diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd01cad42..b612684d5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -815,11 +815,15 @@ file( GLOB HEADER_FILES posix/cocoa/*.h posix/sdl/*.h r_data/*.h + rapidjson/*.h resourcefiles/*.h sfmt/*.h sound/*.h textures/*.h scripting/*.h + scripting/codegeneration/*.h + scripting/decorate/*.h + scripting/zscript/*.h scripting/vm/*.h xlat/*.h *.h diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index d5150e985..8e69ecb06 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -820,7 +820,8 @@ void SetDehParams(FState *state, int codepointer) int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2); buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation, ATAG_OBJECT), NAP + argcount, 0); // Attach it to the state. - VMScriptFunction *sfunc = buildit.MakeFunction(); + VMScriptFunction *sfunc = new VMScriptFunction; + buildit.MakeFunction(sfunc); sfunc->NumArgs = NAP; state->SetAction(sfunc); } diff --git a/src/scripting/codegeneration/thingdef_exp.h b/src/scripting/codegeneration/thingdef_exp.h index 65c3ace63..2e9af65b6 100644 --- a/src/scripting/codegeneration/thingdef_exp.h +++ b/src/scripting/codegeneration/thingdef_exp.h @@ -41,6 +41,9 @@ */ #include "m_random.h" +#include "sc_man.h" +#include "s_sound.h" +#include "actor.h" #define CHECKRESOLVED() if (isresolved) return this; isresolved=true; @@ -58,14 +61,15 @@ class FxJumpStatement; // // //========================================================================== +struct FScriptPosition; struct FCompileContext { TArray Jumps; PPrototype *ReturnProto; - PClassActor *Class; + PClass *Class; - FCompileContext(PClassActor *cls = nullptr, PPrototype *ret = nullptr); + FCompileContext(PClass *cls = nullptr, PPrototype *ret = nullptr); PSymbol *FindInClass(FName identifier); PSymbol *FindGlobal(FName identifier); @@ -1175,7 +1179,6 @@ public: class FxDamageValue : public FxExpression { FxExpression *val; - VMScriptFunction *MyFunction; public: @@ -1184,8 +1187,6 @@ public: FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); - VMScriptFunction *GetFunction() const { return MyFunction; } - void SetFunction(VMScriptFunction *func) { MyFunction = func; } }; //========================================================================== diff --git a/src/scripting/codegeneration/thingdef_expression.cpp b/src/scripting/codegeneration/thingdef_expression.cpp index ae2639b73..31acc391e 100644 --- a/src/scripting/codegeneration/thingdef_expression.cpp +++ b/src/scripting/codegeneration/thingdef_expression.cpp @@ -91,7 +91,7 @@ static const FLOP FxFlops[] = // //========================================================================== -FCompileContext::FCompileContext(PClassActor *cls, PPrototype *ret) : Class(cls), ReturnProto(ret) +FCompileContext::FCompileContext(PClass *cls, PPrototype *ret) : Class(cls), ReturnProto(ret) { } @@ -3902,7 +3902,7 @@ VMFunction *FxVMFunctionCall::GetDirectFunction() // then it can be a "direct" function. That is, the DECORATE // definition can call that function directly without wrapping // it inside VM code. - if (EmitTail && (ArgList ? ArgList->Size() : 0) == 0 && (Function->Flags & VARF_Action)) + if ((ArgList ? ArgList->Size() : 0) == 0 && (Function->Flags & VARF_Action)) { return Function->Variants[0].Implementation; } @@ -4922,20 +4922,19 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); ABORT(ctx.Class); + auto aclass = dyn_cast(ctx.Class); - if (ctx.Class->NumOwnedStates == 0) - { - // This can't really happen - assert(false); - } - if (ctx.Class->NumOwnedStates <= index) + // This expression type can only be used from DECORATE, so there's no need to consider the possibility of calling it from a non-actor. + assert(aclass != nullptr && aclass->NumOwnedStates > 0); + + if (aclass->NumOwnedStates <= index) { ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", ctx.Class->TypeName.GetChars(), index); delete this; return NULL; } - FxExpression *x = new FxConstant(ctx.Class->OwnedStates + index, ScriptPosition); + FxExpression *x = new FxConstant(aclass->OwnedStates + index, ScriptPosition); delete this; return x; } @@ -5245,7 +5244,6 @@ FxDamageValue::FxDamageValue(FxExpression *v) { val = v; ValueType = TypeVoid; - MyFunction = NULL; } FxDamageValue::~FxDamageValue() diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 186b269ce..a863c4a4e 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -441,42 +441,6 @@ static void ParseArgListDef(FScanner &sc, PClassActor *cls, sc.MustGetToken(';'); } -//========================================================================== -// -// SetImplicitArgs -// -// Adds the parameters implied by the function flags. -// -//========================================================================== - -void SetImplicitArgs(TArray *args, TArray *argflags, PClass *cls, DWORD funcflags) -{ - // Must be called before adding any other arguments. - assert(args == NULL || args->Size() == 0); - assert(argflags == NULL || argflags->Size() == 0); - - if (funcflags & VARF_Method) - { - // implied self pointer - if (args != NULL) args->Push(NewClassPointer(RUNTIME_CLASS(AActor))); - if (argflags != NULL) argflags->Push(VARF_Implicit); - } - if (funcflags & VARF_Action) - { - // implied stateowner and callingstate pointers - if (args != NULL) - { - args->Push(NewClassPointer(cls)); - args->Push(TypeState); - } - if (argflags != NULL) - { - argflags->Push(VARF_Implicit); - argflags->Push(VARF_Implicit); - } - } -} - //========================================================================== // // ParseFunctionDef @@ -1559,3 +1523,14 @@ void ParseDecorate (FScanner &sc) } } } + +void ParseAllDecorate() +{ + int lastlump, lump; + + while ((lump = Wads.FindLump("DECORATE", &lastlump)) != -1) + { + FScanner sc(lump); + ParseDecorate(sc); + } +} \ No newline at end of file diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 59d620b2a..143144aa5 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -57,8 +57,7 @@ #include "codegeneration/thingdef_exp.h" #include "version.h" #include "templates.h" - -TDeletingArray StateTempCalls; +#include "vmbuilder.h" //========================================================================== //*** @@ -141,13 +140,14 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage & FString statestring; FState state; char lastsprite[5] = ""; - FStateTempCall *tcall = NULL; - FArgumentList *args = NULL; + FxExpression *ScriptCode; + FArgumentList *args = nullptr; sc.MustGetStringName ("{"); sc.SetEscape(false); // disable escape sequences in the state parser while (!sc.CheckString ("}") && !sc.End) { + ScriptCode = nullptr; memset(&state,0,sizeof(state)); statestring = ParseStateString(sc); if (!statestring.CompareNoCase("GOTO")) @@ -224,10 +224,6 @@ do_stop: sc.MustGetString(); statestring = sc.String; - if (tcall == NULL) - { - tcall = new FStateTempCall; - } if (sc.CheckString("RANDOM")) { int min, max; @@ -315,35 +311,27 @@ do_stop: } bool hasfinalret; - tcall->Code = ParseActions(sc, state, statestring, bag, hasfinalret); - if (!hasfinalret && tcall->Code != nullptr) + ScriptCode = ParseActions(sc, state, statestring, bag, hasfinalret); + if (!hasfinalret && ScriptCode != nullptr) { - static_cast(tcall->Code)->Add(new FxReturnStatement(nullptr, sc)); + static_cast(ScriptCode)->Add(new FxReturnStatement(nullptr, sc)); } goto endofstate; } sc.UnGet(); endofstate: + if (ScriptCode != nullptr) + { + state.ActionFunc = FunctionBuildList.AddFunction(actor, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true); + } int count = bag.statedef.AddStates(&state, statestring); if (count < 0) { - sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars()); + sc.ScriptError("Invalid frame character string '%s'", statestring.GetChars()); count = -count; } - if (tcall->Code != NULL) - { - tcall->ActorClass = actor; - tcall->FirstState = bag.statedef.GetStateCount() - count; - tcall->NumStates = count; - StateTempCalls.Push(tcall); - tcall = NULL; - } } } - if (tcall != NULL) - { - delete tcall; - } if (args != NULL) { delete args; diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 5227009e7..1a761b8c2 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -66,174 +66,48 @@ #include "vmbuilder.h" #include "stats.h" -TDeletingArray ActorDamageFuncs; - - // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void InitThingdef(); -void ParseDecorate(FScanner &ctx); // STATIC FUNCTION PROTOTYPES -------------------------------------------- PClassActor *QuestItemClasses[31]; //========================================================================== // -// Do some postprocessing after everything has been defined +// SetImplicitArgs +// +// Adds the parameters implied by the function flags. // //========================================================================== -static void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, int labellen) +void SetImplicitArgs(TArray *args, TArray *argflags, PClass *cls, DWORD funcflags) { - const char *marks = "======================================================="; - fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); - fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", - sfunc->NumRegD, sfunc->NumRegF, sfunc->NumRegA, sfunc->NumRegS, sfunc->MaxParam); - VMDumpConstants(dump, sfunc); - fprintf(dump, "\nDisassembly @ %p:\n", sfunc->Code); - VMDisasm(dump, sfunc->Code, sfunc->CodeSize, sfunc); + // Must be called before adding any other arguments. + assert(args == NULL || args->Size() == 0); + assert(argflags == NULL || argflags->Size() == 0); + + if (funcflags & VARF_Method) + { + // implied self pointer + if (args != NULL) args->Push(NewClassPointer(cls)); + if (argflags != NULL) argflags->Push(VARF_Implicit); + } + if (funcflags & VARF_Action) + { + // implied caller and callingstate pointers + if (args != NULL) + { + args->Insert(0, NewClassPointer(RUNTIME_CLASS(AActor))); // the caller must go before self due to an old design mistake. + args->Push(TypeState); + } + if (argflags != NULL) + { + argflags->Push(VARF_Implicit); + argflags->Push(VARF_Implicit); + } + } } -static void FinishThingdef() -{ - int errorcount = 0; - unsigned i; - int codesize = 0; - FILE *dump = NULL; - - if (Args->CheckParm("-dumpdisasm")) dump = fopen("disasm.txt", "w"); - - for (i = 0; i < StateTempCalls.Size(); ++i) - { - FStateTempCall *tcall = StateTempCalls[i]; - VMFunction *func = nullptr; - - assert(tcall->Code != NULL); - - // We don't know the return type in advance for anonymous functions. - FCompileContext ctx(tcall->ActorClass, nullptr); - tcall->Code = tcall->Code->Resolve(ctx); - tcall->Proto = ctx.ReturnProto; - - // Make sure resolving it didn't obliterate it. - if (tcall->Code != nullptr) - { - // Can we call this function directly without wrapping it in an - // anonymous function? e.g. Are we passing any parameters to it? - func = tcall->Code->GetDirectFunction(); - - if (func == nullptr) - { - VMFunctionBuilder buildit(true); - - assert(tcall->Proto != nullptr); - - // Allocate registers used to pass parameters in. - // self, stateowner, state (all are pointers) - buildit.Registers[REGT_POINTER].Get(3); - - // Emit code - tcall->Code->Emit(&buildit); - - VMScriptFunction *sfunc = buildit.MakeFunction(); - sfunc->NumArgs = NAP; - - // Generate prototype for this anonymous function - TArray args(3); - SetImplicitArgs(&args, NULL, tcall->ActorClass, VARF_Method | VARF_Action); - sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args); - - func = sfunc; - - if (dump != NULL) - { - char label[64]; - int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", - tcall->ActorClass->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); - DumpFunction(dump, sfunc, label, labellen); - codesize += sfunc->CodeSize; - } - } - - delete tcall->Code; - tcall->Code = nullptr; - for (int k = 0; k < tcall->NumStates; ++k) - { - tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); - } - } - } - - for (i = 0; i < PClassActor::AllActorClasses.Size(); i++) - { - PClassActor *ti = PClassActor::AllActorClasses[i]; - - if (ti->Size == TentativeClass) - { - Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); - errorcount++; - continue; - } - - AActor *def = GetDefaultByType(ti); - - if (!def) - { - Printf(TEXTCOLOR_RED "No ActorInfo defined for class '%s'\n", ti->TypeName.GetChars()); - errorcount++; - continue; - } - - if (def->DamageFunc != nullptr) - { - FxDamageValue *dmg = (FxDamageValue *)ActorDamageFuncs[(uintptr_t)def->DamageFunc - 1]; - VMScriptFunction *sfunc; - sfunc = dmg->GetFunction(); - if (sfunc == nullptr) - { - FCompileContext ctx(ti); - dmg = static_cast(dmg->Resolve(ctx)); - - if (dmg != nullptr) - { - VMFunctionBuilder buildit; - buildit.Registers[REGT_POINTER].Get(1); // The self pointer - dmg->Emit(&buildit); - sfunc = buildit.MakeFunction(); - sfunc->NumArgs = 1; - sfunc->Proto = nullptr; ///FIXME: Need a proper prototype here - // Save this function in case this damage value was reused - // (which happens quite easily with inheritance). - dmg->SetFunction(sfunc); - } - } - def->DamageFunc = sfunc; - - if (dump != nullptr && sfunc != nullptr) - { - char label[64]; - int labellen = mysnprintf(label, countof(label), "Function %s.Damage", - ti->TypeName.GetChars()); - DumpFunction(dump, sfunc, label, labellen); - codesize += sfunc->CodeSize; - } - } - } - if (dump != NULL) - { - fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); - fclose(dump); - } - if (errorcount > 0) - { - I_Error("%d errors during actor postprocessing", errorcount); - } - - ActorDamageFuncs.DeleteAndClear(); - StateTempCalls.DeleteAndClear(); -} - - - //========================================================================== // // LoadActors @@ -242,29 +116,48 @@ static void FinishThingdef() // //========================================================================== void ParseScripts(); +void ParseAllDecorate(); void LoadActors () { - int lastlump, lump; cycle_t timer; timer.Reset(); timer.Clock(); - ActorDamageFuncs.Clear(); - InitThingdef(); - lastlump = 0; - ParseScripts(); - FScriptPosition::ResetErrorCounter(); - while ((lump = Wads.FindLump ("DECORATE", &lastlump)) != -1) - { - FScanner sc(lump); - ParseDecorate (sc); - } - FinishThingdef(); + + InitThingdef(); + ParseScripts(); + ParseAllDecorate(); + + FunctionBuildList.Build(); + if (FScriptPosition::ErrorCounter > 0) { I_Error("%d errors while parsing DECORATE scripts", FScriptPosition::ErrorCounter); } + + int errorcount = 0; + for (auto ti : PClassActor::AllActorClasses) + { + if (ti->Size == TentativeClass) + { + Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); + errorcount++; + continue; + } + + if (GetDefaultByType(ti) == nullptr) + { + Printf(TEXTCOLOR_RED "No ActorInfo defined for class '%s'\n", ti->TypeName.GetChars()); + errorcount++; + continue; + } + } + if (errorcount > 0) + { + I_Error("%d errors during actor postprocessing", errorcount); + } + timer.Unclock(); if (!batchrun) Printf("DECORATE parsing took %.2f ms\n", timer.TimeMS()); // Base time: ~52 ms diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 714657d24..4a984dd5c 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -101,25 +101,6 @@ public: int GetStateCount() const { return StateArray.Size(); } }; -//========================================================================== -// -// -// -//========================================================================== - -struct FStateTempCall -{ - FStateTempCall() : ActorClass(NULL), Code(NULL), FirstState(0), NumStates(0) {} - - PClassActor *ActorClass; - class FxExpression *Code; - class PPrototype *Proto; - int FirstState; - int NumStates; -}; -extern TDeletingArray StateTempCalls; -extern TDeletingArray ActorDamageFuncs; - //========================================================================== // // Extra info maintained while defining an actor. diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 3c171be7f..084736c24 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -69,6 +69,7 @@ #include "teaminfo.h" #include "v_video.h" #include "r_data/colormaps.h" +#include "vmbuilder.h" //========================================================================== @@ -656,7 +657,7 @@ DEFINE_PROPERTY(damage, X, Actor) } else { - defaults->DamageFunc = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(id) + 1); + defaults->DamageFunc = FunctionBuildList.AddFunction(bag.Info, id, FStringf("%s.DamageFunction", bag.Info->TypeName.GetChars()), false); } } diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 28b555e4e..69e5b81b3 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1020,4 +1020,5 @@ class PFunction; PFunction *FindGlobalActionFunction(const char *name); + #endif diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index fd9a0063e..4a880cef6 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -32,6 +32,10 @@ */ #include "vmbuilder.h" +#include "codegeneration/thingdef_exp.h" +#include "info.h" +#include "m_argv.h" +#include "thingdef.h" //========================================================================== // @@ -68,10 +72,8 @@ VMFunctionBuilder::~VMFunctionBuilder() // //========================================================================== -VMScriptFunction *VMFunctionBuilder::MakeFunction() +void VMFunctionBuilder::MakeFunction(VMScriptFunction *func) { - VMScriptFunction *func = new VMScriptFunction; - func->Alloc(Code.Size(), NumIntConstants, NumFloatConstants, NumStringConstants, NumAddressConstants); // Copy code block. @@ -106,8 +108,6 @@ VMScriptFunction *VMFunctionBuilder::MakeFunction() // entries on the parameter stack, but it means the caller probably // did something wrong. assert(ActiveParam == 0); - - return func; } //========================================================================== @@ -634,3 +634,113 @@ void VMFunctionBuilder::BackpatchToHere(size_t loc) { Backpatch(loc, Code.Size()); } + +//========================================================================== +// +// FFunctionBuildList +// +// This list contains all functions yet to build. +// All adding functions return a VMFunction - either a complete one +// for native functions or an empty VMScriptFunction for scripted ones +// This VMScriptFunction object later gets filled in with the actual +// info, but we get the pointer right after registering the function +// with the builder. +// +//========================================================================== +FFunctionBuildList FunctionBuildList; + +VMFunction *FFunctionBuildList::AddFunction(PClass *cls, FxExpression *code, const FString &name, bool statecall) +{ + auto func = code->GetDirectFunction(); + if (func != nullptr) + { + delete code; + return func; + } + + Printf("Adding %s\n", name.GetChars()); + + Item it; + it.Class = cls; + it.Code = code; + it.DumpName = name; + it.Function = new VMScriptFunction; + it.Proto = nullptr; + it.type = statecall; + mItems.Push(it); + return it.Function; +} + + +void FFunctionBuildList::Build() +{ + int errorcount = 0; + int codesize = 0; + FILE *dump = nullptr; + + if (Args->CheckParm("-dumpdisasm")) dump = fopen("disasm.txt", "w"); + + for (auto &item : mItems) + { + assert(item.Code != NULL); + + // We don't know the return type in advance for anonymous functions. + FCompileContext ctx(item.Class, nullptr); + item.Code = item.Code->Resolve(ctx); + item.Proto = ctx.ReturnProto; + + // Make sure resolving it didn't obliterate it. + if (item.Code != nullptr) + { + VMFunctionBuilder buildit(true); + + assert(item.Proto != nullptr); + + int numargs; + int flags; + + // Kludge alert. This needs to be done in a more universal fashion. + // Right now there's only action and damage functions, so for the time being + // this will do to get the whole thing started first. + + if (item.type == 1) // anonymous action function + { + numargs = NAP; + flags = VARF_Method | VARF_Action; + } + else + { + numargs = 1; + flags = VARF_Method; + } + + // Generate prototype for this anonymous function + buildit.Registers[REGT_POINTER].Get(numargs); + TArray args(numargs); + SetImplicitArgs(&args, nullptr, item.Class, flags); + + VMScriptFunction *sfunc = item.Function; + item.Function->Proto = NewPrototype(item.Proto->ReturnTypes, args); + + // Emit code + item.Code->Emit(&buildit); + buildit.MakeFunction(item.Function); + item.Function->NumArgs = numargs; + + if (dump != nullptr) + { + char label[64]; + int labellen = mysnprintf(label, countof(label), item.DumpName, + item.Class->TypeName.GetChars()); + DumpFunction(dump, sfunc, label, labellen); + codesize += sfunc->CodeSize; + } + } + delete item.Code; + } + if (dump != nullptr) + { + fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); + fclose(dump); + } +} \ No newline at end of file diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index ed2516c2a..59e9fbe79 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -26,7 +26,7 @@ public: VMFunctionBuilder(bool checkself = false); ~VMFunctionBuilder(); - VMScriptFunction *MakeFunction(); + void MakeFunction(VMScriptFunction *func); // Returns the constant register holding the value. int GetConstantInt(int val); @@ -87,4 +87,34 @@ private: }; +void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, int labellen); + + +//========================================================================== +// +// +// +//========================================================================== +class FxExpression; + +class FFunctionBuildList +{ + struct Item + { + PClass *Class = nullptr; + FxExpression *Code = nullptr; + PPrototype *Proto = nullptr; + VMScriptFunction *Function = nullptr; + FString DumpName; + int type; // temporary kludge + }; + + TArray mItems; + +public: + VMFunction *AddFunction(PClass *cls, FxExpression *code, const FString &name, bool statecall = false); + void Build(); +}; + +extern FFunctionBuildList FunctionBuildList; #endif diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 68b92f9f3..0b84cf8c0 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -33,6 +33,7 @@ #include "vm.h" #include "c_console.h" +#include "templates.h" #define NOP MODE_AUNUSED | MODE_BUNUSED | MODE_CUNUSED @@ -598,3 +599,21 @@ static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const } return col; } + +//========================================================================== +// +// Do some postprocessing after everything has been defined +// +//========================================================================== + +void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, int labellen) +{ + const char *marks = "======================================================="; + fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); + fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", + sfunc->NumRegD, sfunc->NumRegF, sfunc->NumRegA, sfunc->NumRegS, sfunc->MaxParam); + VMDumpConstants(dump, sfunc); + fprintf(dump, "\nDisassembly @ %p:\n", sfunc->Code); + VMDisasm(dump, sfunc->Code, sfunc->CodeSize, sfunc); +} + diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index e8ea8a6e7..d175bd917 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -47,6 +47,7 @@ #include "p_lnspec.h" #include "gdtoa.h" #include "codegeneration/thingdef_exp.h" +#include "vmbuilder.h" #define DEFINING_CONST ((PSymbolConst *)(void *)1) @@ -2165,12 +2166,7 @@ void ZCCCompiler::CompileStates() auto code = SetupActionFunction(static_cast(c->Type()), sl->Action); if (code != nullptr) { - auto tcall = new FStateTempCall; - tcall->Code = code; - tcall->ActorClass = static_cast(c->Type()); - tcall->FirstState = statedef.GetStateCount() - count; - tcall->NumStates = count; - StateTempCalls.Push(tcall); + state.ActionFunc = FunctionBuildList.AddFunction(c->Type(), code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), true); } } break; diff --git a/src/zstring.cpp b/src/zstring.cpp index f4a3a1fbb..3794a472a 100644 --- a/src/zstring.cpp +++ b/src/zstring.cpp @@ -1192,3 +1192,11 @@ FStringData *FStringData::MakeCopy () FString::StrCopy (copy->Chars(), Chars(), Len); return copy; } + +FStringf::FStringf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + VFormat(fmt, ap); + va_end(ap); +} diff --git a/src/zstring.h b/src/zstring.h index 00f373b59..519b354bf 100644 --- a/src/zstring.h +++ b/src/zstring.h @@ -308,6 +308,13 @@ private: bool operator >= (const FString &illegal) const; }; +class FStringf : public FString +{ +public: + FStringf(const char *fmt, ...); +}; + + namespace StringFormat { enum