diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 81ee907f47..66bdc652c9 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -823,7 +823,9 @@ void SetDehParams(FState *state, int codepointer) VMScriptFunction *sfunc = new VMScriptFunction; buildit.MakeFunction(sfunc); sfunc->NumArgs = NAP; + sfunc->ImplicitArgs = NAP; state->SetAction(sfunc); + sfunc->PrintableName.Format("Dehacked.%s.%d.%d", MBFCodePointers[codepointer].name.GetChars(), value1, value2); } } diff --git a/src/dobjtype.h b/src/dobjtype.h index e6f2a491b0..c5d96972b1 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -719,6 +719,12 @@ public: PClass *OwningClass = nullptr; unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags); + int GetImplicitArgs() + { + if (Variants[0].Flags & VARF_Action) return 3; + else if (Variants[0].Flags & VARF_Method) return 1; + return 0; + } size_t PropagateMark(); diff --git a/src/info.cpp b/src/info.cpp index 44f485e6ce..5e267b39c8 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -94,13 +94,13 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, } if (stateret == NULL) { - stack.Call(ActionFunc, params, countof(params), NULL, 0, NULL); + stack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, NULL, 0, NULL); } else { VMReturn ret; ret.PointerAt((void **)stateret); - stack.Call(ActionFunc, params, countof(params), &ret, 1, NULL); + stack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1, NULL); } ActionCycles.Unclock(); return true; diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index c8e110a68d..bbeeca3743 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -168,7 +168,7 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state) numret = 2; } } - stack.Call(state->ActionFunc, params, countof(params), wantret, numret); + stack.Call(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret); // As long as even one state succeeds, the whole chain succeeds unless aborted below. // A state that wants to jump does not count as "succeeded". if (nextstate == NULL) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index dce724a324..1de5c13c2f 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5196,11 +5196,11 @@ PPrototype *FxVMFunctionCall::ReturnProto() VMFunction *FxVMFunctionCall::GetDirectFunction() { - // If this return statement calls a function with no arguments, + // If this return statement calls a non-virtual function with no arguments, // then it can be a "direct" function. That is, the DECORATE // definition can call that function directly without wrapping // it inside VM code. - if ((ArgList ? ArgList->Size() : 0) == 0 && (Function->Variants[0].Flags & VARF_Action)) + if ((ArgList ? ArgList->Size() : 0) == 0 && !(Function->Variants[0].Flags & VARF_Virtual)) { return Function->Variants[0].Implementation; } @@ -5222,10 +5222,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) auto proto = Function->Variants[0].Proto; auto argtypes = proto->ArgumentTypes; - int implicit; - if (Function->Variants[0].Flags & VARF_Action) implicit = 3; - else if (Function->Variants[0].Flags & VARF_Method) implicit = 1; - else implicit = 0; + int implicit = Function->GetImplicitArgs(); // This should never happen. if (Self == nullptr && !(Function->Variants[0].Flags & VARF_Static)) diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index b9dafde0c0..a37b7449b6 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -179,12 +179,12 @@ class VMFunction : public DObject HAS_OBJECT_POINTERS; public: bool Native; + BYTE ImplicitArgs = 0; // either 0 for static, 1 for method or 3 for action FName Name; class PPrototype *Proto; - VMFunction() : Native(false), Name(NAME_None), Proto(NULL) {} - VMFunction(FName name) : Native(false), Name(name), Proto(NULL) {} + VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) {} }; enum EVMOpMode diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index a5f15b262b..b58de0ea4b 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -665,6 +665,7 @@ VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *c it.Code = code; it.PrintableName = name; it.Function = new VMScriptFunction; + it.Function->ImplicitArgs = functype->GetImplicitArgs(); it.Proto = nullptr; it.FromDecorate = fromdecorate; mItems.Push(it); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index ba038a7160..9b4212820e 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1951,14 +1951,15 @@ void ZCCCompiler::InitFunctions() f->Flags &= notallowed; } uint32_t varflags = VARF_Method; + int implicitargs = 1; AFuncDesc *afd = nullptr; // map to implementation flags. if (f->Flags & ZCC_Private) varflags |= VARF_Private; if (f->Flags & ZCC_Protected) varflags |= VARF_Protected; if (f->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; - if (f->Flags & ZCC_Action) varflags |= VARF_Action|VARF_Final; // Action implies Final. - if (f->Flags & ZCC_Static) varflags = (varflags & ~VARF_Method) | VARF_Final; // Static implies Final. + if (f->Flags & ZCC_Action) varflags |= VARF_Action|VARF_Final, implicitargs = 3; // Action implies Final. + if (f->Flags & ZCC_Static) varflags = (varflags & ~VARF_Method) | VARF_Final, implicitargs = 0; // Static implies Final. if ((f->Flags & (ZCC_Action | ZCC_Static)) == (ZCC_Action | ZCC_Static)) { Error(f, "%s: Action and Static on the same function is not allowed.", FName(f->Name).GetChars()); @@ -1973,6 +1974,7 @@ void ZCCCompiler::InitFunctions() { Error(f, "The function '%s' has not been exported from the executable.", FName(f->Name).GetChars()); } + (*afd->VMPointer)->ImplicitArgs = BYTE(implicitargs); } SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags); auto p = f->Params; @@ -2063,7 +2065,7 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClassActor *cls, ZCC_TreeNode *a PFunction *afd = dyn_cast(cls->Symbols.FindSymbol(id->Identifier, true)); if (afd != nullptr) { - if (fc->Parameters == nullptr && (afd->Variants[0].Flags & VARF_Action)) + if (fc->Parameters == nullptr && !(afd->Variants[0].Flags & VARF_Virtual)) { // We can use this function directly without wrapping it in a caller. return new FxVMFunctionCall(new FxSelf(*af), afd, nullptr, *af, false);