backend update from GZDoom.

This commit is contained in:
Christoph Oelckers 2023-12-10 13:30:50 +01:00
parent 80fe0788c9
commit c0d166c307
74 changed files with 1496 additions and 392 deletions

View file

@ -2728,7 +2728,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
{
FArgumentList args;
args.Push(Right);
auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition);
auto call = new FxMemberFunctionCall(Base, NAME_Copy, std::move(args), ScriptPosition);
Right = Base = nullptr;
delete this;
return call->Resolve(ctx);
@ -2756,7 +2756,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
{
FArgumentList args;
args.Push(Right);
auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition);
auto call = new FxMemberFunctionCall(Base, NAME_Copy, std::move(args), ScriptPosition);
Right = Base = nullptr;
delete this;
return call->Resolve(ctx);
@ -3826,6 +3826,16 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
delete left;
left = x;
}
else if (left->IsNumeric() && right->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
{
right = new FxTypeCast(right, TypeSInt32, true);
SAFE_RESOLVE(right, ctx);
}
else if (right->IsNumeric() && left->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
{
left = new FxTypeCast(left, TypeSInt32, true);
SAFE_RESOLVE(left, ctx);
}
if (left->ValueType == TypeString || right->ValueType == TypeString)
{
@ -4118,6 +4128,17 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
delete left;
left = x;
}
else if (left->IsNumeric() && right->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
{
right = new FxIntCast(right, true, true);
SAFE_RESOLVE(right, ctx);
}
else if (right->IsNumeric() && left->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
{
left = new FxTypeCast(left, TypeSInt32, true);
SAFE_RESOLVE(left, ctx);
}
// Special cases: Compare strings and names with names, sounds, colors, state labels and class types.
// These are all types a string can be implicitly cast into, so for convenience, so they should when doing a comparison.
if ((left->ValueType == TypeString || left->ValueType == TypeName) &&
@ -8181,7 +8202,7 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction
//
//==========================================================================
FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos)
FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos)
: FxExpression(EFX_FunctionCall, pos)
{
MethodName = methodname;
@ -8608,7 +8629,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
//
//==========================================================================
FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos)
FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &&args, const FScriptPosition &pos)
: FxExpression(EFX_MemberFunctionCall, pos)
{
Self = self;
@ -9153,7 +9174,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
if (a->IsMap())
{
// Copy and Move must turn their parameter into a pointer to the backing struct type.
auto o = static_cast<PMapIterator*>(a->ValueType);
auto o = static_cast<PMap*>(a->ValueType);
auto backingtype = o->BackingType;
if (mapKeyType != o->KeyType || mapValueType != o->ValueType)
{
@ -11361,12 +11382,14 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build)
//
//==========================================================================
FxForEachLoop::FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* code, const FScriptPosition& pos)
: FxLoopStatement(EFX_ForEachLoop, pos), loopVarName(vn), Array(arrayvar), Array2(arrayvar2), Code(code)
FxForEachLoop::FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* arrayvar3, FxExpression* arrayvar4, FxExpression* code, const FScriptPosition& pos)
: FxLoopStatement(EFX_ForEachLoop, pos), loopVarName(vn), Array(arrayvar), Array2(arrayvar2), Array3(arrayvar3), Array4(arrayvar4), Code(code)
{
ValueType = TypeVoid;
if (Array != nullptr) Array->NeedResult = false;
if (Array2 != nullptr) Array2->NeedResult = false;
if (Array3 != nullptr) Array3->NeedResult = false;
if (Array4 != nullptr) Array4->NeedResult = false;
if (Code != nullptr) Code->NeedResult = false;
}
@ -11374,57 +11397,347 @@ FxForEachLoop::~FxForEachLoop()
{
SAFE_DELETE(Array);
SAFE_DELETE(Array2);
SAFE_DELETE(Array3);
SAFE_DELETE(Array4);
SAFE_DELETE(Code);
}
extern bool IsGameSpecificForEachLoop(FxForEachLoop *);
extern FxExpression * ResolveGameSpecificForEachLoop(FxForEachLoop *);
FxExpression* FxForEachLoop::DoResolve(FCompileContext& ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(Array, ctx);
SAFE_RESOLVE(Array2, ctx);
SAFE_RESOLVE(Array3, ctx);
SAFE_RESOLVE(Array4, ctx);
// Instead of writing a new code generator for this, convert this into
//
// int @size = array.Size();
// for(int @i = 0; @i < @size; @i++)
// {
// let var = array[i];
// body
// }
// and let the existing 'for' loop code sort out the rest.
FName sizevar = "@size";
FName itvar = "@i";
FArgumentList al;
auto block = new FxCompoundStatement(ScriptPosition);
auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, al, ScriptPosition);
auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition);
auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition);
block->Add(size);
block->Add(it);
if(Array->ValueType->isMap() || Array->ValueType->isMapIterator())
{
auto mapLoop = new FxTwoArgForEachLoop(NAME_None, loopVarName, Array, Array2, Array3, Array4, Code, ScriptPosition);
Array = Array2 = Array3 = Array4 = Code = nullptr;
delete this;
return mapLoop->Resolve(ctx);
}
else if(IsGameSpecificForEachLoop(this))
{
return ResolveGameSpecificForEachLoop(this)->Resolve(ctx);
}
else
{
// Instead of writing a new code generator for this, convert this into
//
// int @size = array.Size();
// for(int @i = 0; @i < @size; @i++)
// {
// let var = array[i];
// body
// }
// and let the existing 'for' loop code sort out the rest.
auto cit = new FxLocalVariable(it, ScriptPosition);
auto csiz = new FxLocalVariable(size, ScriptPosition);
auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition));
FName sizevar = "@size";
FName itvar = "@i";
auto iit = new FxLocalVariable(it, ScriptPosition);
auto bump = new FxPreIncrDecr(iit, TK_Incr);
auto block = new FxCompoundStatement(ScriptPosition);
auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, {}, ScriptPosition);
auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition);
auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition);
block->Add(size);
block->Add(it);
auto ait = new FxLocalVariable(it, ScriptPosition);
auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element.
auto cit = new FxLocalVariable(it, ScriptPosition);
auto csiz = new FxLocalVariable(size, ScriptPosition);
auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition));
auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition);
auto body = new FxCompoundStatement(ScriptPosition);
body->Add(assign);
body->Add(Code);
auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition);
block->Add(forloop);
Array2 = Array = nullptr;
Code = nullptr;
delete this;
return block->Resolve(ctx);
auto iit = new FxLocalVariable(it, ScriptPosition);
auto bump = new FxPreIncrDecr(iit, TK_Incr);
auto ait = new FxLocalVariable(it, ScriptPosition);
auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element.
auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition);
auto body = new FxCompoundStatement(ScriptPosition);
body->Add(assign);
body->Add(Code);
auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition);
block->Add(forloop);
Array2 = Array = nullptr;
Code = nullptr;
delete this;
return block->Resolve(ctx);
}
}
//==========================================================================
//
// FxMapForEachLoop
//
//==========================================================================
FxTwoArgForEachLoop::FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos)
: FxExpression(EFX_TwoArgForEachLoop,pos), keyVarName(kv), valueVarName(vv), MapExpr(mapexpr), MapExpr2(mapexpr2), MapExpr3(mapexpr3), MapExpr4(mapexpr4), Code(code)
{
ValueType = TypeVoid;
if (MapExpr != nullptr) MapExpr->NeedResult = false;
if (MapExpr2 != nullptr) MapExpr2->NeedResult = false;
if (MapExpr3 != nullptr) MapExpr3->NeedResult = false;
if (MapExpr4 != nullptr) MapExpr4->NeedResult = false;
if (Code != nullptr) Code->NeedResult = false;
}
FxTwoArgForEachLoop::~FxTwoArgForEachLoop()
{
SAFE_DELETE(MapExpr);
SAFE_DELETE(MapExpr2);
SAFE_DELETE(MapExpr3);
SAFE_DELETE(MapExpr4);
SAFE_DELETE(Code);
}
extern bool HasGameSpecificTwoArgForEachLoopTypeNames();
extern const char * GetGameSpecificTwoArgForEachLoopTypeNames();
extern bool IsGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *);
extern FxExpression * ResolveGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *);
FxExpression *FxTwoArgForEachLoop::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(MapExpr, ctx);
SAFE_RESOLVE(MapExpr2, ctx);
SAFE_RESOLVE(MapExpr3, ctx);
SAFE_RESOLVE(MapExpr4, ctx);
bool is_iterator = false;
if(IsGameSpecificTwoArgForEachLoop(this))
{
return ResolveGameSpecificTwoArgForEachLoop(this)->Resolve(ctx);
}
else if(!(MapExpr->ValueType->isMap() || (is_iterator = MapExpr->ValueType->isMapIterator())))
{
if(HasGameSpecificTwoArgForEachLoopTypeNames())
{
ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be %s a map, or a map iterator, but is a %s", GetGameSpecificTwoArgForEachLoopTypeNames(), MapExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
else
{
ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be a map or a map iterator, but is a %s", MapExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
}
else if(valueVarName == NAME_None)
{
ScriptPosition.Message(MSG_ERROR, "missing value for foreach( k, v : m )");
delete this;
return nullptr;
}
auto block = new FxCompoundStatement(ScriptPosition);
auto valType = is_iterator ? static_cast<PMapIterator*>(MapExpr->ValueType)->ValueType : static_cast<PMap*>(MapExpr->ValueType)->ValueType;
auto keyType = is_iterator ? static_cast<PMapIterator*>(MapExpr->ValueType)->KeyType : static_cast<PMap*>(MapExpr->ValueType)->KeyType;
auto v = new FxLocalVariableDeclaration(valType, valueVarName, nullptr, 0, ScriptPosition);
block->Add(v);
if(keyVarName != NAME_None)
{
auto k = new FxLocalVariableDeclaration(keyType, keyVarName, nullptr, 0, ScriptPosition);
block->Add(k);
}
if(MapExpr->ValueType->isMapIterator())
{
/*
{
KeyType k;
ValueType v;
if(it.ReInit()) while(it.Next())
{
k = it.GetKey();
v = it.GetValue();
body
}
}
*/
auto inner_block = new FxCompoundStatement(ScriptPosition);
if(keyVarName != NAME_None)
{
inner_block->Add(new FxAssign(new FxIdentifier(keyVarName, ScriptPosition), new FxMemberFunctionCall(MapExpr, "GetKey", {}, ScriptPosition), true));
}
inner_block->Add(new FxAssign(new FxIdentifier(valueVarName, ScriptPosition), new FxMemberFunctionCall(MapExpr2, "GetValue", {}, ScriptPosition), true));
inner_block->Add(Code);
auto reInit = new FxMemberFunctionCall(MapExpr3, "ReInit", {}, ScriptPosition);
block->Add(new FxIfStatement(reInit, new FxWhileLoop(new FxMemberFunctionCall(MapExpr4, "Next", {}, ScriptPosition), inner_block, ScriptPosition), nullptr, ScriptPosition));
MapExpr = MapExpr2 = MapExpr3 = MapExpr4 = Code = nullptr;
delete this;
return block->Resolve(ctx);
}
else
{
/*
{
KeyType k;
ValueType v;
MapIterator<KeyType, ValueType> @it;
@it.Init(map);
while(@it.Next())
{
k = @it.GetKey();
v = @it.GetValue();
body
}
}
*/
PType * itType = NewMapIterator(keyType, valType);
auto it = new FxLocalVariableDeclaration(itType, "@it", nullptr, 0, ScriptPosition);
block->Add(it);
FArgumentList al_map;
al_map.Push(MapExpr);
block->Add(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Init", std::move(al_map), ScriptPosition));
auto inner_block = new FxCompoundStatement(ScriptPosition);
if(keyVarName != NAME_None)
{
inner_block->Add(new FxAssign(new FxIdentifier(keyVarName, ScriptPosition), new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "GetKey", {}, ScriptPosition), true));
}
inner_block->Add(new FxAssign(new FxIdentifier(valueVarName, ScriptPosition), new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "GetValue", {}, ScriptPosition), true));
inner_block->Add(Code);
block->Add(new FxWhileLoop(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition), inner_block, ScriptPosition));
delete MapExpr2;
delete MapExpr3;
delete MapExpr4;
MapExpr = MapExpr2 = MapExpr3 = MapExpr4 = Code = nullptr;
delete this;
return block->Resolve(ctx);
}
}
//==========================================================================
//
// FxThreeArgForEachLoop
//
//==========================================================================
FxThreeArgForEachLoop::FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos)
: FxExpression(EFX_ThreeArgForEachLoop, pos), varVarName(vv), posVarName(pv), flagsVarName(fv), BlockIteratorExpr(blockiteartorexpr), Code(code)
{
ValueType = TypeVoid;
if (BlockIteratorExpr != nullptr) BlockIteratorExpr->NeedResult = false;
if (Code != nullptr) Code->NeedResult = false;
}
FxThreeArgForEachLoop::~FxThreeArgForEachLoop()
{
SAFE_DELETE(BlockIteratorExpr);
SAFE_DELETE(Code);
}
extern bool HasGameSpecificThreeArgForEachLoopTypeNames();
extern const char * GetGameSpecificThreeArgForEachLoopTypeNames();
extern bool IsGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *);
extern FxExpression * ResolveGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *);
FxExpression *FxThreeArgForEachLoop::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(BlockIteratorExpr, ctx);
if(IsGameSpecificThreeArgForEachLoop(this))
{
return ResolveGameSpecificThreeArgForEachLoop(this)->Resolve(ctx);
}
else
{
//put any non-game-specific typed for-each loops here
}
if(HasGameSpecificThreeArgForEachLoopTypeNames())
{
ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - 'it' must be % but is a %s", GetGameSpecificThreeArgForEachLoopTypeNames(), BlockIteratorExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
else
{
ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - three-arg foreach loops not supported");
delete this;
return nullptr;
}
}
//==========================================================================
//
// FxCastForEachLoop
//
//==========================================================================
FxTypedForEachLoop::FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos)
: FxExpression(EFX_TypedForEachLoop, pos), className(cv), varName(vv), Expr(castiteartorexpr), Code(code)
{
ValueType = TypeVoid;
if (Expr != nullptr) Expr->NeedResult = false;
if (Code != nullptr) Code->NeedResult = false;
}
FxTypedForEachLoop::~FxTypedForEachLoop()
{
SAFE_DELETE(Expr);
SAFE_DELETE(Code);
}
extern bool HasGameSpecificTypedForEachLoopTypeNames();
extern const char * GetGameSpecificTypedForEachLoopTypeNames();
extern bool IsGameSpecificTypedForEachLoop(FxTypedForEachLoop *);
extern FxExpression * ResolveGameSpecificTypedForEachLoop(FxTypedForEachLoop *);
FxExpression *FxTypedForEachLoop::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(Expr, ctx);
if(IsGameSpecificTypedForEachLoop(this))
{
return ResolveGameSpecificTypedForEachLoop(this)->Resolve(ctx);
}
else
{
//put any non-game-specific typed for-each loops here
}
if(HasGameSpecificTypedForEachLoopTypeNames())
{
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be % but is a %s",GetGameSpecificTypedForEachLoopTypeNames(), Expr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
else
{
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - typed foreach loops not supported");
delete this;
return nullptr;
}
}
//==========================================================================
//
@ -12267,8 +12580,7 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx)
if (IsDynamicArray())
{
auto stackVar = new FxStackVariable(ValueType, StackOffset, ScriptPosition);
FArgumentList argsList;
clearExpr = new FxMemberFunctionCall(stackVar, "Clear", argsList, ScriptPosition);
clearExpr = new FxMemberFunctionCall(stackVar, "Clear", {}, ScriptPosition);
SAFE_RESOLVE(clearExpr, ctx);
}
@ -12586,10 +12898,9 @@ FxExpression *FxLocalArrayDeclaration::Resolve(FCompileContext &ctx)
else
{
FArgumentList argsList;
argsList.Clear();
argsList.Push(v);
FxExpression *funcCall = new FxMemberFunctionCall(stackVar, NAME_Push, argsList, (const FScriptPosition) v->ScriptPosition);
FxExpression *funcCall = new FxMemberFunctionCall(stackVar, NAME_Push, std::move(argsList), (const FScriptPosition) v->ScriptPosition);
SAFE_RESOLVE(funcCall, ctx);
v = funcCall;

View file

@ -275,6 +275,9 @@ enum EFxType
EFX_DoWhileLoop,
EFX_ForLoop,
EFX_ForEachLoop,
EFX_TwoArgForEachLoop,
EFX_ThreeArgForEachLoop,
EFX_TypedForEachLoop,
EFX_JumpStatement,
EFX_ReturnStatement,
EFX_ClassTypeCast,
@ -1621,7 +1624,7 @@ public:
FName MethodName;
FArgumentList ArgList;
FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos);
FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos);
~FxFunctionCall();
FxExpression *Resolve(FCompileContext&);
};
@ -1638,10 +1641,11 @@ class FxMemberFunctionCall : public FxExpression
FxExpression *Self;
FName MethodName;
FArgumentList ArgList;
bool ResolveSelf;
public:
FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos);
FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &&args, const FScriptPosition &pos);
~FxMemberFunctionCall();
FxExpression *Resolve(FCompileContext&);
};
@ -2069,17 +2073,83 @@ public:
class FxForEachLoop : public FxLoopStatement
{
public:
FName loopVarName;
FxExpression* Array;
FxExpression* Array2;
FxExpression* Array3;
FxExpression* Array4;
FxExpression* Code;
public:
FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* code, const FScriptPosition& pos);
FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* arrayvar3, FxExpression* arrayvar4, FxExpression* code, const FScriptPosition& pos);
~FxForEachLoop();
FxExpression* DoResolve(FCompileContext&);
};
//==========================================================================
//
// FxTwoArgForEachLoop
//
//==========================================================================
class FxTwoArgForEachLoop : public FxExpression
{
public:
FName keyVarName;
FName valueVarName;
FxExpression* MapExpr;
FxExpression* MapExpr2;
FxExpression* MapExpr3;
FxExpression* MapExpr4;
FxExpression* Code;
FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos);
~FxTwoArgForEachLoop();
FxExpression *Resolve(FCompileContext&);
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};
//==========================================================================
//
// FxThreeArgForEachLoop
//
//==========================================================================
class FxThreeArgForEachLoop : public FxExpression
{
public:
FName varVarName;
FName posVarName;
FName flagsVarName;
FxExpression* BlockIteratorExpr;
FxExpression* Code;
FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos);
~FxThreeArgForEachLoop();
FxExpression *Resolve(FCompileContext&);
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};
//==========================================================================
//
// FxTypedForEachLoop
//
//==========================================================================
class FxTypedForEachLoop : public FxExpression
{
public:
FName className;
FName varName;
FxExpression* Expr;
FxExpression* Code;
FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos);
~FxTypedForEachLoop();
FxExpression *Resolve(FCompileContext&);
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};
//==========================================================================
//
// FxJumpStatement

View file

@ -41,6 +41,9 @@
CVAR(Bool, strictdecorate, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)
EXTERN_CVAR(Bool, vm_jit)
EXTERN_CVAR(Bool, vm_jit_aot)
struct VMRemap
{
uint8_t altOp, kReg, kType;
@ -928,6 +931,13 @@ void FFunctionBuildList::Build()
disasmdump.Write(sfunc, item.PrintableName);
sfunc->Unsafe = ctx.Unsafe;
#if HAVE_VM_JIT
if(vm_jit && vm_jit_aot)
{
sfunc->JitCompile();
}
#endif
}
catch (CRecoverableError &err)
{
@ -1094,8 +1104,6 @@ void FunctionCallEmitter::AddParameterStringConst(const FString &konst)
});
}
EXTERN_CVAR(Bool, vm_jit)
ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray<ExpEmit> *ReturnRegs)
{
unsigned paramcount = 0;

View file

@ -147,6 +147,24 @@ VMFunction *FindVMFunction(PClass *cls, const char *name)
}
//==========================================================================
//
// Find an action function in AActor's table from a qualified name
// This cannot search in structs. sorry. :(
//
//==========================================================================
VMFunction* FindVMFunction( const char* name)
{
auto p = strchr(name, '.');
if (p == nullptr) return nullptr;
std::string clsname(name, p - name);
auto cls = PClass::FindClass(clsname.c_str());
if (cls == nullptr) return nullptr;
return FindVMFunction(cls, p + 1);
}
//==========================================================================
//
// Sorting helpers

View file

@ -42,6 +42,8 @@
#include "textureid.h"
#include "maps.h"
#include "palettecontainer.h"
#include "texturemanager.h"
#include "i_interface.h"
FTypeTable TypeTable;
@ -1659,7 +1661,8 @@ PClassPointer::PClassPointer(PClass *restrict)
loadOp = OP_LP;
storeOp = OP_SP;
Flags |= TYPE_ClassPointer;
mVersion = restrict->VMType->mVersion;
if (restrict) mVersion = restrict->VMType->mVersion;
else mVersion = 0;
}
//==========================================================================
@ -2549,9 +2552,63 @@ static void PMapValueWriter(FSerializer &ar, const M *map, const PMap *m)
}
else if constexpr(std::is_same_v<typename M::KeyType,uint32_t>)
{
FString key;
key.Format("%u",p->Key);
m->ValueType->WriteValue(ar,key.GetChars(),static_cast<const void *>(&p->Value));
if(m->KeyType->Flags & 8 /*TYPE_IntNotInt*/)
{
if(m->KeyType == TypeName)
{
m->ValueType->WriteValue(ar,FName(ENamedName(p->Key)).GetChars(),static_cast<const void *>(&p->Value));
}
else if(m->KeyType == TypeSound)
{
m->ValueType->WriteValue(ar,soundEngine->GetSoundName(FSoundID::fromInt(p->Key)),static_cast<const void *>(&p->Value));
}
else if(m->KeyType == TypeTextureID)
{
if(!!(p->Key & 0x8000000))
{ // invalid
m->ValueType->WriteValue(ar,"invalid",static_cast<const void *>(&p->Value));
}
else if(p->Key == 0 || p->Key >= TexMan.NumTextures())
{ // null
m->ValueType->WriteValue(ar,"null",static_cast<const void *>(&p->Value));
}
else
{
FTextureID tid;
tid.SetIndex(p->Key);
FGameTexture *tex = TexMan.GetGameTexture(tid);
int lump = tex->GetSourceLump();
unsigned useType = static_cast<unsigned>(tex->GetUseType());
FString name;
if (TexMan.GetLinkedTexture(lump) == tex)
{
name = fileSystem.GetFileFullName(lump);
}
else
{
name = tex->GetName().GetChars();
}
name.AppendFormat(":%u",useType);
m->ValueType->WriteValue(ar,name.GetChars(),static_cast<const void *>(&p->Value));
}
}
else
{ // bool/color/enum/sprite/translationID
FString key;
key.Format("%u",p->Key);
m->ValueType->WriteValue(ar,key.GetChars(),static_cast<const void *>(&p->Value));
}
}
else
{
FString key;
key.Format("%u",p->Key);
m->ValueType->WriteValue(ar,key.GetChars(),static_cast<const void *>(&p->Value));
}
}
//else unknown key type
}
@ -2584,20 +2641,85 @@ static bool PMapValueReader(FSerializer &ar, M *map, const PMap *m)
const char * k;
while((k = ar.GetKey()))
{
typename M::ValueType * val;
typename M::ValueType * val = nullptr;
if constexpr(std::is_same_v<typename M::KeyType,FString>)
{
val = &map->InsertNew(k);
}
else if constexpr(std::is_same_v<typename M::KeyType,uint32_t>)
{
FString s(k);
if(!s.IsInt())
if(m->KeyType->Flags & 8 /*TYPE_IntNotInt*/)
{
ar.EndObject();
return false;
if(m->KeyType == TypeName)
{
val = &map->InsertNew(FName(k).GetIndex());
}
else if(m->KeyType == TypeSound)
{
val = &map->InsertNew(S_FindSound(k).index());
}
else if(m->KeyType == TypeTextureID)
{
FString s(k);
FTextureID tex;
if(s.Compare("invalid") == 0)
{
tex.SetInvalid();
}
else if(s.Compare("null") == 0)
{
tex.SetNull();
}
else
{
ptrdiff_t sep = s.LastIndexOf(":");
if(sep < 0)
{
ar.EndObject();
return false;
}
FString texName = s.Left(sep);
FString useType = s.Mid(sep + 1);
tex = TexMan.GetTextureID(texName.GetChars(), (ETextureType) useType.ToULong());
}
val = &map->InsertNew(tex.GetIndex());
}
else if(m->KeyType == TypeTranslationID)
{
FString s(k);
if(!s.IsInt())
{
ar.EndObject();
return false;
}
int v = s.ToULong();
if (sysCallbacks.RemapTranslation) v = sysCallbacks.RemapTranslation(FTranslationID::fromInt(v)).index();
val = &map->InsertNew(v);
}
else
{ // bool/color/enum/sprite
FString s(k);
if(!s.IsInt())
{
ar.EndObject();
return false;
}
val = &map->InsertNew(static_cast<uint32_t>(s.ToULong()));
}
}
else
{
FString s(k);
if(!s.IsInt())
{
ar.EndObject();
return false;
}
val = &map->InsertNew(static_cast<uint32_t>(s.ToULong()));
}
val = &map->InsertNew(static_cast<uint32_t>(s.ToULong()));
}
if (!m->ValueType->ReadValue(ar,nullptr,static_cast<void*>(val)))
{

View file

@ -742,6 +742,7 @@ extern PPointer *TypeVoidPtr;
extern PPointer* TypeRawFunction;
extern PPointer* TypeVMFunction;
inline FString &DObject::StringVar(FName field)
{
return *(FString*)ScriptVar(field, TypeString);

View file

@ -983,6 +983,53 @@ static void PrintArrayIterationStmt(FLispString &out, const ZCC_TreeNode *node)
out.Close();
}
static void PrintTwoArgIterationStmt(FLispString &out, const ZCC_TreeNode *node)
{
auto inode = (ZCC_TwoArgIterationStmt *)node;
out.Break();
out.Open("map-iteration-stmt");
PrintVarName(out, inode->ItKey);
out.Break();
PrintVarName(out, inode->ItValue);
out.Break();
PrintNodes(out, inode->ItMap);
out.Break();
PrintNodes(out, inode->LoopStatement);
out.Close();
}
static void PrintThreeArgIterationStmt(FLispString &out, const ZCC_TreeNode *node)
{
auto inode = (ZCC_ThreeArgIterationStmt *)node;
out.Break();
out.Open("block-iteration-stmt");
PrintVarName(out, inode->ItVar);
out.Break();
PrintVarName(out, inode->ItPos);
out.Break();
PrintVarName(out, inode->ItFlags);
out.Break();
PrintNodes(out, inode->ItBlock);
out.Break();
PrintNodes(out, inode->LoopStatement);
out.Close();
}
static void PrintTypedIterationStmt(FLispString &out, const ZCC_TreeNode *node)
{
auto inode = (ZCC_TypedIterationStmt *)node;
out.Break();
out.Open("cast-iteration-stmt");
PrintVarName(out, inode->ItType);
out.Break();
PrintVarName(out, inode->ItVar);
out.Break();
PrintNodes(out, inode->ItExpr);
out.Break();
PrintNodes(out, inode->LoopStatement);
out.Close();
}
static const NodePrinterFunc TreeNodePrinter[] =
{
PrintIdentifier,
@ -1050,6 +1097,9 @@ static const NodePrinterFunc TreeNodePrinter[] =
PrintMixinDef,
PrintMixinStmt,
PrintArrayIterationStmt,
PrintTwoArgIterationStmt,
PrintThreeArgIterationStmt,
PrintTypedIterationStmt,
};
FString ZCC_PrintAST(const ZCC_TreeNode *root)

View file

@ -378,6 +378,15 @@ flag_def(X) ::= FLAGDEF(T) IDENTIFIER(A) COLON IDENTIFIER(B) COMMA INTCONST(C) S
X = def;
}
flag_def(X) ::= FLAGDEF(T) INTERNAL IDENTIFIER(A) COLON IDENTIFIER(B) COMMA INTCONST(C) SEMICOLON.
{
NEW_AST_NODE(FlagDef,def,T);
def->NodeName = A.Name();
def->RefName = B.Name();
def->BitValue = C.Int | 0x10000;
X = def;
}
identifier_list(X) ::= IDENTIFIER(A).
{
@ -437,6 +446,7 @@ struct_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ }
struct_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ }
struct_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ }
struct_member(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ }
struct_member(X) ::= flag_def(A). { X = A; /*X-overwrites-A*/ }
/*----- Constant Definition ------*/
/* Like UnrealScript, a constant's type is implied by its value's type. */
@ -1946,6 +1956,9 @@ statement(X) ::= expression_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/
statement(X) ::= selection_statement(X).
statement(X) ::= iteration_statement(X).
statement(X) ::= array_iteration_statement(X).
statement(X) ::= two_arg_iteration_statement(X).
statement(X) ::= three_arg_iteration_statement(X).
statement(X) ::= typed_iteration_statement(X).
statement(X) ::= jump_statement(X).
statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
statement(X) ::= assign_decl_statement(A) SEMICOLON.{ X = A; /*X-overwrites-A*/ }
@ -2115,6 +2128,43 @@ array_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(IN) COLON expr(
X = iter;
}
%type two_arg_iteration_statement{ZCC_Statement *}
two_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(KEY) COMMA variable_name(VAL) COLON expr(EX) RPAREN statement(ST).
{
NEW_AST_NODE(TwoArgIterationStmt, iter, T);
iter->ItKey = KEY;
iter->ItValue = VAL;
iter->ItMap = EX;
iter->LoopStatement = ST;
X = iter;
}
%type three_arg_iteration_statement{ZCC_Statement *}
three_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(VAR) COMMA variable_name(POS) COMMA variable_name(FLAGS) COLON expr(EX) RPAREN statement(ST).
{
NEW_AST_NODE(ThreeArgIterationStmt, iter, T);
iter->ItVar = VAR;
iter->ItPos = POS;
iter->ItFlags = FLAGS;
iter->ItBlock = EX;
iter->LoopStatement = ST;
X = iter;
}
%type typed_iteration_statement{ZCC_Statement *}
typed_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(TYPE) variable_name(VAR) COLON expr(EX) RPAREN statement(ST).
{
NEW_AST_NODE(TypedIterationStmt, iter, T);
iter->ItType = TYPE;
iter->ItVar = VAR;
iter->ItExpr = EX;
iter->LoopStatement = ST;
X = iter;
}
while_or_until(X) ::= WHILE(T).
{
X.Int = ZCC_WHILE;

View file

@ -57,6 +57,13 @@ double GetFloatConst(FxExpression *ex, FCompileContext &ctx)
return ex ? static_cast<FxConstant*>(ex)->GetValue().GetFloat() : 0;
}
VMFunction* GetFuncConst(FxExpression* ex, FCompileContext& ctx)
{
ex = new FxTypeCast(ex, TypeVMFunction, false);
ex = ex->Resolve(ctx);
return static_cast<VMFunction*>(ex ? static_cast<FxConstant*>(ex)->GetValue().GetPointer() : nullptr);
}
const char * ZCCCompiler::GetStringConst(FxExpression *ex, FCompileContext &ctx)
{
ex = new FxStringCast(ex);
@ -452,6 +459,11 @@ void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZC
}
break;
case AST_FlagDef:
cls->FlagDefs.Push(static_cast<ZCC_FlagDef*>(node));
break;
default:
assert(0 && "Unhandled AST node type");
break;
@ -2987,12 +2999,12 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
{
case AST_ExprID:
// The function name is a simple identifier.
return new FxFunctionCall(static_cast<ZCC_ExprID *>(fcall->Function)->Identifier, NAME_None, ConvertNodeList(args, fcall->Parameters), *ast);
return new FxFunctionCall(static_cast<ZCC_ExprID *>(fcall->Function)->Identifier, NAME_None, std::move(ConvertNodeList(args, fcall->Parameters)), *ast);
case AST_ExprMemberAccess:
{
auto ema = static_cast<ZCC_ExprMemberAccess *>(fcall->Function);
return new FxMemberFunctionCall(ConvertNode(ema->Left, true), ema->Right, ConvertNodeList(args, fcall->Parameters), *ast);
return new FxMemberFunctionCall(ConvertNode(ema->Left, true), ema->Right, std::move(ConvertNodeList(args, fcall->Parameters)), *ast);
}
case AST_ExprBinary:
@ -3002,7 +3014,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
auto binary = static_cast<ZCC_ExprBinary *>(fcall->Function);
if (binary->Left->NodeType == AST_ExprID && binary->Right->NodeType == AST_ExprID)
{
return new FxFunctionCall(static_cast<ZCC_ExprID *>(binary->Left)->Identifier, static_cast<ZCC_ExprID *>(binary->Right)->Identifier, ConvertNodeList(args, fcall->Parameters), *ast);
return new FxFunctionCall(static_cast<ZCC_ExprID *>(binary->Left)->Identifier, static_cast<ZCC_ExprID *>(binary->Right)->Identifier, std::move(ConvertNodeList(args, fcall->Parameters)), *ast);
}
}
// fall through if this isn't an array access node.
@ -3376,10 +3388,45 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
auto iter = static_cast<ZCC_ArrayIterationStmt*>(ast);
auto var = iter->ItName->Name;
FxExpression* const itArray = ConvertNode(iter->ItArray);
FxExpression* const itArray2 = ConvertNode(iter->ItArray); // the handler needs two copies of this - here's the easiest place to create them.
FxExpression* const itArray2 = ConvertNode(iter->ItArray);
FxExpression* const itArray3 = ConvertNode(iter->ItArray);
FxExpression* const itArray4 = ConvertNode(iter->ItArray); // the handler needs copies of this - here's the easiest place to create them.
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
return new FxForEachLoop(iter->ItName->Name, itArray, itArray2, body, *ast);
return new FxForEachLoop(iter->ItName->Name, itArray, itArray2, itArray3, itArray4, body, *ast);
}
case AST_TwoArgIterationStmt:
{
auto iter = static_cast<ZCC_TwoArgIterationStmt*>(ast);
auto key = iter->ItKey->Name;
auto var = iter->ItValue->Name;
FxExpression* const itMap = ConvertNode(iter->ItMap);
FxExpression* const itMap2 = ConvertNode(iter->ItMap);
FxExpression* const itMap3 = ConvertNode(iter->ItMap);
FxExpression* const itMap4 = ConvertNode(iter->ItMap);
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
return new FxTwoArgForEachLoop(key, var, itMap, itMap2, itMap3, itMap4, body, *ast);
}
case AST_ThreeArgIterationStmt:
{
auto iter = static_cast<ZCC_ThreeArgIterationStmt*>(ast);
auto var = iter->ItVar->Name;
auto pos = iter->ItPos->Name;
auto flags = iter->ItFlags->Name;
FxExpression* const itBlock = ConvertNode(iter->ItBlock);
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
return new FxThreeArgForEachLoop(var, pos, flags, itBlock, body, *ast);
}
case AST_TypedIterationStmt:
{
auto iter = static_cast<ZCC_TypedIterationStmt*>(ast);
auto cls = iter->ItType->Name;
auto var = iter->ItVar->Name;
FxExpression* const itExpr = ConvertNode(iter->ItExpr);
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
return new FxTypedForEachLoop(cls, var, itExpr, body, *ast);
}
case AST_IterationStmt:

View file

@ -6,7 +6,6 @@
struct Baggage;
struct FPropertyInfo;
class AActor;
class FxExpression;
typedef TDeletingArray<FxExpression*> FArgumentList;
@ -23,6 +22,7 @@ struct ZCC_StructWork
TArray<ZCC_VarDeclarator *> Fields;
TArray<ZCC_FuncDeclarator *> Functions;
TArray<ZCC_StaticArrayStatement *> Arrays;
TArray<ZCC_FlagDef*> FlagDefs;
ZCC_StructWork()
{

View file

@ -1177,6 +1177,46 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c
break;
}
case AST_TwoArgIterationStmt:
{
TreeNodeDeepCopy_Start(TwoArgIterationStmt);
// ZCC_TwoArgIterationStmt
copy->ItKey = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItKey, true, copiedNodesList));
copy->ItValue = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItValue, true, copiedNodesList));
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
copy->ItMap = static_cast<ZCC_Expression*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItMap, true, copiedNodesList));
break;
}
case AST_ThreeArgIterationStmt:
{
TreeNodeDeepCopy_Start(ThreeArgIterationStmt);
// ZCC_TwoArgIterationStmt
copy->ItVar = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList));
copy->ItPos = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItPos, true, copiedNodesList));
copy->ItFlags = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItFlags, true, copiedNodesList));
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
copy->ItBlock = static_cast<ZCC_Expression*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItBlock, true, copiedNodesList));
break;
}
case AST_TypedIterationStmt:
{
TreeNodeDeepCopy_Start(TypedIterationStmt);
// ZCC_TwoArgIterationStmt
copy->ItType = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItType, true, copiedNodesList));
copy->ItVar = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList));
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
copy->ItExpr = static_cast<ZCC_Expression*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItExpr, true, copiedNodesList));
break;
}
case AST_IfStmt:
{
TreeNodeDeepCopy_Start(IfStmt);

View file

@ -145,6 +145,9 @@ enum EZCCTreeNodeType
AST_MixinDef,
AST_MixinStmt,
AST_ArrayIterationStmt,
AST_TwoArgIterationStmt,
AST_ThreeArgIterationStmt,
AST_TypedIterationStmt,
NUM_AST_NODE_TYPES
};
@ -532,6 +535,31 @@ struct ZCC_ArrayIterationStmt : ZCC_Statement
ZCC_Statement* LoopStatement;
};
struct ZCC_TwoArgIterationStmt : ZCC_Statement
{
ZCC_VarName* ItKey;
ZCC_VarName* ItValue;
ZCC_Expression* ItMap;
ZCC_Statement* LoopStatement;
};
struct ZCC_ThreeArgIterationStmt : ZCC_Statement
{
ZCC_VarName* ItVar;
ZCC_VarName* ItPos;
ZCC_VarName* ItFlags;
ZCC_Expression* ItBlock;
ZCC_Statement* LoopStatement;
};
struct ZCC_TypedIterationStmt : ZCC_Statement
{
ZCC_VarName* ItType;
ZCC_VarName* ItVar;
ZCC_Expression* ItExpr;
ZCC_Statement* LoopStatement;
};
struct ZCC_IfStmt : ZCC_Statement
{
ZCC_Expression *Condition;

View file

@ -724,6 +724,11 @@ struct AFuncDesc
extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \
MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname;
#define DEFINE_FIELD_NAMED_UNSIZED(cls, name, scriptname) \
static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), ~0u, 0 }; \
extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \
MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname;
#define DEFINE_FIELD_BIT(cls, name, scriptname, bitval) \
static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), bitval }; \
extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \
@ -792,6 +797,7 @@ class AActor;
class PFunction;
VMFunction *FindVMFunction(PClass *cls, const char *name);
VMFunction* FindVMFunction(const char* name);
#define DECLARE_VMFUNC(cls, name) static VMFunction *name; if (name == nullptr) name = FindVMFunction(RUNTIME_CLASS(cls), #name);
FString FStringFormat(VM_ARGS, int offset = 0);

View file

@ -54,8 +54,14 @@ CUSTOM_CVAR(Bool, vm_jit, true, CVAR_NOINITCALL)
Printf("You must restart " GAMENAME " for this change to take effect.\n");
Printf("This cvar is currently not saved. You must specify it on the command line.");
}
CUSTOM_CVAR(Bool, vm_jit_aot, true, CVAR_NOINITCALL)
{
Printf("You must restart " GAMENAME " for this change to take effect.\n");
Printf("This cvar is currently not saved. You must specify it on the command line.");
}
#else
CVAR(Bool, vm_jit, false, CVAR_NOINITCALL|CVAR_NOSET)
CVAR(Bool, vm_jit_aot, false, CVAR_NOINITCALL|CVAR_NOSET)
FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames, int maxFrames) { return FString(); }
void JitRelease() {}
#endif
@ -282,6 +288,25 @@ static bool CanJit(VMScriptFunction *func)
return false;
}
void VMScriptFunction::JitCompile()
{
if(!(VarFlags & VARF_Abstract))
{
#ifdef HAVE_VM_JIT
if (vm_jit && CanJit(this))
{
ScriptCall = ::JitCompile(this);
if (!ScriptCall)
ScriptCall = VMExec;
}
else
#endif // HAVE_VM_JIT
{
ScriptCall = VMExec;
}
}
}
int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret)
{
// [Player701] Check that we aren't trying to call an abstract function.
@ -291,18 +316,8 @@ int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int num
{
ThrowAbortException(X_OTHER, "attempt to call abstract function %s.", func->PrintableName);
}
#ifdef HAVE_VM_JIT
if (vm_jit && CanJit(static_cast<VMScriptFunction*>(func)))
{
func->ScriptCall = JitCompile(static_cast<VMScriptFunction*>(func));
if (!func->ScriptCall)
func->ScriptCall = VMExec;
}
else
#endif // HAVE_VM_JIT
{
func->ScriptCall = VMExec;
}
static_cast<VMScriptFunction*>(func)->JitCompile();
return func->ScriptCall(func, params, numparams, ret, numret);
}

View file

@ -481,4 +481,6 @@ public:
private:
static int FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret);
void JitCompile();
friend class FFunctionBuildList;
};