diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 44e675ed2..89ac12401 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 8dd9baa96..6ae49f04c 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 1e4d412a2..ff48ab79d 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 1a95f051d..1ed2c78d6 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 f58fd7719..aba8102c1 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 1aa5c09f7..f11feab86 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 6d62e7081..531af0701 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 ab1fdad71..f1266bd51 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 5b58180a8..3424b81d7 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 0a69c8c2b..0f9da7383 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 3440d4b24..9f58c0724 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