From a981737855bff7fc62c2aa1cc40a621f496a4bfc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 18 Nov 2018 17:10:55 +0100 Subject: [PATCH] - generate register type info for the parameter lists of all functions. Currently used for loading parameters into registers. For checking parameters of native functions some more work is needed to get the info to the function. Currently it doesn't receive the function descriptor. --- src/d_dehacked.cpp | 2 ++ src/events.cpp | 4 +++- src/p_mobj.cpp | 15 ------------ src/p_sectors.cpp | 7 ------ src/scripting/backend/codegen.cpp | 27 ++++++++++++++-------- src/scripting/backend/vmbuilder.cpp | 1 + src/scripting/thingdef_data.cpp | 7 ++---- src/scripting/vm/vm.h | 11 ++++++++- src/scripting/vm/vmexec.cpp | 19 ++++++++------- src/scripting/vm/vmframe.cpp | 36 +++++++++++++++++++++++++++++ wadsrc/static/zscript/mapdata.txt | 1 + 11 files changed, 84 insertions(+), 46 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 44e675ed28..89ac12401c 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -749,6 +749,7 @@ static void (*MBFCodePointerFactories[])(FunctionCallEmitter&, int, int) = void SetDehParams(FState *state, int codepointer) { + static uint8_t regts[] = { REGT_POINTER, REGT_POINTER, REGT_POINTER }; int value1 = state->GetMisc1(); int value2 = state->GetMisc2(); if (!(value1|value2)) return; @@ -788,6 +789,7 @@ void SetDehParams(FState *state, int codepointer) buildit.Emit(OP_RET, RET_FINAL, REGT_NIL, 0); // Attach it to the state. VMScriptFunction *sfunc = new VMScriptFunction; + sfunc->RegTypes = regts; // These functions are built after running the script compiler so they don't get this info. buildit.MakeFunction(sfunc); sfunc->NumArgs = numargs; sfunc->ImplicitArgs = numargs; diff --git a/src/events.cpp b/src/events.cpp index 8dd9baa966..6ae49f04c2 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -688,7 +688,7 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLineDamaged); DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick) -DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame) +//DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame) DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderOverlay) DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerEntered) @@ -972,6 +972,7 @@ static FRenderEvent E_SetupRenderEvent() void DStaticEventHandler::RenderFrame() { + /* This is intentionally and permanently disabled. IFVIRTUAL(DStaticEventHandler, RenderFrame) { // don't create excessive DObjects if not going to be processed anyway @@ -981,6 +982,7 @@ void DStaticEventHandler::RenderFrame() VMValue params[2] = { (DStaticEventHandler*)this, &e }; VMCall(func, params, 2, nullptr, 0); } + */ } void DStaticEventHandler::RenderOverlay(EHudState state) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 1e4d412a24..ff48ab79d3 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4689,14 +4689,6 @@ void AActor::Tick () } } -DEFINE_ACTION_FUNCTION(AActor, Tick) -{ - PARAM_SELF_PROLOGUE(AActor); - self->Tick(); - return 0; -} - - //========================================================================== // // AActor :: CheckNoDelay @@ -8282,13 +8274,6 @@ DEFINE_ACTION_FUNCTION(AActor, SetDamage) return 0; } -DEFINE_ACTION_FUNCTION(AActor, GetDefaultByType) -{ - PARAM_PROLOGUE; - PARAM_CLASS(cls, AActor); - ACTION_RETURN_OBJECT(cls == nullptr? nullptr : GetDefaultByType(cls)); -} - // This combines all 3 variations of the internal function DEFINE_ACTION_FUNCTION(AActor, VelFromAngle) { diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 1a95f051d9..1ed2c78d63 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -1899,13 +1899,6 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt) ACTION_RETURN_INT(self->GetLightLevel()); } - DEFINE_ACTION_FUNCTION(_Sector, ClearSpecial) - { - PARAM_SELF_STRUCT_PROLOGUE(sector_t); - self->ClearSpecial(); - return 0; - } - DEFINE_ACTION_FUNCTION(_Sector, PortalBlocksView) { PARAM_SELF_STRUCT_PROLOGUE(sector_t); diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index f58fd77192..aba8102c16 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -259,7 +259,7 @@ void ExpEmit::Reuse(VMFunctionBuilder *build) // //========================================================================== -static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func) +static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func, const uint8_t *reginfo) { PSymbol *sym = Namespaces.GlobalNamespace->Symbols.FindSymbol(funcname, false); if (sym == nullptr) @@ -267,6 +267,7 @@ static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCall PSymbolVMFunction *symfunc = Create(funcname); VMNativeFunction *calldec = new VMNativeFunction(func, funcname); calldec->PrintableName = funcname.GetChars(); + calldec->RegTypes = reginfo; symfunc->Function = calldec; sym = symfunc; Namespaces.GlobalNamespace->Symbols.AddSymbol(sym); @@ -5487,7 +5488,8 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) { // Call DecoRandom to generate a random number. VMFunction *callfunc; - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom); + static const uint8_t reginfo[] = { REGT_POINTER, REGT_INT, REGT_INT }; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom, reginfo); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); @@ -5595,7 +5597,8 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) // Call BuiltinRandom to generate a random number. VMFunction *callfunc; - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom); + static const uint8_t reginfo[] = { REGT_POINTER, REGT_INT, REGT_INT }; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom, reginfo); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); @@ -5714,7 +5717,8 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) { // Call the BuiltinFRandom function to generate a floating point random number.. VMFunction *callfunc; - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinFRandom, BuiltinFRandom); + static uint8_t reginfo[] = { REGT_POINTER, REGT_FLOAT, REGT_FLOAT }; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinFRandom, BuiltinFRandom, reginfo); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); @@ -5793,7 +5797,8 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) { // Call the BuiltinRandom function to generate the random number. VMFunction *callfunc; - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom2, BuiltinRandom2); + static uint8_t reginfo[] = { REGT_POINTER, REGT_INT }; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom2, BuiltinRandom2, reginfo); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); @@ -5865,7 +5870,8 @@ ExpEmit FxRandomSeed::Emit(VMFunctionBuilder *build) { // Call DecoRandom to generate a random number. VMFunction *callfunc; - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandomSeed, BuiltinRandomSeed); + static uint8_t reginfo[] = { REGT_POINTER, REGT_INT }; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandomSeed, BuiltinRandomSeed, reginfo); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); @@ -8567,7 +8573,8 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) } // Call the BuiltinCallLineSpecial function to perform the desired special. VMFunction *callfunc; - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial, BuiltinCallLineSpecial); + static uint8_t reginfo[] = { REGT_INT, REGT_POINTER, REGT_INT, REGT_INT, REGT_INT, REGT_INT, REGT_INT }; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial, BuiltinCallLineSpecial, reginfo); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); @@ -10776,7 +10783,8 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) // Call the BuiltinNameToClass function to convert from 'name' to class. VMFunction *callfunc; - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinNameToClass, BuiltinNameToClass); + static uint8_t reginfo[] = { REGT_INT, REGT_POINTER }; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinNameToClass, BuiltinNameToClass, reginfo); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); @@ -10885,7 +10893,8 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build) emitters.AddParameterPointerConst(desttype); VMFunction *callfunc; - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast); + static uint8_t reginfo[] = { REGT_POINTER, REGT_POINTER }; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast, reginfo); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); diff --git a/src/scripting/backend/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp index 1aa5c09f77..f11feab868 100644 --- a/src/scripting/backend/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -909,6 +909,7 @@ void FFunctionBuildList::Build() fprintf(dump, "\n*************************************************************************\n%i code bytes\n%i data bytes", codesize * 4, datasize); fclose(dump); } + VMFunction::CreateRegUseInfo(); FScriptPosition::StrictErrors = false; if (Args->CheckParm("-dumpjit")) DumpJit(); mItems.Clear(); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 6d62e70817..531af0701e 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -943,6 +943,8 @@ void InitThingdef() auto fcp = NewStruct("FCheckPosition", nullptr); fcp->mConstructor = *FindFunction(fcp, "_Constructor")->VMPointer; fcp->mDestructor = *FindFunction(fcp, "_Destructor")->VMPointer; + static const uint8_t reguse[] = { REGT_POINTER }; + fcp->mConstructor->RegTypes = fcp->mDestructor->RegTypes = reguse; fcp->Size = sizeof(FCheckPosition); fcp->Align = alignof(FCheckPosition); @@ -991,11 +993,6 @@ void SynthesizeFlagFields() } } } -DEFINE_ACTION_FUNCTION(DObject, GameType) -{ - PARAM_PROLOGUE; - ACTION_RETURN_INT(gameinfo.gametype); -} DEFINE_ACTION_FUNCTION(DObject, BAM) { diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index ab1fdad71d..f1266bd511 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -319,10 +319,11 @@ class VMFunction { public: bool Unsafe = false; - int VarFlags = 0; // [ZZ] this replaces 5+ bool fields uint8_t ImplicitArgs = 0; // either 0 for static, 1 for method or 3 for action + int VarFlags = 0; // [ZZ] this replaces 5+ bool fields unsigned VirtualIndex = ~0u; FName Name; + const uint8_t *RegTypes = nullptr; TArray DefaultArgs; FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. @@ -352,8 +353,16 @@ public: } AllFunctions.Clear(); } + static void CreateRegUseInfo() + { + for (auto f : AllFunctions) + { + f->CreateRegUse(); + } + } static TArray AllFunctions; protected: + void CreateRegUse(); }; class VMNativeFunction : public VMFunction diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index 5b58180a8e..3424b81d70 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -193,17 +193,20 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) const VMRegisters calleereg(callee); assert(calleefunc != NULL && !(calleefunc->VarFlags & VARF_Native)); - assert(numparam == calleefunc->NumArgs || ((int)calleefunc->DefaultArgs.Size() == calleefunc->NumArgs)); + assert(numparam == calleefunc->NumArgs); assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3); regd = regf = regs = rega = 0; - for (int i = 0; i < calleefunc->NumArgs; ++i) + const uint8_t *reginfo = calleefunc->RegTypes; + assert(reginfo != nullptr); + for (int i = 0; i < calleefunc->NumArgs; ++i, reginfo++) { - // get all actual parameters and fill the rest from the defaults. - VMValue &p = i < numparam? params[i] : calleefunc->DefaultArgs[i]; - if (p.Type < REGT_STRING) + // copy all parameters to the local registers. + VMValue &p = params[i]; + assert(*reginfo == p.Type); + if (*reginfo < REGT_STRING) { - if (p.Type == REGT_INT) + if (*reginfo == REGT_INT) { calleereg.d[regd++] = p.i; } @@ -212,13 +215,13 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) calleereg.f[regf++] = p.f; } } - else if (p.Type == REGT_STRING) + else if (*reginfo == REGT_STRING) { calleereg.s[regs++] = p.s(); } else { - assert(p.Type == REGT_POINTER); + assert(*reginfo == REGT_POINTER); calleereg.a[rega++] = p.a; } } diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 0a69c8c2b0..0f9da73839 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -65,6 +65,42 @@ IMPLEMENT_CLASS(VMException, false, false) TArray VMFunction::AllFunctions; +// Creates the register type list for a function. +// Native functions only need this to assert their parameters in debug mode, script functions use this to load their registers from the VMValues. +void VMFunction::CreateRegUse() +{ +#ifdef NDEBUG + if (VarFlags & VARF_Native) return; // we do not need this for native functions in release builds. +#endif + int count = 0; + if (!Proto) + { + if (RegTypes) return; + Printf(TEXTCOLOR_ORANGE "Function without prototype needs register info manually set: %s\n", PrintableName.GetChars()); + return; + } + assert(Proto->isPrototype()); + for (auto arg : Proto->ArgumentTypes) + { + count += arg? arg->GetRegCount() : 1; + } + uint8_t *regp; + RegTypes = regp = (uint8_t*)ClassDataAllocator.Alloc(count); + count = 0; + for (auto arg : Proto->ArgumentTypes) + { + if (arg == nullptr) + { + // Marker for start of varargs. + *regp++ = REGT_NIL; + } + else for (int i = 0; i < arg->GetRegCount(); i++) + { + *regp++ = arg->GetRegType(); + } + } +} + VMScriptFunction::VMScriptFunction(FName name) { Name = name; diff --git a/wadsrc/static/zscript/mapdata.txt b/wadsrc/static/zscript/mapdata.txt index 3440d4b242..9f58c07242 100644 --- a/wadsrc/static/zscript/mapdata.txt +++ b/wadsrc/static/zscript/mapdata.txt @@ -34,6 +34,7 @@ struct SectorPortal native play struct Vertex native play { native readonly Vector2 p; + native int Index(); } struct Side native play