- moved the VM types into their own file and only include it where really needed.
This commit is contained in:
parent
3e47f00ba0
commit
6599e2c425
111 changed files with 4283 additions and 4147 deletions
|
|
@ -6620,7 +6620,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build)
|
|||
ob.Free(build);
|
||||
ExpEmit meta(build, REGT_POINTER);
|
||||
build->Emit(OP_CLSS, meta.RegNum, ob.RegNum);
|
||||
build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
|
||||
build->Emit(OP_LP, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
|
||||
return meta;
|
||||
|
||||
}
|
||||
|
|
@ -6878,7 +6878,7 @@ ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build)
|
|||
if (offsetreg == -1) offsetreg = build->GetConstantInt(0);
|
||||
auto op = membervar->Type->GetLoadOp();
|
||||
if (op == OP_LO)
|
||||
op = OP_LOS;
|
||||
op = OP_LP;
|
||||
build->Emit(op, loc.RegNum, build->FramePointer.RegNum, offsetreg);
|
||||
}
|
||||
else
|
||||
|
|
@ -9355,7 +9355,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build)
|
|||
op.Free(build);
|
||||
}
|
||||
ExpEmit to(build, REGT_POINTER);
|
||||
build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass)));
|
||||
build->Emit(OP_LP, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass)));
|
||||
return to;
|
||||
}
|
||||
|
||||
|
|
@ -9427,7 +9427,7 @@ ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build)
|
|||
build->Emit(OP_LKP, to.RegNum, op.RegNum);
|
||||
op = to;
|
||||
}
|
||||
build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
|
||||
build->Emit(OP_LP, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
|
||||
return to;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@
|
|||
#include "actor.h"
|
||||
#include "vmbuilder.h"
|
||||
#include "scopebarrier.h"
|
||||
#include "types.h"
|
||||
#include "vmintern.h"
|
||||
|
||||
|
||||
#define CHECKRESOLVED() if (isresolved) return this; isresolved=true;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@
|
|||
|
||||
#include "tarray.h"
|
||||
#include "dobject.h"
|
||||
#include "thingdef.h"
|
||||
#include "vm.h"
|
||||
#include "types.h"
|
||||
|
||||
// We need one specific type for each of the 7 integral VM types and instantiate the needed functions for each of them.
|
||||
// Dynamic arrays cannot hold structs because for every type there'd need to be an internal implementation which is impossible.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "dobject.h"
|
||||
#include "scopebarrier.h"
|
||||
#include "types.h"
|
||||
#include "vmintern.h"
|
||||
|
||||
|
||||
// Note: the same object can't be both UI and Play. This is checked explicitly in the field construction and will cause esoteric errors here if found.
|
||||
|
|
|
|||
|
|
@ -35,8 +35,9 @@
|
|||
#include "codegen.h"
|
||||
#include "info.h"
|
||||
#include "m_argv.h"
|
||||
#include "thingdef.h"
|
||||
//#include "thingdef.h"
|
||||
#include "doomerrors.h"
|
||||
#include "vmintern.h"
|
||||
|
||||
struct VMRemap
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define VMUTIL_H
|
||||
|
||||
#include "dobject.h"
|
||||
#include "vmintern.h"
|
||||
|
||||
class VMFunctionBuilder;
|
||||
class FxExpression;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "dobject.h"
|
||||
#include "c_console.h"
|
||||
#include "templates.h"
|
||||
#include "vmintern.h"
|
||||
|
||||
#define NOP MODE_AUNUSED | MODE_BUNUSED | MODE_CUNUSED
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
#include "i_system.h"
|
||||
#include "templates.h"
|
||||
#include "serializer.h"
|
||||
#include "types.h"
|
||||
#include "vm.h"
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
|
|
@ -128,6 +130,80 @@ int PFunction::GetImplicitArgs()
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* PField *****************************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(PField, false, false)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PField - Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PField::PField()
|
||||
: PSymbol(NAME_None), Offset(0), Type(nullptr), Flags(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PField::PField(FName name, PType *type, uint32_t flags, size_t offset, int bitvalue)
|
||||
: PSymbol(name), Offset(offset), Type(type), Flags(flags)
|
||||
{
|
||||
if (bitvalue != 0)
|
||||
{
|
||||
BitValue = 0;
|
||||
unsigned val = bitvalue;
|
||||
while ((val >>= 1)) BitValue++;
|
||||
|
||||
if (type->IsA(RUNTIME_CLASS(PInt)) && unsigned(BitValue) < 8u * type->Size)
|
||||
{
|
||||
// map to the single bytes in the actual variable. The internal bit instructions operate on 8 bit values.
|
||||
#ifndef __BIG_ENDIAN__
|
||||
Offset += BitValue / 8;
|
||||
#else
|
||||
Offset += type->Size - 1 - BitValue / 8;
|
||||
#endif
|
||||
BitValue &= 7;
|
||||
Type = TypeBool;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just abort. Bit fields should only be defined internally.
|
||||
I_Error("Trying to create an invalid bit field element: %s", name.GetChars());
|
||||
}
|
||||
}
|
||||
else BitValue = -1;
|
||||
}
|
||||
|
||||
VersionInfo PField::GetVersion()
|
||||
{
|
||||
VersionInfo Highest = { 0,0,0 };
|
||||
if (!(Flags & VARF_Deprecated)) Highest = mVersion;
|
||||
if (Type->mVersion > Highest) Highest = Type->mVersion;
|
||||
return Highest;
|
||||
}
|
||||
|
||||
/* PProperty *****************************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(PProperty, false, false)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PField - Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PProperty::PProperty()
|
||||
: PSymbol(NAME_None)
|
||||
{
|
||||
}
|
||||
|
||||
PProperty::PProperty(FName name, TArray<PField *> &fields)
|
||||
: PSymbol(name)
|
||||
{
|
||||
Variables = std::move(fields);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
|||
|
|
@ -274,5 +274,4 @@ struct FNamespaceManager
|
|||
};
|
||||
|
||||
extern FNamespaceManager Namespaces;
|
||||
|
||||
|
||||
void RemoveUnusedSymbols();
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
#include "a_weapons.h"
|
||||
#include "p_conversation.h"
|
||||
#include "v_text.h"
|
||||
#include "thingdef.h"
|
||||
//#include "thingdef.h"
|
||||
#include "backend/codegen.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "backend/vmbuilder.h"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "s_sound.h"
|
||||
#include "sc_man.h"
|
||||
#include "cmdlib.h"
|
||||
#include "vm.h"
|
||||
|
||||
|
||||
class FScanner;
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@
|
|||
#include "serializer.h"
|
||||
#include "wi_stuff.h"
|
||||
#include "a_dynlight.h"
|
||||
#include "vm.h"
|
||||
#include "types.h"
|
||||
|
||||
static TArray<FPropertyInfo*> properties;
|
||||
static TArray<AFuncDesc> AFTable;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@
|
|||
#include "a_keys.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "d_player.h"
|
||||
#include "types.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
|||
2689
src/scripting/types.cpp
Normal file
2689
src/scripting/types.cpp
Normal file
File diff suppressed because it is too large
Load diff
641
src/scripting/types.h
Normal file
641
src/scripting/types.h
Normal file
|
|
@ -0,0 +1,641 @@
|
|||
#pragma once
|
||||
|
||||
#include "dobject.h"
|
||||
#include "serializer.h"
|
||||
|
||||
// Variable/parameter/field flags -------------------------------------------
|
||||
class PStruct;
|
||||
|
||||
// Making all these different storage types use a common set of flags seems
|
||||
// like the simplest thing to do.
|
||||
|
||||
enum
|
||||
{
|
||||
VARF_Optional = (1<<0), // func param is optional
|
||||
VARF_Method = (1<<1), // func has an implied self parameter
|
||||
VARF_Action = (1<<2), // func has implied owner and state parameters
|
||||
VARF_Native = (1<<3), // func is native code, field is natively defined
|
||||
VARF_ReadOnly = (1<<4), // field is read only, do not write to it
|
||||
VARF_Private = (1<<5), // field is private to containing class
|
||||
VARF_Protected = (1<<6), // field is only accessible by containing class and children.
|
||||
VARF_Deprecated = (1<<7), // Deprecated fields should output warnings when used.
|
||||
VARF_Virtual = (1<<8), // function is virtual
|
||||
VARF_Final = (1<<9), // Function may not be overridden in subclasses
|
||||
VARF_In = (1<<10),
|
||||
VARF_Out = (1<<11),
|
||||
VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures)
|
||||
VARF_Static = (1<<13),
|
||||
VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code.
|
||||
VARF_Override = (1<<15), // overrides a virtual function from the parent class.
|
||||
VARF_Ref = (1<<16), // argument is passed by reference.
|
||||
VARF_Transient = (1<<17), // don't auto serialize field.
|
||||
VARF_Meta = (1<<18), // static class data (by necessity read only.)
|
||||
VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature
|
||||
VARF_UI = (1<<20), // [ZZ] ui: object is ui-scope only (can't modify playsim)
|
||||
VARF_Play = (1<<21), // [ZZ] play: object is playsim-scope only (can't access ui)
|
||||
VARF_VirtualScope = (1<<22), // [ZZ] virtualscope: object should use the scope of the particular class it's being used with (methods only)
|
||||
VARF_ClearScope = (1<<23), // [ZZ] clearscope: this method ignores the member access chain that leads to it and is always plain data.
|
||||
};
|
||||
|
||||
// Basic information shared by all types ------------------------------------
|
||||
|
||||
// Only one copy of a type is ever instantiated at one time.
|
||||
// - Enums, classes, and structs are defined by their names and outer classes.
|
||||
// - Pointers are uniquely defined by the type they point at.
|
||||
// - ClassPointers are also defined by their class restriction.
|
||||
// - Arrays are defined by their element type and count.
|
||||
// - DynArrays are defined by their element type.
|
||||
// - Maps are defined by their key and value types.
|
||||
// - Prototypes are defined by the argument and return types.
|
||||
// - Functions are defined by their names and outer objects.
|
||||
// In table form:
|
||||
// Outer Name Type Type2 Count
|
||||
// Enum * *
|
||||
// Class * *
|
||||
// Struct * *
|
||||
// Function * *
|
||||
// Pointer *
|
||||
// ClassPointer + *
|
||||
// Array * *
|
||||
// DynArray *
|
||||
// Map * *
|
||||
// Prototype *+ *+
|
||||
|
||||
struct ZCC_ExprConstant;
|
||||
class PType : public PTypeBase
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(PType, PTypeBase)
|
||||
protected:
|
||||
|
||||
public:
|
||||
PClass *TypeTableType; // The type to use for hashing into the type table
|
||||
unsigned int Size; // this type's size
|
||||
unsigned int Align; // this type's preferred alignment
|
||||
PType *HashNext; // next type in this type table
|
||||
PSymbolTable Symbols;
|
||||
bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument.
|
||||
FString mDescriptiveName;
|
||||
VersionInfo mVersion = { 0,0,0 };
|
||||
uint8_t loadOp, storeOp, moveOp, RegType, RegCount;
|
||||
|
||||
PType(unsigned int size = 1, unsigned int align = 1);
|
||||
virtual ~PType();
|
||||
virtual bool isNumeric() { return false; }
|
||||
|
||||
// Writes the value of a variable of this type at (addr) to an archive, preceded by
|
||||
// a tag indicating its type. The tag is there so that variable types can be changed
|
||||
// without completely breaking savegames, provided that the change isn't between
|
||||
// totally unrelated types.
|
||||
virtual void WriteValue(FSerializer &ar, const char *key,const void *addr) const;
|
||||
|
||||
// Returns true if the stored value was compatible. False otherwise.
|
||||
// If the value was incompatible, then the memory at *addr is unchanged.
|
||||
virtual bool ReadValue(FSerializer &ar, const char *key,void *addr) const;
|
||||
|
||||
// Sets the default value for this type at (base + offset)
|
||||
// If the default value is binary 0, then this function doesn't need
|
||||
// to do anything, because PClass::Extend() takes care of that.
|
||||
//
|
||||
// The stroffs array is so that types that need special initialization
|
||||
// and destruction (e.g. strings) can add their offsets to it for special
|
||||
// initialization when the object is created and destruction when the
|
||||
// object is destroyed.
|
||||
virtual void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL);
|
||||
virtual void SetPointer(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL);
|
||||
virtual void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) const;
|
||||
|
||||
// Initialize the value, if needed (e.g. strings)
|
||||
virtual void InitializeValue(void *addr, const void *def) const;
|
||||
|
||||
// Destroy the value, if needed (e.g. strings)
|
||||
virtual void DestroyValue(void *addr) const;
|
||||
|
||||
// Sets the value of a variable of this type at (addr)
|
||||
virtual void SetValue(void *addr, int val);
|
||||
virtual void SetValue(void *addr, double val);
|
||||
|
||||
// Gets the value of a variable of this type at (addr)
|
||||
virtual int GetValueInt(void *addr) const;
|
||||
virtual double GetValueFloat(void *addr) const;
|
||||
|
||||
// Gets the opcode to store from a register to memory
|
||||
int GetStoreOp() const
|
||||
{
|
||||
return storeOp;
|
||||
}
|
||||
|
||||
// Gets the opcode to load from memory to a register
|
||||
int GetLoadOp() const
|
||||
{
|
||||
return loadOp;
|
||||
}
|
||||
|
||||
// Gets the opcode to move from register to another register
|
||||
int GetMoveOp() const
|
||||
{
|
||||
return moveOp;
|
||||
}
|
||||
|
||||
// Gets the register type for this type
|
||||
int GetRegType() const
|
||||
{
|
||||
return RegType;
|
||||
}
|
||||
|
||||
int GetRegCount() const
|
||||
{
|
||||
return RegCount;
|
||||
}
|
||||
// Returns true if this type matches the two identifiers. Referring to the
|
||||
// above table, any type is identified by at most two characteristics. Each
|
||||
// type that implements this function will cast these to the appropriate type.
|
||||
// It is up to the caller to make sure they are the correct types. There is
|
||||
// only one prototype for this function in order to simplify type table
|
||||
// management.
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
|
||||
// Get the type IDs used by IsMatch
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
|
||||
const char *DescriptiveName() const;
|
||||
|
||||
static void StaticInit();
|
||||
};
|
||||
|
||||
// Not-really-a-type types --------------------------------------------------
|
||||
|
||||
class PErrorType : public PType
|
||||
{
|
||||
DECLARE_CLASS(PErrorType, PType);
|
||||
public:
|
||||
PErrorType(int which = 1) : PType(0, which) {}
|
||||
};
|
||||
|
||||
class PVoidType : public PType
|
||||
{
|
||||
DECLARE_CLASS(PVoidType, PType);
|
||||
public:
|
||||
PVoidType() : PType(0, 1) {}
|
||||
};
|
||||
|
||||
// Some categorization typing -----------------------------------------------
|
||||
|
||||
class PBasicType : public PType
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(PBasicType, PType);
|
||||
public:
|
||||
PBasicType();
|
||||
PBasicType(unsigned int size, unsigned int align);
|
||||
};
|
||||
|
||||
class PCompoundType : public PType
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(PCompoundType, PType);
|
||||
};
|
||||
|
||||
class PContainerType : public PCompoundType
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(PContainerType, PCompoundType);
|
||||
public:
|
||||
PTypeBase *Outer; // object this type is contained within
|
||||
FName TypeName; // this type's name
|
||||
|
||||
PContainerType() : Outer(NULL) {
|
||||
mDescriptiveName = "NamedType";
|
||||
}
|
||||
PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) {
|
||||
mDescriptiveName = name.GetChars();
|
||||
}
|
||||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
virtual PField *AddField(FName name, PType *type, uint32_t flags = 0) = 0;
|
||||
virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) = 0;
|
||||
};
|
||||
|
||||
// Basic types --------------------------------------------------------------
|
||||
|
||||
class PInt : public PBasicType
|
||||
{
|
||||
DECLARE_CLASS(PInt, PBasicType);
|
||||
public:
|
||||
PInt(unsigned int size, bool unsign, bool compatible = true);
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
||||
|
||||
virtual void SetValue(void *addr, int val);
|
||||
virtual void SetValue(void *addr, double val);
|
||||
virtual int GetValueInt(void *addr) const;
|
||||
virtual double GetValueFloat(void *addr) const;
|
||||
virtual bool isNumeric() override { return IntCompatible; }
|
||||
|
||||
bool Unsigned;
|
||||
bool IntCompatible;
|
||||
protected:
|
||||
PInt();
|
||||
void SetOps();
|
||||
};
|
||||
|
||||
class PBool : public PInt
|
||||
{
|
||||
DECLARE_CLASS(PBool, PInt);
|
||||
public:
|
||||
PBool();
|
||||
virtual void SetValue(void *addr, int val);
|
||||
virtual void SetValue(void *addr, double val);
|
||||
virtual int GetValueInt(void *addr) const;
|
||||
virtual double GetValueFloat(void *addr) const;
|
||||
};
|
||||
|
||||
class PFloat : public PBasicType
|
||||
{
|
||||
DECLARE_CLASS(PFloat, PBasicType);
|
||||
public:
|
||||
PFloat(unsigned int size);
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
||||
|
||||
virtual void SetValue(void *addr, int val);
|
||||
virtual void SetValue(void *addr, double val);
|
||||
virtual int GetValueInt(void *addr) const;
|
||||
virtual double GetValueFloat(void *addr) const;
|
||||
virtual bool isNumeric() override { return true; }
|
||||
protected:
|
||||
PFloat();
|
||||
void SetOps();
|
||||
private:
|
||||
struct SymbolInitF
|
||||
{
|
||||
ENamedName Name;
|
||||
double Value;
|
||||
};
|
||||
struct SymbolInitI
|
||||
{
|
||||
ENamedName Name;
|
||||
int Value;
|
||||
};
|
||||
|
||||
void SetSingleSymbols();
|
||||
void SetDoubleSymbols();
|
||||
void SetSymbols(const SymbolInitF *syminit, size_t count);
|
||||
void SetSymbols(const SymbolInitI *syminit, size_t count);
|
||||
};
|
||||
|
||||
class PString : public PBasicType
|
||||
{
|
||||
DECLARE_CLASS(PString, PBasicType);
|
||||
public:
|
||||
PString();
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
||||
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL) override;
|
||||
void InitializeValue(void *addr, const void *def) const override;
|
||||
void DestroyValue(void *addr) const override;
|
||||
};
|
||||
|
||||
// Variations of integer types ----------------------------------------------
|
||||
|
||||
class PName : public PInt
|
||||
{
|
||||
DECLARE_CLASS(PName, PInt);
|
||||
public:
|
||||
PName();
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
||||
};
|
||||
|
||||
class PSound : public PInt
|
||||
{
|
||||
DECLARE_CLASS(PSound, PInt);
|
||||
public:
|
||||
PSound();
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
||||
};
|
||||
|
||||
class PSpriteID : public PInt
|
||||
{
|
||||
DECLARE_CLASS(PSpriteID, PInt);
|
||||
public:
|
||||
PSpriteID();
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
|
||||
};
|
||||
|
||||
class PTextureID : public PInt
|
||||
{
|
||||
DECLARE_CLASS(PTextureID, PInt);
|
||||
public:
|
||||
PTextureID();
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
|
||||
};
|
||||
|
||||
class PColor : public PInt
|
||||
{
|
||||
DECLARE_CLASS(PColor, PInt);
|
||||
public:
|
||||
PColor();
|
||||
};
|
||||
|
||||
class PStateLabel : public PInt
|
||||
{
|
||||
DECLARE_CLASS(PStateLabel, PInt);
|
||||
public:
|
||||
PStateLabel();
|
||||
};
|
||||
|
||||
// Pointers -----------------------------------------------------------------
|
||||
|
||||
class PPointer : public PBasicType
|
||||
{
|
||||
DECLARE_CLASS(PPointer, PBasicType);
|
||||
|
||||
public:
|
||||
typedef void(*WriteHandler)(FSerializer &ar, const char *key, const void *addr);
|
||||
typedef bool(*ReadHandler)(FSerializer &ar, const char *key, void *addr);
|
||||
|
||||
PPointer();
|
||||
PPointer(PType *pointsat, bool isconst = false);
|
||||
|
||||
PType *PointedType;
|
||||
bool IsConst;
|
||||
|
||||
WriteHandler writer = nullptr;
|
||||
ReadHandler reader = nullptr;
|
||||
|
||||
void InstallHandlers(WriteHandler w, ReadHandler r)
|
||||
{
|
||||
writer = w;
|
||||
reader = r;
|
||||
}
|
||||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
||||
|
||||
protected:
|
||||
void SetOps();
|
||||
};
|
||||
|
||||
class PStatePointer : public PPointer
|
||||
{
|
||||
DECLARE_CLASS(PStatePointer, PPointer);
|
||||
public:
|
||||
PStatePointer();
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
|
||||
};
|
||||
|
||||
|
||||
class PObjectPointer : public PPointer
|
||||
{
|
||||
DECLARE_CLASS(PObjectPointer, PPointer);
|
||||
public:
|
||||
PObjectPointer(PClass *pointedtype = nullptr, bool isconst = false);
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
|
||||
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) override;
|
||||
PClass *PointedClass() const;
|
||||
};
|
||||
|
||||
|
||||
class PClassPointer : public PPointer
|
||||
{
|
||||
DECLARE_CLASS(PClassPointer, PPointer);
|
||||
public:
|
||||
PClassPointer(class PClass *restrict = nullptr);
|
||||
|
||||
class PClass *ClassRestriction;
|
||||
|
||||
bool isCompatible(PType *type);
|
||||
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
|
||||
|
||||
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) override;
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
};
|
||||
|
||||
// Compound types -----------------------------------------------------------
|
||||
|
||||
class PEnum : public PInt
|
||||
{
|
||||
DECLARE_CLASS(PEnum, PInt);
|
||||
public:
|
||||
PEnum(FName name, PTypeBase *outer);
|
||||
|
||||
PTypeBase *Outer;
|
||||
FName EnumName;
|
||||
protected:
|
||||
PEnum();
|
||||
};
|
||||
|
||||
class PArray : public PCompoundType
|
||||
{
|
||||
DECLARE_CLASS(PArray, PCompoundType);
|
||||
public:
|
||||
PArray(PType *etype, unsigned int ecount);
|
||||
|
||||
PType *ElementType;
|
||||
unsigned int ElementCount;
|
||||
unsigned int ElementSize;
|
||||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
||||
|
||||
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special) override;
|
||||
void SetPointer(void *base, unsigned offset, TArray<size_t> *special) override;
|
||||
|
||||
protected:
|
||||
PArray();
|
||||
};
|
||||
|
||||
class PStaticArray : public PArray
|
||||
{
|
||||
DECLARE_CLASS(PStaticArray, PArray);
|
||||
public:
|
||||
PStaticArray(PType *etype);
|
||||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
|
||||
protected:
|
||||
PStaticArray();
|
||||
};
|
||||
|
||||
class PDynArray : public PCompoundType
|
||||
{
|
||||
DECLARE_CLASS(PDynArray, PCompoundType);
|
||||
public:
|
||||
PDynArray(PType *etype, PStruct *backing);
|
||||
|
||||
PType *ElementType;
|
||||
PStruct *BackingType;
|
||||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
|
||||
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) override;
|
||||
void InitializeValue(void *addr, const void *def) const override;
|
||||
void DestroyValue(void *addr) const override;
|
||||
void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) const override;
|
||||
|
||||
protected:
|
||||
PDynArray();
|
||||
};
|
||||
|
||||
class PMap : public PCompoundType
|
||||
{
|
||||
DECLARE_CLASS(PMap, PCompoundType);
|
||||
public:
|
||||
PMap(PType *keytype, PType *valtype);
|
||||
|
||||
PType *KeyType;
|
||||
PType *ValueType;
|
||||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
protected:
|
||||
PMap();
|
||||
};
|
||||
|
||||
class PStruct : public PContainerType
|
||||
{
|
||||
DECLARE_CLASS(PStruct, PContainerType);
|
||||
|
||||
public:
|
||||
PStruct(FName name, PTypeBase *outer, bool isnative = false);
|
||||
|
||||
bool isNative;
|
||||
// Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use these two functions for it.
|
||||
VMFunction *mConstructor = nullptr;
|
||||
VMFunction *mDestructor = nullptr;
|
||||
|
||||
virtual PField *AddField(FName name, PType *type, uint32_t flags=0);
|
||||
virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0);
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
||||
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) override;
|
||||
void SetPointer(void *base, unsigned offset, TArray<size_t> *specials) override;
|
||||
|
||||
protected:
|
||||
PStruct();
|
||||
};
|
||||
|
||||
class PPrototype : public PCompoundType
|
||||
{
|
||||
DECLARE_CLASS(PPrototype, PCompoundType);
|
||||
public:
|
||||
PPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes);
|
||||
|
||||
TArray<PType *> ArgumentTypes;
|
||||
TArray<PType *> ReturnTypes;
|
||||
|
||||
size_t PropagateMark();
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
protected:
|
||||
PPrototype();
|
||||
};
|
||||
|
||||
|
||||
// Meta-info for every class derived from DObject ---------------------------
|
||||
|
||||
class PClassType : public PContainerType
|
||||
{
|
||||
DECLARE_CLASS(PClassType, PContainerType);
|
||||
|
||||
private:
|
||||
|
||||
public:
|
||||
PClass *Descriptor;
|
||||
PClassType *ParentType;
|
||||
|
||||
PClassType(PClass *cls = nullptr);
|
||||
PField *AddField(FName name, PType *type, uint32_t flags = 0) override;
|
||||
PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Returns a type from the TypeTable. Will create one if it isn't present.
|
||||
PMap *NewMap(PType *keytype, PType *valuetype);
|
||||
PArray *NewArray(PType *type, unsigned int count);
|
||||
PStaticArray *NewStaticArray(PType *type);
|
||||
PDynArray *NewDynArray(PType *type);
|
||||
PPointer *NewPointer(PType *type, bool isconst = false);
|
||||
PPointer *NewPointer(PClass *type, bool isconst = false);
|
||||
PClassPointer *NewClassPointer(PClass *restrict);
|
||||
PEnum *NewEnum(FName name, PTypeBase *outer);
|
||||
PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false);
|
||||
PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes);
|
||||
PClassType *NewClassType(PClass *cls);
|
||||
|
||||
// Built-in types -----------------------------------------------------------
|
||||
|
||||
extern PErrorType *TypeError;
|
||||
extern PErrorType *TypeAuto;
|
||||
extern PVoidType *TypeVoid;
|
||||
extern PInt *TypeSInt8, *TypeUInt8;
|
||||
extern PInt *TypeSInt16, *TypeUInt16;
|
||||
extern PInt *TypeSInt32, *TypeUInt32;
|
||||
extern PBool *TypeBool;
|
||||
extern PFloat *TypeFloat32, *TypeFloat64;
|
||||
extern PString *TypeString;
|
||||
extern PName *TypeName;
|
||||
extern PSound *TypeSound;
|
||||
extern PColor *TypeColor;
|
||||
extern PTextureID *TypeTextureID;
|
||||
extern PSpriteID *TypeSpriteID;
|
||||
extern PStruct *TypeVector2;
|
||||
extern PStruct *TypeVector3;
|
||||
extern PStruct *TypeColorStruct;
|
||||
extern PStruct *TypeStringStruct;
|
||||
extern PStatePointer *TypeState;
|
||||
extern PPointer *TypeFont;
|
||||
extern PStateLabel *TypeStateLabel;
|
||||
extern PPointer *TypeNullPtr;
|
||||
extern PPointer *TypeVoidPtr;
|
||||
|
||||
inline FString &DObject::StringVar(FName field)
|
||||
{
|
||||
return *(FString*)ScriptVar(field, TypeString);
|
||||
}
|
||||
|
||||
// Type tables --------------------------------------------------------------
|
||||
|
||||
struct FTypeTable
|
||||
{
|
||||
enum { HASH_SIZE = 1021 };
|
||||
|
||||
PType *TypeHash[HASH_SIZE];
|
||||
|
||||
PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum);
|
||||
void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket);
|
||||
void AddType(PType *type);
|
||||
void Clear();
|
||||
|
||||
static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3);
|
||||
};
|
||||
|
||||
|
||||
extern FTypeTable TypeTable;
|
||||
|
||||
|
|
@ -26,134 +26,6 @@ typedef signed int VM_SWORD;
|
|||
|
||||
#define VM_EPSILON (1/65536.0)
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#define VM_DEFINE_OP2(TYPE, ARG1, ARG2) TYPE ARG2, ARG1
|
||||
#define VM_DEFINE_OP4(TYPE, ARG1, ARG2, ARG3, ARG4) TYPE ARG4, ARG3, ARG2, ARG1
|
||||
#else // little endian
|
||||
#define VM_DEFINE_OP2(TYPE, ARG1, ARG2) TYPE ARG1, ARG2
|
||||
#define VM_DEFINE_OP4(TYPE, ARG1, ARG2, ARG3, ARG4) TYPE ARG1, ARG2, ARG3, ARG4
|
||||
#endif // __BIG_ENDIAN__
|
||||
|
||||
union VMOP
|
||||
{
|
||||
struct
|
||||
{
|
||||
VM_DEFINE_OP4(VM_UBYTE, op, a, b, c);
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_DEFINE_OP4(VM_SBYTE, pad0, as, bs, cs);
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_DEFINE_OP2(VM_SWORD, pad1:8, i24:24);
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_DEFINE_OP2(VM_SWORD, pad2:16, i16:16);
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_DEFINE_OP2(VM_UHALF, pad3, i16u);
|
||||
};
|
||||
VM_UWORD word;
|
||||
|
||||
// Interesting fact: VC++ produces better code for i16 when it's defined
|
||||
// as a bitfield than when it's defined as two discrete units.
|
||||
// Compare:
|
||||
// mov eax,dword ptr [op] ; As two discrete units
|
||||
// shr eax,10h
|
||||
// movsx eax,ax
|
||||
// versus:
|
||||
// mov eax,dword ptr [op] ; As a bitfield
|
||||
// sar eax,10h
|
||||
};
|
||||
|
||||
#undef VM_DEFINE_OP4
|
||||
#undef VM_DEFINE_OP2
|
||||
|
||||
enum
|
||||
{
|
||||
#include "vmops.h"
|
||||
NUM_OPS
|
||||
};
|
||||
|
||||
// Flags for A field of CMPS
|
||||
enum
|
||||
{
|
||||
CMP_CHECK = 1,
|
||||
|
||||
CMP_EQ = 0,
|
||||
CMP_LT = 2,
|
||||
CMP_LE = 4,
|
||||
CMP_METHOD_MASK = 6,
|
||||
|
||||
CMP_BK = 8,
|
||||
CMP_CK = 16,
|
||||
CMP_APPROX = 32,
|
||||
};
|
||||
|
||||
// Floating point operations for FLOP
|
||||
enum
|
||||
{
|
||||
FLOP_ABS,
|
||||
FLOP_NEG,
|
||||
FLOP_EXP,
|
||||
FLOP_LOG,
|
||||
FLOP_LOG10,
|
||||
FLOP_SQRT,
|
||||
FLOP_CEIL,
|
||||
FLOP_FLOOR,
|
||||
|
||||
FLOP_ACOS, // This group works with radians
|
||||
FLOP_ASIN,
|
||||
FLOP_ATAN,
|
||||
FLOP_COS,
|
||||
FLOP_SIN,
|
||||
FLOP_TAN,
|
||||
|
||||
FLOP_ACOS_DEG, // This group works with degrees
|
||||
FLOP_ASIN_DEG,
|
||||
FLOP_ATAN_DEG,
|
||||
FLOP_COS_DEG,
|
||||
FLOP_SIN_DEG,
|
||||
FLOP_TAN_DEG,
|
||||
|
||||
FLOP_COSH,
|
||||
FLOP_SINH,
|
||||
FLOP_TANH,
|
||||
};
|
||||
|
||||
// Cast operations
|
||||
enum
|
||||
{
|
||||
CAST_I2F,
|
||||
CAST_I2S,
|
||||
CAST_U2F,
|
||||
CAST_U2S,
|
||||
CAST_F2I,
|
||||
CAST_F2U,
|
||||
CAST_F2S,
|
||||
CAST_P2S,
|
||||
CAST_S2I,
|
||||
CAST_S2F,
|
||||
CAST_S2N,
|
||||
CAST_N2S,
|
||||
CAST_S2Co,
|
||||
CAST_S2So,
|
||||
CAST_Co2S,
|
||||
CAST_So2S,
|
||||
CAST_V22S,
|
||||
CAST_V32S,
|
||||
CAST_SID2S,
|
||||
CAST_TID2S,
|
||||
|
||||
CASTB_I,
|
||||
CASTB_F,
|
||||
CASTB_A,
|
||||
CASTB_S
|
||||
};
|
||||
|
||||
// Register types for VMParam
|
||||
enum
|
||||
{
|
||||
|
|
@ -198,105 +70,6 @@ public:
|
|||
// This must be a separate function because the VC compiler would otherwise allocate memory on the stack for every separate instance of the exception object that may get thrown.
|
||||
void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...);
|
||||
|
||||
enum EVMOpMode
|
||||
{
|
||||
MODE_ASHIFT = 0,
|
||||
MODE_BSHIFT = 4,
|
||||
MODE_CSHIFT = 8,
|
||||
MODE_BCSHIFT = 12,
|
||||
|
||||
MODE_ATYPE = 15 << MODE_ASHIFT,
|
||||
MODE_BTYPE = 15 << MODE_BSHIFT,
|
||||
MODE_CTYPE = 15 << MODE_CSHIFT,
|
||||
MODE_BCTYPE = 31 << MODE_BCSHIFT,
|
||||
|
||||
MODE_I = 0,
|
||||
MODE_F,
|
||||
MODE_S,
|
||||
MODE_P,
|
||||
MODE_V,
|
||||
MODE_X,
|
||||
MODE_KI,
|
||||
MODE_KF,
|
||||
MODE_KS,
|
||||
MODE_KP,
|
||||
MODE_KV,
|
||||
MODE_UNUSED,
|
||||
MODE_IMMS,
|
||||
MODE_IMMZ,
|
||||
MODE_JOINT,
|
||||
MODE_CMP,
|
||||
|
||||
MODE_PARAM,
|
||||
MODE_THROW,
|
||||
MODE_CATCH,
|
||||
MODE_CAST,
|
||||
|
||||
MODE_AI = MODE_I << MODE_ASHIFT,
|
||||
MODE_AF = MODE_F << MODE_ASHIFT,
|
||||
MODE_AS = MODE_S << MODE_ASHIFT,
|
||||
MODE_AP = MODE_P << MODE_ASHIFT,
|
||||
MODE_AV = MODE_V << MODE_ASHIFT,
|
||||
MODE_AX = MODE_X << MODE_ASHIFT,
|
||||
MODE_AKP = MODE_KP << MODE_ASHIFT,
|
||||
MODE_AUNUSED = MODE_UNUSED << MODE_ASHIFT,
|
||||
MODE_AIMMS = MODE_IMMS << MODE_ASHIFT,
|
||||
MODE_AIMMZ = MODE_IMMZ << MODE_ASHIFT,
|
||||
MODE_ACMP = MODE_CMP << MODE_ASHIFT,
|
||||
|
||||
MODE_BI = MODE_I << MODE_BSHIFT,
|
||||
MODE_BF = MODE_F << MODE_BSHIFT,
|
||||
MODE_BS = MODE_S << MODE_BSHIFT,
|
||||
MODE_BP = MODE_P << MODE_BSHIFT,
|
||||
MODE_BV = MODE_V << MODE_BSHIFT,
|
||||
MODE_BX = MODE_X << MODE_BSHIFT,
|
||||
MODE_BKI = MODE_KI << MODE_BSHIFT,
|
||||
MODE_BKF = MODE_KF << MODE_BSHIFT,
|
||||
MODE_BKS = MODE_KS << MODE_BSHIFT,
|
||||
MODE_BKP = MODE_KP << MODE_BSHIFT,
|
||||
MODE_BKV = MODE_KV << MODE_BSHIFT,
|
||||
MODE_BUNUSED = MODE_UNUSED << MODE_BSHIFT,
|
||||
MODE_BIMMS = MODE_IMMS << MODE_BSHIFT,
|
||||
MODE_BIMMZ = MODE_IMMZ << MODE_BSHIFT,
|
||||
|
||||
MODE_CI = MODE_I << MODE_CSHIFT,
|
||||
MODE_CF = MODE_F << MODE_CSHIFT,
|
||||
MODE_CS = MODE_S << MODE_CSHIFT,
|
||||
MODE_CP = MODE_P << MODE_CSHIFT,
|
||||
MODE_CV = MODE_V << MODE_CSHIFT,
|
||||
MODE_CX = MODE_X << MODE_CSHIFT,
|
||||
MODE_CKI = MODE_KI << MODE_CSHIFT,
|
||||
MODE_CKF = MODE_KF << MODE_CSHIFT,
|
||||
MODE_CKS = MODE_KS << MODE_CSHIFT,
|
||||
MODE_CKP = MODE_KP << MODE_CSHIFT,
|
||||
MODE_CKV = MODE_KV << MODE_CSHIFT,
|
||||
MODE_CUNUSED = MODE_UNUSED << MODE_CSHIFT,
|
||||
MODE_CIMMS = MODE_IMMS << MODE_CSHIFT,
|
||||
MODE_CIMMZ = MODE_IMMZ << MODE_CSHIFT,
|
||||
|
||||
MODE_BCJOINT = (MODE_JOINT << MODE_BSHIFT) | (MODE_JOINT << MODE_CSHIFT),
|
||||
MODE_BCKI = MODE_KI << MODE_BCSHIFT,
|
||||
MODE_BCKF = MODE_KF << MODE_BCSHIFT,
|
||||
MODE_BCKS = MODE_KS << MODE_BCSHIFT,
|
||||
MODE_BCKP = MODE_KP << MODE_BCSHIFT,
|
||||
MODE_BCIMMS = MODE_IMMS << MODE_BCSHIFT,
|
||||
MODE_BCIMMZ = MODE_IMMZ << MODE_BCSHIFT,
|
||||
MODE_BCPARAM = MODE_PARAM << MODE_BCSHIFT,
|
||||
MODE_BCTHROW = MODE_THROW << MODE_BCSHIFT,
|
||||
MODE_BCCATCH = MODE_CATCH << MODE_BCSHIFT,
|
||||
MODE_BCCAST = MODE_CAST << MODE_BCSHIFT,
|
||||
|
||||
MODE_ABCJOINT = (MODE_JOINT << MODE_ASHIFT) | MODE_BCJOINT,
|
||||
};
|
||||
|
||||
struct VMOpInfo
|
||||
{
|
||||
const char *Name;
|
||||
int Mode;
|
||||
};
|
||||
|
||||
extern const VMOpInfo OpInfo[NUM_OPS];
|
||||
|
||||
struct VMReturn
|
||||
{
|
||||
void *Location;
|
||||
|
|
@ -544,186 +317,6 @@ public:
|
|||
protected:
|
||||
};
|
||||
|
||||
// VM frame layout:
|
||||
// VMFrame header
|
||||
// parameter stack - 16 byte boundary, 16 bytes each
|
||||
// double registers - 8 bytes each
|
||||
// string registers - 4 or 8 bytes each
|
||||
// address registers - 4 or 8 bytes each
|
||||
// data registers - 4 bytes each
|
||||
// address register tags-1 byte each
|
||||
// extra space - 16 byte boundary
|
||||
struct VMFrame
|
||||
{
|
||||
VMFrame *ParentFrame;
|
||||
VMFunction *Func;
|
||||
VM_UBYTE NumRegD;
|
||||
VM_UBYTE NumRegF;
|
||||
VM_UBYTE NumRegS;
|
||||
VM_UBYTE NumRegA;
|
||||
VM_UHALF MaxParam;
|
||||
VM_UHALF NumParam; // current number of parameters
|
||||
|
||||
static int FrameSize(int numregd, int numregf, int numregs, int numrega, int numparam, int numextra)
|
||||
{
|
||||
int size = (sizeof(VMFrame) + 15) & ~15;
|
||||
size += numparam * sizeof(VMValue);
|
||||
size += numregf * sizeof(double);
|
||||
size += numrega * sizeof(void *);
|
||||
size += numregs * sizeof(FString);
|
||||
size += numregd * sizeof(int);
|
||||
if (numextra != 0)
|
||||
{
|
||||
size = (size + 15) & ~15;
|
||||
size += numextra;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
VMValue *GetParam() const
|
||||
{
|
||||
assert(((size_t)this & 15) == 0 && "VM frame is unaligned");
|
||||
return (VMValue *)(((size_t)(this + 1) + 15) & ~15);
|
||||
}
|
||||
|
||||
double *GetRegF() const
|
||||
{
|
||||
return (double *)(GetParam() + MaxParam);
|
||||
}
|
||||
|
||||
FString *GetRegS() const
|
||||
{
|
||||
return (FString *)(GetRegF() + NumRegF);
|
||||
}
|
||||
|
||||
void **GetRegA() const
|
||||
{
|
||||
return (void **)(GetRegS() + NumRegS);
|
||||
}
|
||||
|
||||
int *GetRegD() const
|
||||
{
|
||||
return (int *)(GetRegA() + NumRegA);
|
||||
}
|
||||
|
||||
void *GetExtra() const
|
||||
{
|
||||
uint8_t *pbeg = (uint8_t*)(GetRegD() + NumRegD);
|
||||
ptrdiff_t ofs = pbeg - (uint8_t *)this;
|
||||
return (VM_UBYTE *)this + ((ofs + 15) & ~15);
|
||||
}
|
||||
|
||||
void GetAllRegs(int *&d, double *&f, FString *&s, void **&a, VMValue *¶m) const
|
||||
{
|
||||
// Calling the individual functions produces suboptimal code. :(
|
||||
param = GetParam();
|
||||
f = (double *)(param + MaxParam);
|
||||
s = (FString *)(f + NumRegF);
|
||||
a = (void **)(s + NumRegS);
|
||||
d = (int *)(a + NumRegA);
|
||||
}
|
||||
|
||||
void InitRegS();
|
||||
};
|
||||
|
||||
struct VMRegisters
|
||||
{
|
||||
VMRegisters(const VMFrame *frame)
|
||||
{
|
||||
frame->GetAllRegs(d, f, s, a, param);
|
||||
}
|
||||
|
||||
VMRegisters(const VMRegisters &o)
|
||||
: d(o.d), f(o.f), s(o.s), a(o.a), param(o.param)
|
||||
{ }
|
||||
|
||||
int *d;
|
||||
double *f;
|
||||
FString *s;
|
||||
void **a;
|
||||
VMValue *param;
|
||||
};
|
||||
|
||||
union FVoidObj
|
||||
{
|
||||
DObject *o;
|
||||
void *v;
|
||||
};
|
||||
|
||||
struct FStatementInfo
|
||||
{
|
||||
uint16_t InstructionIndex;
|
||||
uint16_t LineNumber;
|
||||
};
|
||||
|
||||
class VMScriptFunction : public VMFunction
|
||||
{
|
||||
public:
|
||||
VMScriptFunction(FName name=NAME_None);
|
||||
~VMScriptFunction();
|
||||
void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers);
|
||||
|
||||
VMOP *Code;
|
||||
FStatementInfo *LineInfo;
|
||||
FString SourceFileName;
|
||||
int *KonstD;
|
||||
double *KonstF;
|
||||
FString *KonstS;
|
||||
FVoidObj *KonstA;
|
||||
int ExtraSpace;
|
||||
int CodeSize; // Size of code in instructions (not bytes)
|
||||
unsigned LineInfoCount;
|
||||
unsigned StackSize;
|
||||
VM_UBYTE NumRegD;
|
||||
VM_UBYTE NumRegF;
|
||||
VM_UBYTE NumRegS;
|
||||
VM_UBYTE NumRegA;
|
||||
VM_UHALF NumKonstD;
|
||||
VM_UHALF NumKonstF;
|
||||
VM_UHALF NumKonstS;
|
||||
VM_UHALF NumKonstA;
|
||||
VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once
|
||||
VM_UBYTE NumArgs; // Number of arguments this function takes
|
||||
TArray<FTypeAndOffset> SpecialInits; // list of all contents on the extra stack which require construction and destruction
|
||||
|
||||
void InitExtra(void *addr);
|
||||
void DestroyExtra(void *addr);
|
||||
int AllocExtraStack(PType *type);
|
||||
int PCToLine(const VMOP *pc);
|
||||
};
|
||||
|
||||
class VMFrameStack
|
||||
{
|
||||
public:
|
||||
VMFrameStack();
|
||||
~VMFrameStack();
|
||||
VMFrame *AllocFrame(VMScriptFunction *func);
|
||||
VMFrame *PopFrame();
|
||||
VMFrame *TopFrame()
|
||||
{
|
||||
assert(Blocks != NULL && Blocks->LastFrame != NULL);
|
||||
return Blocks->LastFrame;
|
||||
}
|
||||
int Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap=NULL);
|
||||
private:
|
||||
enum { BLOCK_SIZE = 4096 }; // Default block size
|
||||
struct BlockHeader
|
||||
{
|
||||
BlockHeader *NextBlock;
|
||||
VMFrame *LastFrame;
|
||||
VM_UBYTE *FreeSpace;
|
||||
int BlockSize;
|
||||
|
||||
void InitFreeSpace()
|
||||
{
|
||||
FreeSpace = (VM_UBYTE *)(((size_t)(this + 1) + 15) & ~15);
|
||||
}
|
||||
};
|
||||
BlockHeader *Blocks;
|
||||
BlockHeader *UnusedBlocks;
|
||||
VMFrame *Alloc(int size);
|
||||
};
|
||||
|
||||
class VMNativeFunction : public VMFunction
|
||||
{
|
||||
public:
|
||||
|
|
@ -738,66 +331,7 @@ public:
|
|||
NativeCallType NativeCall;
|
||||
};
|
||||
|
||||
class VMParamFiller
|
||||
{
|
||||
public:
|
||||
VMParamFiller(const VMFrame *frame) : Reg(frame), RegD(0), RegF(0), RegS(0), RegA(0) {}
|
||||
VMParamFiller(const VMRegisters *reg) : Reg(*reg), RegD(0), RegF(0), RegS(0), RegA(0) {}
|
||||
|
||||
void ParamInt(int val)
|
||||
{
|
||||
Reg.d[RegD++] = val;
|
||||
}
|
||||
|
||||
void ParamFloat(double val)
|
||||
{
|
||||
Reg.f[RegF++] = val;
|
||||
}
|
||||
|
||||
void ParamString(FString &val)
|
||||
{
|
||||
Reg.s[RegS++] = val;
|
||||
}
|
||||
|
||||
void ParamString(const char *val)
|
||||
{
|
||||
Reg.s[RegS++] = val;
|
||||
}
|
||||
|
||||
void ParamObject(DObject *obj)
|
||||
{
|
||||
Reg.a[RegA] = obj;
|
||||
RegA++;
|
||||
}
|
||||
|
||||
void ParamPointer(void *ptr)
|
||||
{
|
||||
Reg.a[RegA] = ptr;
|
||||
RegA++;
|
||||
}
|
||||
|
||||
private:
|
||||
const VMRegisters Reg;
|
||||
int RegD, RegF, RegS, RegA;
|
||||
};
|
||||
|
||||
|
||||
enum EVMEngine
|
||||
{
|
||||
VMEngine_Default,
|
||||
VMEngine_Unchecked,
|
||||
VMEngine_Checked
|
||||
};
|
||||
|
||||
extern thread_local VMFrameStack GlobalVMStack;
|
||||
|
||||
|
||||
void VMSelectEngine(EVMEngine engine);
|
||||
extern int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret);
|
||||
void VMFillParams(VMValue *params, VMFrame *callee, int numparam);
|
||||
|
||||
void VMDumpConstants(FILE *out, const VMScriptFunction *func);
|
||||
void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func);
|
||||
int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults/*, VMException **trap = NULL*/);
|
||||
|
||||
// Use this in the prototype for a native function.
|
||||
#define VM_ARGS VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret
|
||||
|
|
@ -1004,7 +538,7 @@ class AActor;
|
|||
#define ACTION_CALL_FROM_PSPRITE() (self->player && stateinfo != nullptr && stateinfo->mStateType == STATE_Psprite)
|
||||
#define ACTION_CALL_FROM_INVENTORY() (stateinfo != nullptr && stateinfo->mStateType == STATE_StateChain)
|
||||
|
||||
// Standard parameters for all action functons
|
||||
// Standard parameters for all action functions
|
||||
// self - Actor this action is to operate on (player if a weapon)
|
||||
// stateowner - Actor this action really belongs to (may be an item)
|
||||
// callingstate - State this action was called from
|
||||
|
|
@ -1033,4 +567,29 @@ VMFunction *FindVMFunction(PClass *cls, const char *name);
|
|||
|
||||
FString FStringFormat(VM_ARGS);
|
||||
|
||||
|
||||
unsigned GetVirtualIndex(PClass *cls, const char *funcname);
|
||||
|
||||
#define IFVIRTUALPTR(self, cls, funcname) \
|
||||
static unsigned VIndex = ~0u; \
|
||||
if (VIndex == ~0u) { \
|
||||
VIndex = GetVirtualIndex(RUNTIME_CLASS(cls), #funcname); \
|
||||
assert(VIndex != ~0u); \
|
||||
} \
|
||||
auto clss = self->GetClass(); \
|
||||
VMFunction *func = clss->Virtuals.Size() > VIndex? clss->Virtuals[VIndex] : nullptr; \
|
||||
if (func != nullptr)
|
||||
|
||||
#define IFVIRTUAL(cls, funcname) IFVIRTUALPTR(this, cls, funcname)
|
||||
|
||||
#define IFVIRTUALPTRNAME(self, cls, funcname) \
|
||||
static unsigned VIndex = ~0u; \
|
||||
if (VIndex == ~0u) { \
|
||||
VIndex = GetVirtualIndex(PClass::FindClass(cls), #funcname); \
|
||||
assert(VIndex != ~0u); \
|
||||
} \
|
||||
auto clss = self->GetClass(); \
|
||||
VMFunction *func = clss->Virtuals.Size() > VIndex? clss->Virtuals[VIndex] : nullptr; \
|
||||
if (func != nullptr)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -40,12 +40,16 @@
|
|||
#include "textures/textures.h"
|
||||
#include "math/cmath.h"
|
||||
#include "stats.h"
|
||||
#include "vmintern.h"
|
||||
#include "types.h"
|
||||
|
||||
extern cycle_t VMCycles[10];
|
||||
extern int VMCalls[10];
|
||||
|
||||
// intentionally implemented in a different source file to prevent inlining.
|
||||
#if 0
|
||||
void ThrowVMException(VMException *x);
|
||||
#endif
|
||||
|
||||
#define IMPLEMENT_VMEXEC
|
||||
|
||||
|
|
|
|||
|
|
@ -215,16 +215,6 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret)
|
|||
GETADDR(PB,RC,X_READ_NIL);
|
||||
reg.a[a] = GC::ReadBarrier(*(DObject **)ptr);
|
||||
NEXTOP;
|
||||
OP(LOS):
|
||||
ASSERTA(a); ASSERTA(B); ASSERTKD(C);
|
||||
GETADDR(PB,KC,X_READ_NIL);
|
||||
reg.a[a] = *(DObject **)ptr;
|
||||
NEXTOP;
|
||||
OP(LOS_R):
|
||||
ASSERTA(a); ASSERTA(B); ASSERTD(C);
|
||||
GETADDR(PB,RC,X_READ_NIL);
|
||||
reg.a[a] = *(DObject **)ptr;
|
||||
NEXTOP;
|
||||
OP(LP):
|
||||
ASSERTA(a); ASSERTA(B); ASSERTKD(C);
|
||||
GETADDR(PB,KC,X_READ_NIL);
|
||||
|
|
|
|||
|
|
@ -36,12 +36,17 @@
|
|||
#include "dobject.h"
|
||||
#include "v_text.h"
|
||||
#include "stats.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "templates.h"
|
||||
#include "vmintern.h"
|
||||
#include "types.h"
|
||||
|
||||
cycle_t VMCycles[10];
|
||||
int VMCalls[10];
|
||||
|
||||
#if 0
|
||||
IMPLEMENT_CLASS(VMException, false, false)
|
||||
#endif
|
||||
|
||||
TArray<VMFunction *> VMFunction::AllFunctions;
|
||||
|
||||
|
|
@ -423,9 +428,8 @@ VMFrame *VMFrameStack::PopFrame()
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap)
|
||||
int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults/*, VMException **trap*/)
|
||||
{
|
||||
assert(this == &GlobalVMStack); // why would anyone even want to create a local stack?
|
||||
bool allocated = false;
|
||||
try
|
||||
{
|
||||
|
|
@ -452,16 +456,18 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur
|
|||
{
|
||||
VMCycles[0].Clock();
|
||||
VMCalls[0]++;
|
||||
AllocFrame(static_cast<VMScriptFunction *>(func));
|
||||
auto &stack = GlobalVMStack;
|
||||
stack.AllocFrame(static_cast<VMScriptFunction *>(func));
|
||||
allocated = true;
|
||||
VMFillParams(params, TopFrame(), numparams);
|
||||
int numret = VMExec(this, code, results, numresults);
|
||||
PopFrame();
|
||||
VMFillParams(params, stack.TopFrame(), numparams);
|
||||
int numret = VMExec(&stack, code, results, numresults);
|
||||
stack.PopFrame();
|
||||
VMCycles[0].Unclock();
|
||||
return numret;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
catch (VMException *exception)
|
||||
{
|
||||
if (allocated)
|
||||
|
|
@ -475,11 +481,12 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur
|
|||
}
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
catch (...)
|
||||
{
|
||||
if (allocated)
|
||||
{
|
||||
PopFrame();
|
||||
GlobalVMStack.PopFrame();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
|
@ -576,10 +583,12 @@ void NullParam(const char *varname)
|
|||
ThrowAbortException(X_READ_NIL, "In function parameter %s", varname);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void ThrowVMException(VMException *x)
|
||||
{
|
||||
throw x;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ADD_STAT(VM)
|
||||
|
|
@ -599,3 +608,32 @@ ADD_STAT(VM)
|
|||
VMCalls[0] = 0;
|
||||
return FStringf("VM time in last 10 tics: %f ms, %d calls, peak = %f ms", added, addedc, peak);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
CCMD(vmengine)
|
||||
{
|
||||
if (argv.argc() == 2)
|
||||
{
|
||||
if (stricmp(argv[1], "default") == 0)
|
||||
{
|
||||
VMSelectEngine(VMEngine_Default);
|
||||
return;
|
||||
}
|
||||
else if (stricmp(argv[1], "checked") == 0)
|
||||
{
|
||||
VMSelectEngine(VMEngine_Checked);
|
||||
return;
|
||||
}
|
||||
else if (stricmp(argv[1], "unchecked") == 0)
|
||||
{
|
||||
VMSelectEngine(VMEngine_Unchecked);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Printf("Usage: vmengine <default|checked|unchecked>\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
474
src/scripting/vm/vmintern.h
Normal file
474
src/scripting/vm/vmintern.h
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
#pragma once
|
||||
|
||||
#include "vm.h"
|
||||
|
||||
class VMScriptFunction;
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#define VM_DEFINE_OP2(TYPE, ARG1, ARG2) TYPE ARG2, ARG1
|
||||
#define VM_DEFINE_OP4(TYPE, ARG1, ARG2, ARG3, ARG4) TYPE ARG4, ARG3, ARG2, ARG1
|
||||
#else // little endian
|
||||
#define VM_DEFINE_OP2(TYPE, ARG1, ARG2) TYPE ARG1, ARG2
|
||||
#define VM_DEFINE_OP4(TYPE, ARG1, ARG2, ARG3, ARG4) TYPE ARG1, ARG2, ARG3, ARG4
|
||||
#endif // __BIG_ENDIAN__
|
||||
|
||||
union VMOP
|
||||
{
|
||||
struct
|
||||
{
|
||||
VM_DEFINE_OP4(VM_UBYTE, op, a, b, c);
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_DEFINE_OP4(VM_SBYTE, pad0, as, bs, cs);
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_DEFINE_OP2(VM_SWORD, pad1:8, i24:24);
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_DEFINE_OP2(VM_SWORD, pad2:16, i16:16);
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_DEFINE_OP2(VM_UHALF, pad3, i16u);
|
||||
};
|
||||
VM_UWORD word;
|
||||
|
||||
// Interesting fact: VC++ produces better code for i16 when it's defined
|
||||
// as a bitfield than when it's defined as two discrete units.
|
||||
// Compare:
|
||||
// mov eax,dword ptr [op] ; As two discrete units
|
||||
// shr eax,10h
|
||||
// movsx eax,ax
|
||||
// versus:
|
||||
// mov eax,dword ptr [op] ; As a bitfield
|
||||
// sar eax,10h
|
||||
};
|
||||
|
||||
#undef VM_DEFINE_OP4
|
||||
#undef VM_DEFINE_OP2
|
||||
|
||||
enum
|
||||
{
|
||||
#include "vmops.h"
|
||||
NUM_OPS
|
||||
};
|
||||
|
||||
// Flags for A field of CMPS
|
||||
enum
|
||||
{
|
||||
CMP_CHECK = 1,
|
||||
|
||||
CMP_EQ = 0,
|
||||
CMP_LT = 2,
|
||||
CMP_LE = 4,
|
||||
CMP_METHOD_MASK = 6,
|
||||
|
||||
CMP_BK = 8,
|
||||
CMP_CK = 16,
|
||||
CMP_APPROX = 32,
|
||||
};
|
||||
|
||||
// Floating point operations for FLOP
|
||||
enum
|
||||
{
|
||||
FLOP_ABS,
|
||||
FLOP_NEG,
|
||||
FLOP_EXP,
|
||||
FLOP_LOG,
|
||||
FLOP_LOG10,
|
||||
FLOP_SQRT,
|
||||
FLOP_CEIL,
|
||||
FLOP_FLOOR,
|
||||
|
||||
FLOP_ACOS, // This group works with radians
|
||||
FLOP_ASIN,
|
||||
FLOP_ATAN,
|
||||
FLOP_COS,
|
||||
FLOP_SIN,
|
||||
FLOP_TAN,
|
||||
|
||||
FLOP_ACOS_DEG, // This group works with degrees
|
||||
FLOP_ASIN_DEG,
|
||||
FLOP_ATAN_DEG,
|
||||
FLOP_COS_DEG,
|
||||
FLOP_SIN_DEG,
|
||||
FLOP_TAN_DEG,
|
||||
|
||||
FLOP_COSH,
|
||||
FLOP_SINH,
|
||||
FLOP_TANH,
|
||||
};
|
||||
|
||||
// Cast operations
|
||||
enum
|
||||
{
|
||||
CAST_I2F,
|
||||
CAST_I2S,
|
||||
CAST_U2F,
|
||||
CAST_U2S,
|
||||
CAST_F2I,
|
||||
CAST_F2U,
|
||||
CAST_F2S,
|
||||
CAST_P2S,
|
||||
CAST_S2I,
|
||||
CAST_S2F,
|
||||
CAST_S2N,
|
||||
CAST_N2S,
|
||||
CAST_S2Co,
|
||||
CAST_S2So,
|
||||
CAST_Co2S,
|
||||
CAST_So2S,
|
||||
CAST_V22S,
|
||||
CAST_V32S,
|
||||
CAST_SID2S,
|
||||
CAST_TID2S,
|
||||
|
||||
CASTB_I,
|
||||
CASTB_F,
|
||||
CASTB_A,
|
||||
CASTB_S
|
||||
};
|
||||
|
||||
enum EVMOpMode
|
||||
{
|
||||
MODE_ASHIFT = 0,
|
||||
MODE_BSHIFT = 4,
|
||||
MODE_CSHIFT = 8,
|
||||
MODE_BCSHIFT = 12,
|
||||
|
||||
MODE_ATYPE = 15 << MODE_ASHIFT,
|
||||
MODE_BTYPE = 15 << MODE_BSHIFT,
|
||||
MODE_CTYPE = 15 << MODE_CSHIFT,
|
||||
MODE_BCTYPE = 31 << MODE_BCSHIFT,
|
||||
|
||||
MODE_I = 0,
|
||||
MODE_F,
|
||||
MODE_S,
|
||||
MODE_P,
|
||||
MODE_V,
|
||||
MODE_X,
|
||||
MODE_KI,
|
||||
MODE_KF,
|
||||
MODE_KS,
|
||||
MODE_KP,
|
||||
MODE_KV,
|
||||
MODE_UNUSED,
|
||||
MODE_IMMS,
|
||||
MODE_IMMZ,
|
||||
MODE_JOINT,
|
||||
MODE_CMP,
|
||||
|
||||
MODE_PARAM,
|
||||
MODE_THROW,
|
||||
MODE_CATCH,
|
||||
MODE_CAST,
|
||||
|
||||
MODE_AI = MODE_I << MODE_ASHIFT,
|
||||
MODE_AF = MODE_F << MODE_ASHIFT,
|
||||
MODE_AS = MODE_S << MODE_ASHIFT,
|
||||
MODE_AP = MODE_P << MODE_ASHIFT,
|
||||
MODE_AV = MODE_V << MODE_ASHIFT,
|
||||
MODE_AX = MODE_X << MODE_ASHIFT,
|
||||
MODE_AKP = MODE_KP << MODE_ASHIFT,
|
||||
MODE_AUNUSED = MODE_UNUSED << MODE_ASHIFT,
|
||||
MODE_AIMMS = MODE_IMMS << MODE_ASHIFT,
|
||||
MODE_AIMMZ = MODE_IMMZ << MODE_ASHIFT,
|
||||
MODE_ACMP = MODE_CMP << MODE_ASHIFT,
|
||||
|
||||
MODE_BI = MODE_I << MODE_BSHIFT,
|
||||
MODE_BF = MODE_F << MODE_BSHIFT,
|
||||
MODE_BS = MODE_S << MODE_BSHIFT,
|
||||
MODE_BP = MODE_P << MODE_BSHIFT,
|
||||
MODE_BV = MODE_V << MODE_BSHIFT,
|
||||
MODE_BX = MODE_X << MODE_BSHIFT,
|
||||
MODE_BKI = MODE_KI << MODE_BSHIFT,
|
||||
MODE_BKF = MODE_KF << MODE_BSHIFT,
|
||||
MODE_BKS = MODE_KS << MODE_BSHIFT,
|
||||
MODE_BKP = MODE_KP << MODE_BSHIFT,
|
||||
MODE_BKV = MODE_KV << MODE_BSHIFT,
|
||||
MODE_BUNUSED = MODE_UNUSED << MODE_BSHIFT,
|
||||
MODE_BIMMS = MODE_IMMS << MODE_BSHIFT,
|
||||
MODE_BIMMZ = MODE_IMMZ << MODE_BSHIFT,
|
||||
|
||||
MODE_CI = MODE_I << MODE_CSHIFT,
|
||||
MODE_CF = MODE_F << MODE_CSHIFT,
|
||||
MODE_CS = MODE_S << MODE_CSHIFT,
|
||||
MODE_CP = MODE_P << MODE_CSHIFT,
|
||||
MODE_CV = MODE_V << MODE_CSHIFT,
|
||||
MODE_CX = MODE_X << MODE_CSHIFT,
|
||||
MODE_CKI = MODE_KI << MODE_CSHIFT,
|
||||
MODE_CKF = MODE_KF << MODE_CSHIFT,
|
||||
MODE_CKS = MODE_KS << MODE_CSHIFT,
|
||||
MODE_CKP = MODE_KP << MODE_CSHIFT,
|
||||
MODE_CKV = MODE_KV << MODE_CSHIFT,
|
||||
MODE_CUNUSED = MODE_UNUSED << MODE_CSHIFT,
|
||||
MODE_CIMMS = MODE_IMMS << MODE_CSHIFT,
|
||||
MODE_CIMMZ = MODE_IMMZ << MODE_CSHIFT,
|
||||
|
||||
MODE_BCJOINT = (MODE_JOINT << MODE_BSHIFT) | (MODE_JOINT << MODE_CSHIFT),
|
||||
MODE_BCKI = MODE_KI << MODE_BCSHIFT,
|
||||
MODE_BCKF = MODE_KF << MODE_BCSHIFT,
|
||||
MODE_BCKS = MODE_KS << MODE_BCSHIFT,
|
||||
MODE_BCKP = MODE_KP << MODE_BCSHIFT,
|
||||
MODE_BCIMMS = MODE_IMMS << MODE_BCSHIFT,
|
||||
MODE_BCIMMZ = MODE_IMMZ << MODE_BCSHIFT,
|
||||
MODE_BCPARAM = MODE_PARAM << MODE_BCSHIFT,
|
||||
MODE_BCTHROW = MODE_THROW << MODE_BCSHIFT,
|
||||
MODE_BCCATCH = MODE_CATCH << MODE_BCSHIFT,
|
||||
MODE_BCCAST = MODE_CAST << MODE_BCSHIFT,
|
||||
|
||||
MODE_ABCJOINT = (MODE_JOINT << MODE_ASHIFT) | MODE_BCJOINT,
|
||||
};
|
||||
|
||||
struct VMOpInfo
|
||||
{
|
||||
const char *Name;
|
||||
int Mode;
|
||||
};
|
||||
|
||||
extern const VMOpInfo OpInfo[NUM_OPS];
|
||||
|
||||
|
||||
// VM frame layout:
|
||||
// VMFrame header
|
||||
// parameter stack - 16 byte boundary, 16 bytes each
|
||||
// double registers - 8 bytes each
|
||||
// string registers - 4 or 8 bytes each
|
||||
// address registers - 4 or 8 bytes each
|
||||
// data registers - 4 bytes each
|
||||
// address register tags-1 byte each
|
||||
// extra space - 16 byte boundary
|
||||
struct VMFrame
|
||||
{
|
||||
VMFrame *ParentFrame;
|
||||
VMFunction *Func;
|
||||
VM_UBYTE NumRegD;
|
||||
VM_UBYTE NumRegF;
|
||||
VM_UBYTE NumRegS;
|
||||
VM_UBYTE NumRegA;
|
||||
VM_UHALF MaxParam;
|
||||
VM_UHALF NumParam; // current number of parameters
|
||||
|
||||
static int FrameSize(int numregd, int numregf, int numregs, int numrega, int numparam, int numextra)
|
||||
{
|
||||
int size = (sizeof(VMFrame) + 15) & ~15;
|
||||
size += numparam * sizeof(VMValue);
|
||||
size += numregf * sizeof(double);
|
||||
size += numrega * sizeof(void *);
|
||||
size += numregs * sizeof(FString);
|
||||
size += numregd * sizeof(int);
|
||||
if (numextra != 0)
|
||||
{
|
||||
size = (size + 15) & ~15;
|
||||
size += numextra;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
VMValue *GetParam() const
|
||||
{
|
||||
assert(((size_t)this & 15) == 0 && "VM frame is unaligned");
|
||||
return (VMValue *)(((size_t)(this + 1) + 15) & ~15);
|
||||
}
|
||||
|
||||
double *GetRegF() const
|
||||
{
|
||||
return (double *)(GetParam() + MaxParam);
|
||||
}
|
||||
|
||||
FString *GetRegS() const
|
||||
{
|
||||
return (FString *)(GetRegF() + NumRegF);
|
||||
}
|
||||
|
||||
void **GetRegA() const
|
||||
{
|
||||
return (void **)(GetRegS() + NumRegS);
|
||||
}
|
||||
|
||||
int *GetRegD() const
|
||||
{
|
||||
return (int *)(GetRegA() + NumRegA);
|
||||
}
|
||||
|
||||
void *GetExtra() const
|
||||
{
|
||||
uint8_t *pbeg = (uint8_t*)(GetRegD() + NumRegD);
|
||||
ptrdiff_t ofs = pbeg - (uint8_t *)this;
|
||||
return (VM_UBYTE *)this + ((ofs + 15) & ~15);
|
||||
}
|
||||
|
||||
void GetAllRegs(int *&d, double *&f, FString *&s, void **&a, VMValue *¶m) const
|
||||
{
|
||||
// Calling the individual functions produces suboptimal code. :(
|
||||
param = GetParam();
|
||||
f = (double *)(param + MaxParam);
|
||||
s = (FString *)(f + NumRegF);
|
||||
a = (void **)(s + NumRegS);
|
||||
d = (int *)(a + NumRegA);
|
||||
}
|
||||
|
||||
void InitRegS();
|
||||
};
|
||||
|
||||
struct VMRegisters
|
||||
{
|
||||
VMRegisters(const VMFrame *frame)
|
||||
{
|
||||
frame->GetAllRegs(d, f, s, a, param);
|
||||
}
|
||||
|
||||
VMRegisters(const VMRegisters &o)
|
||||
: d(o.d), f(o.f), s(o.s), a(o.a), param(o.param)
|
||||
{ }
|
||||
|
||||
int *d;
|
||||
double *f;
|
||||
FString *s;
|
||||
void **a;
|
||||
VMValue *param;
|
||||
};
|
||||
|
||||
union FVoidObj
|
||||
{
|
||||
DObject *o;
|
||||
void *v;
|
||||
};
|
||||
|
||||
struct FStatementInfo
|
||||
{
|
||||
uint16_t InstructionIndex;
|
||||
uint16_t LineNumber;
|
||||
};
|
||||
|
||||
class VMFrameStack
|
||||
{
|
||||
public:
|
||||
VMFrameStack();
|
||||
~VMFrameStack();
|
||||
VMFrame *AllocFrame(VMScriptFunction *func);
|
||||
VMFrame *PopFrame();
|
||||
VMFrame *TopFrame()
|
||||
{
|
||||
assert(Blocks != NULL && Blocks->LastFrame != NULL);
|
||||
return Blocks->LastFrame;
|
||||
}
|
||||
private:
|
||||
enum { BLOCK_SIZE = 4096 }; // Default block size
|
||||
struct BlockHeader
|
||||
{
|
||||
BlockHeader *NextBlock;
|
||||
VMFrame *LastFrame;
|
||||
VM_UBYTE *FreeSpace;
|
||||
int BlockSize;
|
||||
|
||||
void InitFreeSpace()
|
||||
{
|
||||
FreeSpace = (VM_UBYTE *)(((size_t)(this + 1) + 15) & ~15);
|
||||
}
|
||||
};
|
||||
BlockHeader *Blocks;
|
||||
BlockHeader *UnusedBlocks;
|
||||
VMFrame *Alloc(int size);
|
||||
};
|
||||
|
||||
class VMParamFiller
|
||||
{
|
||||
public:
|
||||
VMParamFiller(const VMFrame *frame) : Reg(frame), RegD(0), RegF(0), RegS(0), RegA(0) {}
|
||||
VMParamFiller(const VMRegisters *reg) : Reg(*reg), RegD(0), RegF(0), RegS(0), RegA(0) {}
|
||||
|
||||
void ParamInt(int val)
|
||||
{
|
||||
Reg.d[RegD++] = val;
|
||||
}
|
||||
|
||||
void ParamFloat(double val)
|
||||
{
|
||||
Reg.f[RegF++] = val;
|
||||
}
|
||||
|
||||
void ParamString(FString &val)
|
||||
{
|
||||
Reg.s[RegS++] = val;
|
||||
}
|
||||
|
||||
void ParamString(const char *val)
|
||||
{
|
||||
Reg.s[RegS++] = val;
|
||||
}
|
||||
|
||||
void ParamObject(DObject *obj)
|
||||
{
|
||||
Reg.a[RegA] = obj;
|
||||
RegA++;
|
||||
}
|
||||
|
||||
void ParamPointer(void *ptr)
|
||||
{
|
||||
Reg.a[RegA] = ptr;
|
||||
RegA++;
|
||||
}
|
||||
|
||||
private:
|
||||
const VMRegisters Reg;
|
||||
int RegD, RegF, RegS, RegA;
|
||||
};
|
||||
|
||||
|
||||
enum EVMEngine
|
||||
{
|
||||
VMEngine_Default,
|
||||
VMEngine_Unchecked,
|
||||
VMEngine_Checked
|
||||
};
|
||||
|
||||
void VMSelectEngine(EVMEngine engine);
|
||||
extern int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret);
|
||||
void VMFillParams(VMValue *params, VMFrame *callee, int numparam);
|
||||
|
||||
void VMDumpConstants(FILE *out, const VMScriptFunction *func);
|
||||
void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func);
|
||||
|
||||
extern thread_local VMFrameStack GlobalVMStack;
|
||||
|
||||
typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
|
||||
|
||||
class VMScriptFunction : public VMFunction
|
||||
{
|
||||
public:
|
||||
VMScriptFunction(FName name = NAME_None);
|
||||
~VMScriptFunction();
|
||||
void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers);
|
||||
|
||||
VMOP *Code;
|
||||
FStatementInfo *LineInfo;
|
||||
FString SourceFileName;
|
||||
int *KonstD;
|
||||
double *KonstF;
|
||||
FString *KonstS;
|
||||
FVoidObj *KonstA;
|
||||
int ExtraSpace;
|
||||
int CodeSize; // Size of code in instructions (not bytes)
|
||||
unsigned LineInfoCount;
|
||||
unsigned StackSize;
|
||||
VM_UBYTE NumRegD;
|
||||
VM_UBYTE NumRegF;
|
||||
VM_UBYTE NumRegS;
|
||||
VM_UBYTE NumRegA;
|
||||
VM_UHALF NumKonstD;
|
||||
VM_UHALF NumKonstF;
|
||||
VM_UHALF NumKonstS;
|
||||
VM_UHALF NumKonstA;
|
||||
VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once
|
||||
VM_UBYTE NumArgs; // Number of arguments this function takes
|
||||
TArray<FTypeAndOffset> SpecialInits; // list of all contents on the extra stack which require construction and destruction
|
||||
|
||||
void InitExtra(void *addr);
|
||||
void DestroyExtra(void *addr);
|
||||
int AllocExtraStack(PType *type);
|
||||
int PCToLine(const VMOP *pc);
|
||||
};
|
||||
|
|
@ -45,8 +45,6 @@ xx(LS, ls, RSRPKI, LS_R, 4, REGT_INT), // load string
|
|||
xx(LS_R, ls, RSRPRI, NOP, 0, 0),
|
||||
xx(LO, lo, RPRPKI, LO_R, 4, REGT_INT), // load object
|
||||
xx(LO_R, lo, RPRPRI, NOP, 0, 0),
|
||||
xx(LOS, los, RPRPKI, LOS_R, 4, REGT_INT), // load object (stack version without read barrier)
|
||||
xx(LOS_R, lo, RPRPRI, NOP, 0, 0),
|
||||
xx(LP, lp, RPRPKI, LP_R, 4, REGT_INT), // load pointer
|
||||
xx(LP_R, lp, RPRPRI, NOP, 0, 0),
|
||||
xx(LV2, lv2, RVRPKI, LV2_R, 4, REGT_INT), // load vector2
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
*/
|
||||
|
||||
#include "dobject.h"
|
||||
#include "vmintern.h"
|
||||
#include "types.h"
|
||||
#include "sc_man.h"
|
||||
#include "memarena.h"
|
||||
#include "zcc_parser.h"
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include "i_system.h"
|
||||
#include "gdtoa.h"
|
||||
#include "backend/vmbuilder.h"
|
||||
#include "types.h"
|
||||
|
||||
FSharedStringArena VMStringConstants;
|
||||
bool isActor(PContainerType *type);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "memarena.h"
|
||||
#include "sc_man.h"
|
||||
#include "types.h"
|
||||
|
||||
struct ZCCToken
|
||||
{
|
||||
|
|
@ -193,7 +194,7 @@ struct ZCC_NamedNode : ZCC_TreeNode
|
|||
|
||||
struct ZCC_Struct : ZCC_NamedNode
|
||||
{
|
||||
VM_UWORD Flags;
|
||||
uint32_t Flags;
|
||||
ZCC_TreeNode *Body;
|
||||
PContainerType *Type;
|
||||
VersionInfo Version;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue