- allow the VM to run on one global stack per thread.

It is utterly pointless to require every function that wants to make a VM call to allocate a new stack first. The allocation overhead doubles the time to set up the call.
With one stack, previously allocated memory can be reused. The only important thing is, if this ever gets used in a multithreaded environment to have the stack being declared as thread_local, although for ZDoom this is of no consequence.

- eliminated all cases where native code was calling other native code through the VM interface. After scriptifying the game code, only 5 places were left which were quickly eliminated. This was mostly to ensure that the native VM function parameters do not need to be propagated further than absolutely necessary.
This commit is contained in:
Christoph Oelckers 2016-11-30 17:15:01 +01:00
parent 47884f8a71
commit 86544086df
23 changed files with 176 additions and 229 deletions

View file

@ -4228,7 +4228,7 @@ PPrototype *FxTypeCheck::ReturnProto()
//
//==========================================================================
int BuiltinTypeCheck(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
int BuiltinTypeCheck(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
{
assert(numparam == 2);
PARAM_POINTER_AT(0, obj, DObject);
@ -5030,7 +5030,7 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx)
//
//==========================================================================
int BuiltinRandom(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
int BuiltinRandom(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
{
assert(numparam >= 1 && numparam <= 3);
FRandom *rng = reinterpret_cast<FRandom *>(param[0].a);
@ -5284,7 +5284,7 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri
//
//==========================================================================
int BuiltinFRandom(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
int BuiltinFRandom(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
{
assert(numparam == 1 || numparam == 3);
FRandom *rng = reinterpret_cast<FRandom *>(param[0].a);
@ -7558,7 +7558,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
//
//==========================================================================
int BuiltinCallLineSpecial(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
int BuiltinCallLineSpecial(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
{
assert(numparam > 2 && numparam < 8);
assert(param[0].Type == REGT_INT);
@ -9518,7 +9518,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx)
//
//==========================================================================
int BuiltinNameToClass(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
int BuiltinNameToClass(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
{
assert(numparam == 2);
assert(numret == 1);
@ -9650,7 +9650,7 @@ FxExpression *FxClassPtrCast::Resolve(FCompileContext &ctx)
//
//==========================================================================
int BuiltinClassCast(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
int BuiltinClassCast(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
{
PARAM_PROLOGUE;
PARAM_CLASS(from, DObject);

View file

@ -867,7 +867,7 @@ class VMNativeFunction : public VMFunction
{
DECLARE_CLASS(VMNativeFunction, VMFunction);
public:
typedef int (*NativeCallType)(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);
typedef int (*NativeCallType)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);
VMNativeFunction() : NativeCall(NULL) { Native = true; }
VMNativeFunction(NativeCallType call) : NativeCall(call) { Native = true; }
@ -930,6 +930,9 @@ enum EVMEngine
VMEngine_Checked
};
extern thread_local VMFrameStack GlobalVMStack;
void VMSelectEngine(EVMEngine engine);
extern int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret);
void VMFillParams(VMValue *params, VMFrame *callee, int numparam);
@ -938,8 +941,8 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func);
void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func);
// Use this in the prototype for a native function.
#define VM_ARGS VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret
#define VM_ARGS_NAMES stack, param, defaultparam, numparam, ret, numret
#define VM_ARGS VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret
#define VM_ARGS_NAMES param, defaultparam, numparam, ret, numret
// Use these to collect the parameters in a native function.
// variable name <x> at position <p>
@ -1012,7 +1015,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_OBJECT_DEF(x,type) ++paramnum; PARAM_OBJECT_DEF_AT(paramnum,x,type)
#define PARAM_CLASS_DEF(x,base) ++paramnum; PARAM_CLASS_DEF_AT(paramnum,x,base)
typedef int(*actionf_p)(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/
typedef int(*actionf_p)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/
struct FieldDesc
{
@ -1048,7 +1051,6 @@ struct AFuncDesc
// Macros to handle action functions. These are here so that I don't have to
// change every single use in case the parameters change.
#define DECLARE_ACTION(name) extern VMNativeFunction *AActor_##name##_VMPtr;
#define DEFINE_ACTION_FUNCTION(cls, name) \
static int AF_##cls##_##name(VM_ARGS); \
@ -1090,8 +1092,6 @@ struct AFuncDesc
MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname;
class AActor;
void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self);
#define CALL_ACTION(name, self) CallAction(stack, AActor_##name##_VMPtr, self);
#define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0)

View file

@ -146,6 +146,12 @@ VMExec_Checked::Exec
#endif
;
// Note: If the VM is being used in multiple threads, this should be declared as thread_local.
// ZDoom doesn't need this at the moment so this is disabled.
thread_local VMFrameStack GlobalVMStack;
//===========================================================================
//
// VMSelectEngine

View file

@ -422,12 +422,13 @@ VMFrame *VMFrameStack::PopFrame()
int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap)
{
assert(this == VMGlobalStack); // why would anyone even want to create a local stack?
bool allocated = false;
try
{
if (func->Native)
{
return static_cast<VMNativeFunction *>(func)->NativeCall(this, params, func->DefaultArgs, numparams, results, numresults);
return static_cast<VMNativeFunction *>(func)->NativeCall(params, func->DefaultArgs, numparams, results, numresults);
}
else
{
@ -503,11 +504,3 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur
throw;
}
}
class AActor;
void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self)
{
// Without the type cast this picks the 'void *' assignment...
VMValue params[3] = { (DObject*)self, (DObject*)self, VMValue(nullptr, ATAG_GENERIC) };
stack->Call(vmfunc, params, vmfunc->ImplicitArgs, nullptr, 0, nullptr);
}

View file

@ -2362,7 +2362,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
{
if (vindex != -1)
{
Error(p, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars());
Error(f, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars());
}
sym->Variants[0].Implementation->VirtualIndex = clstype->Virtuals.Push(sym->Variants[0].Implementation);
}
@ -3267,3 +3267,7 @@ FArgumentList &ZCCCompiler::ConvertNodeList(FArgumentList &args, ZCC_TreeNode *h
}
return args;
}
void func()
{
}