diff --git a/src/info.cpp b/src/info.cpp index 87332fd2b..385dc5bd4 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -148,6 +148,7 @@ void FState::CheckCallerType(AActor *self, AActor *stateowner) } } +TArray actionParams; bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, FState **stateret) { @@ -155,7 +156,6 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, { ActionCycles.Clock(); - VMValue params[3] = { self, stateowner, VMValue(info) }; // If the function returns a state, store it at *stateret. // If it doesn't return a state but stateret is non-nullptr, we need // to set *stateret to nullptr. @@ -169,19 +169,36 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, stateret = nullptr; } } + + VMReturn ret; + ret.PointerAt((void **)stateret); try { CheckCallerType(self, stateowner); - - if (stateret == nullptr) + + // Build the parameter array. Action functions have never any explicit parameters but need to pass the defaults + // and fill in the implicit arguments of the called function. + + if (ActionFunc->DefaultArgs.Size() > 0) { - VMCall(ActionFunc, params, ActionFunc->ImplicitArgs, nullptr, 0); + auto index = actionParams.Append(ActionFunc->DefaultArgs); + if (ActionFunc->ImplicitArgs >= 1) + { + actionParams[index] = self; + } + if (ActionFunc->ImplicitArgs == 3) + { + actionParams[index + 1] = stateowner; + actionParams[index + 2] = VMValue(info); + } + + VMCallAction(ActionFunc, &actionParams[index], ActionFunc->DefaultArgs.Size(), &ret, stateret != nullptr); + actionParams.Clamp(index); } else { - VMReturn ret; - ret.PointerAt((void **)stateret); - VMCall(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1); + VMValue params[3] = { self, stateowner, VMValue(info) }; + VMCallAction(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, stateret != nullptr); } } catch (CVMAbortException &err) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index bcba95930..477ceda96 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -1211,7 +1211,7 @@ DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int ce auto c = PClass::FindClass("OptionMenuItemSubmenu"); auto p = c->CreateNew(); FString namestr = label; - VMValue params[] = { p, &namestr, cmd.GetIndex(), center }; + VMValue params[] = { p, &namestr, cmd.GetIndex(), center, false }; auto f = dyn_cast(c->FindSymbol("Init", false)); VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; @@ -1233,7 +1233,7 @@ DMenuItemBase * CreateOptionMenuItemCommand(const char *label, FName cmd, bool c auto c = PClass::FindClass("OptionMenuItemCommand"); auto p = c->CreateNew(); FString namestr = label; - VMValue params[] = { p, &namestr, cmd.GetIndex(), centered }; + VMValue params[] = { p, &namestr, cmd.GetIndex(), centered, false }; auto f = dyn_cast(c->FindSymbol("Init", false)); VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); auto unsafe = dyn_cast(c->FindSymbol("mUnsafe", false)); diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index f7bf7e108..43c703900 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -477,7 +477,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) } DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew(); params[0] = item; - VMCall(func->Variants[0].Implementation, ¶ms[0], params.Size(), nullptr, 0); + VMCallWithDefaults(func->Variants[0].Implementation, params, nullptr, 0); desc->mItems.Push((DMenuItemBase*)item); if (cls->IsDescendantOf("ListMenuItemSelectable")) @@ -917,7 +917,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc) DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew(); params[0] = item; - VMCall(func->Variants[0].Implementation, ¶ms[0], params.Size(), nullptr, 0); + VMCallWithDefaults(func->Variants[0].Implementation, params, nullptr, 0); desc->mItems.Push((DMenuItemBase*)item); success = true; diff --git a/src/namedef.h b/src/namedef.h index 184c58fd0..2d0c2c126 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -827,6 +827,7 @@ xx(Key) // Decorate compatibility functions xx(BuiltinTypeCheck) xx(BuiltinRandom) +xx(BuiltinRandom2) xx(BuiltinFRandom) xx(BuiltinCallLineSpecial) xx(BuiltinNameToClass) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 10038cb6d..808b724e1 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5448,7 +5448,7 @@ static int ScriptCall(AActor *activator, unsigned argc, int32_t *args) // The return value can be the same types as the parameter types, plus void if (func->Proto->ReturnTypes.Size() == 0) { - VMCall(func, ¶ms[0], params.Size(), nullptr, 0); + VMCallWithDefaults(func, params, nullptr, 0); } else { @@ -5470,20 +5470,20 @@ static int ScriptCall(AActor *activator, unsigned argc, int32_t *args) { double d; VMReturn ret(&d); - VMCall(func, ¶ms[0], params.Size(), &ret, 1); + VMCallWithDefaults(func, params, &ret, 1); retval = DoubleToACS(d); } else if (rettype == TypeString) { FString d; VMReturn ret(&d); - VMCall(func, ¶ms[0], params.Size(), &ret, 1); + VMCallWithDefaults(func, params, &ret, 1); retval = GlobalACSStrings.AddString(d); } else { // All other return values can not be handled so ignore them. - VMCall(func, ¶ms[0], params.Size(), nullptr, 0); + VMCallWithDefaults(func, params, nullptr, 0); } } } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index ff9ac211c..86eda27fe 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -96,12 +96,13 @@ static FRandom pr_bfgselfdamage("BFGSelfDamage"); // until there is no next state // //========================================================================== +extern TArray actionParams; // this can use the same storage as CallAction + bool AStateProvider::CallStateChain (AActor *actor, FState *state) { INTBOOL result = false; int counter = 0; - VMValue params[3] = { actor, this, 0 }; // We accept return types of `state`, `(int|bool)` or `state, (int|bool)`. // The last one is for the benefit of A_Warp and A_Teleport. @@ -139,7 +140,6 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state) VMReturn *wantret; FStateParamInfo stp = { state, STATE_StateChain, PSP_WEAPON }; - params[2] = VMValue(&stp); retval = true; // assume success wantret = NULL; // assume no return value wanted numret = 0; @@ -167,10 +167,33 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state) wantret = &ret[1]; numret = 1; } + + try { state->CheckCallerType(actor, this); - VMCall(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret); + + if (state->ActionFunc->DefaultArgs.Size() > 0) + { + auto index = actionParams.Append(state->ActionFunc->DefaultArgs); + if (state->ActionFunc->ImplicitArgs >= 1) + { + actionParams[index] = actor; + } + if (state->ActionFunc->ImplicitArgs == 3) + { + actionParams[index + 1] = this; + actionParams[index + 2] = VMValue(&stp); + } + + VMCallAction(state->ActionFunc, &actionParams[index], state->ActionFunc->DefaultArgs.Size(), wantret, numret); + actionParams.Clamp(index); + } + else + { + VMValue params[3] = { actor, this, VMValue(&stp) }; + VMCallAction(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret); + } } catch (CVMAbortException &err) { diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 039a21dab..e9c7cc96f 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -5445,12 +5445,9 @@ FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScrip : FxExpression(EFX_Random, pos) { EmitTail = false; - if (mi != nullptr && ma != nullptr) - { - min = new FxIntCast(mi, nowarn); - max = new FxIntCast(ma, nowarn); - } - else min = max = nullptr; + assert(mi && ma); + min = new FxIntCast(mi, nowarn); + max = new FxIntCast(ma, nowarn); rng = r; ValueType = TypeSInt32; } @@ -5508,29 +5505,15 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx) int BuiltinRandom(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) { - assert(numparam >= 1 && numparam <= 3); - FRandom *rng = reinterpret_cast(param[0].a); - if (numparam == 1) + PARAM_PROLOGUE; + PARAM_POINTER(rng, FRandom); + PARAM_INT(min); + PARAM_INT(max); + if (max < min) { - ACTION_RETURN_INT((*rng)()); + std::swap(max, min); } - else if (numparam == 2) - { - int maskval = param[1].i; - ACTION_RETURN_INT(rng->Random2(maskval)); - } - else if (numparam == 3) - { - int min = param[1].i, max = param[2].i; - if (max < min) - { - swapvalues(max, min); - } - ACTION_RETURN_INT((*rng)(max - min + 1) + min); - } - - // Shouldn't happen - return 0; + ACTION_RETURN_INT((*rng)(max - min + 1) + min); } ExpEmit FxRandom::Emit(VMFunctionBuilder *build) @@ -5541,22 +5524,16 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); + assert(min && max); callfunc = ((PSymbolVMFunction *)sym)->Function; if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); - if (min != nullptr && max != nullptr) - { - EmitParameter(build, min, ScriptPosition); - EmitParameter(build, max, ScriptPosition); - build->Emit(opcode, build->GetConstantAddress(callfunc), 3, 1); - } - else - { - build->Emit(opcode, build->GetConstantAddress(callfunc), 1, 1); - } + EmitParameter(build, min, ScriptPosition); + EmitParameter(build, max, ScriptPosition); + build->Emit(opcode, build->GetConstantAddress(callfunc), 3, 1); if (EmitTail) { @@ -5746,11 +5723,9 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) : FxRandom(r, nullptr, nullptr, pos, true) { - if (mi != nullptr && ma != nullptr) - { - min = new FxFloatCast(mi); - max = new FxFloatCast(ma); - } + assert(mi && ma); + min = new FxFloatCast(mi); + max = new FxFloatCast(ma); ValueType = TypeFloat64; ExprType = EFX_FRandom; } @@ -5763,25 +5738,19 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri int BuiltinFRandom(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) { - assert(numparam == 1 || numparam == 3); - FRandom *rng = reinterpret_cast(param[0].a); + PARAM_PROLOGUE; + PARAM_POINTER(rng, FRandom); + PARAM_FLOAT(min); + PARAM_FLOAT(max); int random = (*rng)(0x40000000); double frandom = random / double(0x40000000); - if (numparam == 3) + if (max < min) { - double min = param[1].f, max = param[2].f; - if (max < min) - { - swapvalues(max, min); - } - ACTION_RETURN_FLOAT(frandom * (max - min) + min); - } - else - { - ACTION_RETURN_FLOAT(frandom); + std::swap(max, min); } + ACTION_RETURN_FLOAT(frandom * (max - min) + min); } ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) @@ -5792,22 +5761,16 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); + assert(min && max); callfunc = ((PSymbolVMFunction *)sym)->Function; if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); - if (min != nullptr && max != nullptr) - { - EmitParameter(build, min, ScriptPosition); - EmitParameter(build, max, ScriptPosition); - build->Emit(opcode, build->GetConstantAddress(callfunc), 3, 1); - } - else - { - build->Emit(opcode, build->GetConstantAddress(callfunc), 1, 1); - } + EmitParameter(build, min, ScriptPosition); + EmitParameter(build, max, ScriptPosition); + build->Emit(opcode, build->GetConstantAddress(callfunc), 3, 1); if (EmitTail) { @@ -5879,11 +5842,25 @@ FxExpression *FxRandom2::Resolve(FCompileContext &ctx) // //========================================================================== +int BuiltinRandom2(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +{ + PARAM_PROLOGUE; + PARAM_POINTER(rng, FRandom); + PARAM_INT(maskval); + ACTION_RETURN_INT(rng->Random2(maskval)); +} + +//========================================================================== +// +// +// +//========================================================================== + ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) { // Call the BuiltinRandom function to generate the random number. VMFunction *callfunc; - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom); + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom2, BuiltinRandom2); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); @@ -8536,6 +8513,10 @@ FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgum Self = self; Special = special; ArgList = std::move(args); + while (ArgList.Size() < 5) + { + ArgList.Push(new FxConstant(0, ScriptPosition)); + } EmitTail = false; } @@ -8617,6 +8598,8 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) } } } + + if (failed) { delete this; @@ -8635,16 +8618,16 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) int BuiltinCallLineSpecial(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) { - assert(numparam > 2 && numparam < 8); - assert(param[0].Type == REGT_INT); - assert(param[1].Type == REGT_POINTER); - int v[5] = { 0 }; + PARAM_PROLOGUE; + PARAM_INT(special); + PARAM_OBJECT(activator, AActor); + PARAM_INT_DEF(arg1); + PARAM_INT_DEF(arg2); + PARAM_INT_DEF(arg3); + PARAM_INT_DEF(arg4); + PARAM_INT_DEF(arg5); - for (int i = 2; i < numparam; ++i) - { - v[i - 2] = param[i].i; - } - ACTION_RETURN_INT(P_ExecuteSpecial(param[0].i, nullptr, reinterpret_cast(param[1].a), false, v[0], v[1], v[2], v[3], v[4])); + ACTION_RETURN_INT(P_ExecuteSpecial(special, nullptr, activator, 0, arg1, arg2, arg3, arg4, arg5)); } ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) @@ -9127,6 +9110,31 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { count += EmitParameter(build, ArgList[i], ScriptPosition, &tempstrings); } + // Complete the parameter list from the defaults. + auto &defaults = Function->Variants[0].Implementation->DefaultArgs; + for (unsigned i = count; i < defaults.Size(); i++) + { + FxConstant *constant; + switch (defaults[i].Type) + { + default: + case REGT_INT: + constant = new FxConstant(defaults[i].i, ScriptPosition); + break; + case REGT_FLOAT: + constant = new FxConstant(defaults[i].f, ScriptPosition); + break; + case REGT_POINTER: + constant = new FxConstant(defaults[i].a, ScriptPosition); + break; + case REGT_STRING: + constant = new FxConstant(defaults[i].s(), ScriptPosition); + break; + } + count += EmitParameter(build, constant, ScriptPosition, &tempstrings); + delete constant; + } + ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 092503282..87084596c 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -501,6 +501,13 @@ public: isresolved = true; } + FxConstant(void *state, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) + { + value.pointer = state; + ValueType = value.Type = TypeVoidPtr; + isresolved = true; + } + FxConstant(const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { value.pointer = nullptr; diff --git a/src/scripting/vm/jit.cpp b/src/scripting/vm/jit.cpp index d292a9d26..143aa90a7 100644 --- a/src/scripting/vm/jit.cpp +++ b/src/scripting/vm/jit.cpp @@ -492,21 +492,7 @@ void JitCompiler::SetupFrame() if (sfunc->SpecialInits.Size() == 0 && sfunc->NumRegS == 0) { - // This is a simple frame with no constructors or destructors. Allocate it on the stack ourselves. - - auto vmstack = cc.newStack(sfunc->StackSize, 16, "vmstack"); - cc.lea(vmframe, vmstack); - - auto slowinit = cc.newLabel(); - auto endinit = cc.newLabel(); - - cc.cmp(numargs, sfunc->NumArgs); - cc.jne(slowinit); SetupSimpleFrame(); - cc.jmp(endinit); - cc.bind(slowinit); - SetupSimpleFrameMissingArgs(); // Does this ever happen? - cc.bind(endinit); } else { @@ -518,6 +504,11 @@ void JitCompiler::SetupSimpleFrame() { using namespace asmjit; + // This is a simple frame with no constructors or destructors. Allocate it on the stack ourselves. + + auto vmstack = cc.newStack(sfunc->StackSize, 16, "vmstack"); + cc.lea(vmframe, vmstack); + int argsPos = 0; int regd = 0, regf = 0, rega = 0; for (unsigned int i = 0; i < sfunc->Proto->ArgumentTypes.Size(); i++) @@ -569,72 +560,21 @@ void JitCompiler::SetupSimpleFrame() cc.xor_(regA[i], regA[i]); } -void JitCompiler::SetupSimpleFrameMissingArgs() +static VMFrameStack *CreateFullVMFrame(VMScriptFunction *func, VMValue *args, int numargs) { - using namespace asmjit; - - auto sfuncptr = newTempIntPtr(); - cc.mov(sfuncptr, imm_ptr(sfunc)); - if (cc.is64Bit()) - cc.mov(x86::qword_ptr(vmframe, offsetof(VMFrame, Func)), sfuncptr); - else - cc.mov(x86::dword_ptr(vmframe, offsetof(VMFrame, Func)), sfuncptr); - cc.mov(x86::byte_ptr(vmframe, offsetof(VMFrame, NumRegD)), sfunc->NumRegD); - cc.mov(x86::byte_ptr(vmframe, offsetof(VMFrame, NumRegF)), sfunc->NumRegF); - cc.mov(x86::byte_ptr(vmframe, offsetof(VMFrame, NumRegS)), sfunc->NumRegS); - cc.mov(x86::byte_ptr(vmframe, offsetof(VMFrame, NumRegA)), sfunc->NumRegA); - cc.mov(x86::word_ptr(vmframe, offsetof(VMFrame, MaxParam)), sfunc->MaxParam); - cc.mov(x86::word_ptr(vmframe, offsetof(VMFrame, NumParam)), 0); - - // Zero initialize the variables (retardedly stupid to do here - should be done by the compiler backend!!) - unsigned int clearbegin = (unsigned int)offsetof(VMFrame, NumParam) + 2; - unsigned int clearend = sfunc->StackSize; - unsigned int sseend = clearbegin + (clearend - clearbegin) / 16 * 16; - if (clearbegin < sseend) + try { - auto zerosse = newTempXmmPd(); - cc.xorpd(zerosse, zerosse); - for (unsigned int i = clearbegin; i < sseend; i += 16) - cc.movupd(x86::ptr(vmframe, i), zerosse); + VMFrameStack *stack = &GlobalVMStack; + VMFrame *newf = stack->AllocFrame(func); + CurrentJitExceptInfo->vmframes++; + VMFillParams(args, newf, numargs); + return stack; } - if (sseend < clearend) + catch (...) { - auto zero32 = newTempInt32(); - cc.xor_(zero32, zero32); - - unsigned int dwordend = sseend + (clearend - sseend) / 4 * 4; - for (unsigned int i = sseend; i < dwordend; i += 4) - cc.mov(asmjit::x86::dword_ptr(vmframe, i), zero32); - - for (unsigned int i = dwordend; i < clearend; i++) - cc.mov(asmjit::x86::byte_ptr(vmframe, i), zero32.r8Lo()); + VMThrowException(std::current_exception()); + return nullptr; } - - auto fillParams = CreateCall([](VMFrame *newf, VMValue *args, int numargs) { - try - { - VMFillParams(args, newf, numargs); - } - catch (...) - { - VMThrowException(std::current_exception()); - } - }); - fillParams->setArg(0, vmframe); - fillParams->setArg(1, args); - fillParams->setArg(2, numargs); - - for (int i = 0; i < sfunc->NumRegD; i++) - cc.mov(regD[i], x86::dword_ptr(vmframe, offsetD + i * sizeof(int32_t))); - - for (int i = 0; i < sfunc->NumRegF; i++) - cc.movsd(regF[i], x86::qword_ptr(vmframe, offsetF + i * sizeof(double))); - - for (int i = 0; i < sfunc->NumRegS; i++) - cc.lea(regS[i], x86::ptr(vmframe, offsetS + i * sizeof(FString))); - - for (int i = 0; i < sfunc->NumRegA; i++) - cc.mov(regA[i], x86::ptr(vmframe, offsetA + i * sizeof(void*))); } void JitCompiler::SetupFullVMFrame() @@ -642,21 +582,7 @@ void JitCompiler::SetupFullVMFrame() using namespace asmjit; stack = cc.newIntPtr("stack"); - auto allocFrame = CreateCall([](VMScriptFunction *func, VMValue *args, int numargs) -> VMFrameStack* { - try - { - VMFrameStack *stack = &GlobalVMStack; - VMFrame *newf = stack->AllocFrame(func); - CurrentJitExceptInfo->vmframes++; - VMFillParams(args, newf, numargs); - return stack; - } - catch (...) - { - VMThrowException(std::current_exception()); - return nullptr; - } - }); + auto allocFrame = CreateCall(CreateFullVMFrame); allocFrame->setRet(0, stack); allocFrame->setArg(0, imm_ptr(sfunc)); allocFrame->setArg(1, args); @@ -678,21 +604,24 @@ void JitCompiler::SetupFullVMFrame() cc.mov(regA[i], x86::ptr(vmframe, offsetA + i * sizeof(void*))); } +static void PopFullVMFrame(VMFrameStack *stack) +{ + try + { + stack->PopFrame(); + CurrentJitExceptInfo->vmframes--; + } + catch (...) + { + VMThrowException(std::current_exception()); + } +} + void JitCompiler::EmitPopFrame() { if (sfunc->SpecialInits.Size() != 0 || sfunc->NumRegS != 0) { - auto popFrame = CreateCall([](VMFrameStack *stack) { - try - { - stack->PopFrame(); - CurrentJitExceptInfo->vmframes--; - } - catch (...) - { - VMThrowException(std::current_exception()); - } - }); + auto popFrame = CreateCall(PopFullVMFrame); popFrame->setArg(0, stack); } } diff --git a/src/scripting/vm/jit_flow.cpp b/src/scripting/vm/jit_flow.cpp index 482dfe2a9..1a31b5d02 100644 --- a/src/scripting/vm/jit_flow.cpp +++ b/src/scripting/vm/jit_flow.cpp @@ -48,6 +48,13 @@ void JitCompiler::EmitIJMP() EmitThrowException(X_OTHER); } +static VMFunction *GetVirtual(DObject *o, int c) +{ + auto p = o->GetClass(); + assert(c < (int)p->Virtuals.Size()); + return p->Virtuals[c]; +} + void JitCompiler::EmitVTBL() { auto label = EmitThrowExceptionLabel(X_READ_NIL); @@ -55,17 +62,25 @@ void JitCompiler::EmitVTBL() cc.jz(label); auto result = newResultIntPtr(); - auto call = CreateCall([](DObject *o, int c) -> VMFunction* { - auto p = o->GetClass(); - assert(c < (int)p->Virtuals.Size()); - return p->Virtuals[c]; - }); + auto call = CreateCall(GetVirtual); call->setRet(0, result); call->setArg(0, regA[B]); call->setArg(1, asmjit::Imm(C)); cc.mov(regA[A], result); } +static void ValidateCall(DObject *o, VMFunction *f, int b) +{ + try + { + FScopeBarrier::ValidateCall(o->GetClass(), f, b - 1); + } + catch (...) + { + VMThrowException(std::current_exception()); + } +} + void JitCompiler::EmitSCOPE() { auto label = EmitThrowExceptionLabel(X_READ_NIL); @@ -76,21 +91,17 @@ void JitCompiler::EmitSCOPE() cc.mov(f, asmjit::imm_ptr(konsta[C].v)); typedef int(*FuncPtr)(DObject*, VMFunction*, int); - auto call = CreateCall([](DObject *o, VMFunction *f, int b) { - try - { - FScopeBarrier::ValidateCall(o->GetClass(), f, b - 1); - } - catch (...) - { - VMThrowException(std::current_exception()); - } - }); + auto call = CreateCall(ValidateCall); call->setArg(0, regA[A]); call->setArg(1, f); call->setArg(2, asmjit::Imm(B)); } +static void SetString(VMReturn* ret, FString* str) +{ + ret->SetString(*str); +} + void JitCompiler::EmitRET() { using namespace asmjit; @@ -179,9 +190,7 @@ void JitCompiler::EmitRET() auto ptr = newTempIntPtr(); cc.mov(ptr, ret); cc.add(ptr, (int)(retnum * sizeof(VMReturn))); - auto call = CreateCall([](VMReturn* ret, FString* str) -> void { - ret->SetString(*str); - }); + auto call = CreateCall(SetString); call->setArg(0, ptr); if (regtype & REGT_KONST) call->setArg(1, asmjit::imm_ptr(&konsts[regnum])); else call->setArg(1, regS[regnum]); @@ -254,35 +263,38 @@ void JitCompiler::EmitRETI() } } +static DObject* CreateNew(PClass *cls, int c) +{ + try + { + if (!cls->ConstructNative) + { + ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars()); + } + else if (cls->bAbstract) + { + ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); + } + else if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited + { + ThrowAbortException(X_OTHER, "Cannot create actors with 'new'"); + } + + // [ZZ] validate readonly and between scope construction + if (c) FScopeBarrier::ValidateNew(cls, c - 1); + return cls->CreateNew(); + } + catch (...) + { + VMThrowException(std::current_exception()); + return nullptr; + } +} + void JitCompiler::EmitNEW() { auto result = newResultIntPtr(); - auto call = CreateCall([](PClass *cls, int c) -> DObject* { - try - { - if (!cls->ConstructNative) - { - ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars()); - } - else if (cls->bAbstract) - { - ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); - } - else if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited - { - ThrowAbortException(X_OTHER, "Cannot create actors with 'new'"); - } - - // [ZZ] validate readonly and between scope construction - if (c) FScopeBarrier::ValidateNew(cls, c - 1); - return cls->CreateNew(); - } - catch (...) - { - VMThrowException(std::current_exception()); - return nullptr; - } - }); + auto call = CreateCall(CreateNew); call->setRet(0, result); call->setArg(0, regA[B]); call->setArg(1, asmjit::Imm(C)); @@ -290,6 +302,43 @@ void JitCompiler::EmitNEW() cc.mov(regA[A], result); } +static void ThrowNewK(PClass *cls, int c) +{ + try + { + if (!cls->ConstructNative) + { + ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars()); + } + else if (cls->bAbstract) + { + ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); + } + else // if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited + { + ThrowAbortException(X_OTHER, "Cannot create actors with 'new'"); + } + } + catch (...) + { + VMThrowException(std::current_exception()); + } +} + +static DObject *CreateNewK(PClass *cls, int c) +{ + try + { + if (c) FScopeBarrier::ValidateNew(cls, c - 1); + return cls->CreateNew(); + } + catch (...) + { + VMThrowException(std::current_exception()); + return nullptr; + } +} + void JitCompiler::EmitNEW_K() { PClass *cls = (PClass*)konsta[B].v; @@ -298,44 +347,13 @@ void JitCompiler::EmitNEW_K() if (!cls->ConstructNative || cls->bAbstract || cls->IsDescendantOf(NAME_Actor)) { - auto call = CreateCall([](PClass *cls, int c) { - try - { - if (!cls->ConstructNative) - { - ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars()); - } - else if (cls->bAbstract) - { - ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); - } - else // if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited - { - ThrowAbortException(X_OTHER, "Cannot create actors with 'new'"); - } - } - catch (...) - { - VMThrowException(std::current_exception()); - } - }); + auto call = CreateCall(ThrowNewK); call->setArg(0, regcls); } else { auto result = newResultIntPtr(); - auto call = CreateCall([](PClass *cls, int c) -> DObject* { - try - { - if (c) FScopeBarrier::ValidateNew(cls, c - 1); - return cls->CreateNew(); - } - catch (...) - { - VMThrowException(std::current_exception()); - return nullptr; - } - }); + auto call = CreateCall(CreateNewK); call->setRet(0, result); call->setArg(0, regcls); call->setArg(1, asmjit::Imm(C)); diff --git a/src/scripting/vm/jit_load.cpp b/src/scripting/vm/jit_load.cpp index 5b35a7d44..1c6061541 100644 --- a/src/scripting/vm/jit_load.cpp +++ b/src/scripting/vm/jit_load.cpp @@ -76,6 +76,11 @@ void JitCompiler::EmitLFP() cc.lea(regA[A], asmjit::x86::ptr(vmframe, offsetExtra)); } +static uint8_t *GetClassMeta(DObject *o) +{ + return o->GetClass()->Meta; +} + void JitCompiler::EmitMETA() { auto label = EmitThrowExceptionLabel(X_READ_NIL); @@ -83,12 +88,17 @@ void JitCompiler::EmitMETA() cc.je(label); auto result = newResultIntPtr(); - auto call = CreateCall([](DObject *o) { return o->GetClass()->Meta; }); + auto call = CreateCall(GetClassMeta); call->setRet(0, result); call->setArg(0, regA[B]); cc.mov(regA[A], result); } +static PClass *GetClass(DObject *o) +{ + return o->GetClass(); +} + void JitCompiler::EmitCLSS() { auto label = EmitThrowExceptionLabel(X_READ_NIL); @@ -96,7 +106,7 @@ void JitCompiler::EmitCLSS() cc.je(label); auto result = newResultIntPtr(); - auto call = CreateCall([](DObject *o) { return o->GetClass(); }); + auto call = CreateCall(GetClass); call->setRet(0, result); call->setArg(0, regA[B]); cc.mov(regA[A], result); @@ -211,6 +221,11 @@ void JitCompiler::EmitLS_R() call->setArg(1, ptr); } +static DObject *ReadBarrier(DObject *p) +{ + return GC::ReadBarrier(p); +} + void JitCompiler::EmitLO() { EmitNullPointerThrow(B, X_READ_NIL); @@ -219,7 +234,7 @@ void JitCompiler::EmitLO() cc.mov(ptr, asmjit::x86::ptr(regA[B], konstd[C])); auto result = newResultIntPtr(); - auto call = CreateCall([](DObject *p) { return GC::ReadBarrier(p); }); + auto call = CreateCall(ReadBarrier); call->setRet(0, result); call->setArg(0, ptr); cc.mov(regA[A], result); @@ -233,7 +248,7 @@ void JitCompiler::EmitLO_R() cc.mov(ptr, asmjit::x86::ptr(regA[B], regD[C])); auto result = newResultIntPtr(); - auto call = CreateCall([](DObject *p) { return GC::ReadBarrier(p); }); + auto call = CreateCall(ReadBarrier); call->setRet(0, result); call->setArg(0, ptr); cc.mov(regA[A], result); @@ -289,12 +304,17 @@ void JitCompiler::EmitLV3_R() cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16)); } +static void SetString(FString *to, char **from) +{ + *to = *from; +} + void JitCompiler::EmitLCS() { EmitNullPointerThrow(B, X_READ_NIL); auto ptr = newTempIntPtr(); cc.lea(ptr, asmjit::x86::ptr(regA[B], konstd[C])); - auto call = CreateCall([](FString* to, char** from) { *to = *from; }); + auto call = CreateCall(SetString); call->setArg(0, regS[A]); call->setArg(1, ptr); } @@ -304,7 +324,7 @@ void JitCompiler::EmitLCS_R() EmitNullPointerThrow(B, X_READ_NIL); auto ptr = newTempIntPtr(); cc.lea(ptr, asmjit::x86::ptr(regA[B], regD[C])); - auto call = CreateCall([](FString* to, char** from) { *to = *from; }); + auto call = CreateCall(SetString); call->setArg(0, regS[A]); call->setArg(1, ptr); } diff --git a/src/scripting/vm/jit_math.cpp b/src/scripting/vm/jit_math.cpp index 7b557cfb3..48514945d 100644 --- a/src/scripting/vm/jit_math.cpp +++ b/src/scripting/vm/jit_math.cpp @@ -4,41 +4,49 @@ ///////////////////////////////////////////////////////////////////////////// // String instructions. +static void ConcatString(FString* to, FString* first, FString* second) +{ + *to = *first + *second; +} + void JitCompiler::EmitCONCAT() { auto rc = CheckRegS(C, A); - auto call = CreateCall([](FString* to, FString* first, FString* second) { - *to = *first + *second; - }); + auto call = CreateCall(ConcatString); call->setArg(0, regS[A]); call->setArg(1, regS[B]); call->setArg(2, rc); } +static int StringLength(FString* str) +{ + return static_cast(str->Len()); +} + void JitCompiler::EmitLENS() { auto result = newResultInt32(); - auto call = CreateCall([](FString* str) -> int { - return static_cast(str->Len()); - }); + auto call = CreateCall(StringLength); call->setRet(0, result); call->setArg(0, regS[B]); cc.mov(regD[A], result); } +static int StringCompareNoCase(FString* first, FString* second) +{ + return first->CompareNoCase(*second); +} + +static int StringCompare(FString* first, FString* second) +{ + return first->Compare(*second); +} + void JitCompiler::EmitCMPS() { EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) { - auto compareNoCaseLambda = [](FString* first, FString* second) -> int { - return first->CompareNoCase(*second); - }; - auto compareLambda = [](FString* first, FString* second) -> int { - return first->Compare(*second); - }; - auto call = static_cast(A & CMP_APPROX) ? - CreateCall(compareNoCaseLambda) : - CreateCall(compareLambda); + auto call = CreateCall(static_cast(A & CMP_APPROX) ? StringCompareNoCase : StringCompare); auto result = newResultInt32(); call->setRet(0, result); @@ -738,6 +746,11 @@ void JitCompiler::EmitDIVF_KR() cc.divsd(regF[A], rc); } +static double DoubleModF(double a, double b) +{ + return a - floor(a / b) * b; +} + void JitCompiler::EmitMODF_RR() { auto label = EmitThrowExceptionLabel(X_DIVISION_BY_ZERO); @@ -745,10 +758,7 @@ void JitCompiler::EmitMODF_RR() cc.je(label); auto result = newResultXmmSd(); - auto call = CreateCall([](double a, double b) -> double - { - return a - floor(a / b) * b; - }); + auto call = CreateCall(DoubleModF); call->setRet(0, result); call->setArg(0, regF[B]); call->setArg(1, regF[C]); @@ -770,9 +780,7 @@ void JitCompiler::EmitMODF_RK() cc.movsd(tmp, asmjit::x86::qword_ptr(tmpPtr)); auto result = newResultXmmSd(); - auto call = CreateCall([](double a, double b) -> double { - return a - floor(a / b) * b; - }); + auto call = CreateCall(DoubleModF); call->setRet(0, result); call->setArg(0, regF[B]); call->setArg(1, tmp); @@ -792,9 +800,7 @@ void JitCompiler::EmitMODF_KR() cc.movsd(tmp, x86::ptr(ToMemAddress(&konstf[B]))); auto result = newResultXmmSd(); - auto call = CreateCall([](double a, double b) -> double { - return a - floor(a / b) * b; - }); + auto call = CreateCall(DoubleModF); call->setRet(0, result); call->setArg(0, tmp); call->setArg(1, regF[C]); diff --git a/src/scripting/vm/jit_move.cpp b/src/scripting/vm/jit_move.cpp index 9b82f4411..fc70bf5d4 100644 --- a/src/scripting/vm/jit_move.cpp +++ b/src/scripting/vm/jit_move.cpp @@ -38,6 +38,23 @@ void JitCompiler::EmitMOVEV3() cc.movsd(regF[A + 2], regF[B + 2]); } +static void CastI2S(FString *a, int b) { a->Format("%d", b); } +static void CastU2S(FString *a, int b) { a->Format("%u", b); } +static void CastF2S(FString *a, double b) { a->Format("%.5f", b); } +static void CastV22S(FString *a, double b, double b1) { a->Format("(%.5f, %.5f)", b, b1); } +static void CastV32S(FString *a, double b, double b1, double b2) { a->Format("(%.5f, %.5f, %.5f)", b, b1, b2); } +static void CastP2S(FString *a, void *b) { if (b == nullptr) *a = "null"; else a->Format("%p", b); } +static int CastS2I(FString *b) { return (VM_SWORD)b->ToLong(); } +static double CastS2F(FString *b) { return b->ToDouble(); } +static int CastS2N(FString *b) { return b->Len() == 0 ? FName(NAME_None) : FName(*b); } +static void CastN2S(FString *a, int b) { FName name = FName(ENamedName(b)); *a = name.IsValidName() ? name.GetChars() : ""; } +static int CastS2Co(FString *b) { return V_GetColor(nullptr, *b); } +static void CastCo2S(FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %02x", c.r, c.g, c.b); } +static int CastS2So(FString *b) { return FSoundID(*b); } +static void CastSo2S(FString *a, int b) { *a = S_sfx[b].name; } +static void CastSID2S(FString *a, unsigned int b) { *a = (b >= sprites.Size()) ? "TNT1" : sprites[b].name; } +static void CastTID2S(FString *a, int b) { auto tex = TexMan[*(FTextureID*)&b]; *a = (tex == nullptr) ? "(null)" : tex->Name.GetChars(); } + void JitCompiler::EmitCAST() { asmjit::X86Gp tmp, resultD; @@ -64,95 +81,95 @@ void JitCompiler::EmitCAST() cc.mov(regD[A], tmp.r32()); break; case CAST_I2S: - call = CreateCall([](FString *a, int b) { a->Format("%d", b); }); + call = CreateCall(CastI2S); call->setArg(0, regS[A]); call->setArg(1, regD[B]); break; case CAST_U2S: - call = CreateCall([](FString *a, int b) { a->Format("%u", b); }); + call = CreateCall(CastU2S); call->setArg(0, regS[A]); call->setArg(1, regD[B]); break; case CAST_F2S: - call = CreateCall([](FString *a, double b) { a->Format("%.5f", b); }); + call = CreateCall(CastF2S); call->setArg(0, regS[A]); call->setArg(1, regF[B]); break; case CAST_V22S: - call = CreateCall([](FString *a, double b, double b1) { a->Format("(%.5f, %.5f)", b, b1); }); + call = CreateCall(CastV22S); call->setArg(0, regS[A]); call->setArg(1, regF[B]); call->setArg(2, regF[B + 1]); break; case CAST_V32S: - call = CreateCall([](FString *a, double b, double b1, double b2) { a->Format("(%.5f, %.5f, %.5f)", b, b1, b2); }); + call = CreateCall(CastV32S); call->setArg(0, regS[A]); call->setArg(1, regF[B]); call->setArg(2, regF[B + 1]); call->setArg(3, regF[B + 2]); break; case CAST_P2S: - call = CreateCall([](FString *a, void *b) { if (b == nullptr) *a = "null"; else a->Format("%p", b); }); + call = CreateCall(CastP2S); call->setArg(0, regS[A]); call->setArg(1, regA[B]); break; case CAST_S2I: resultD = newResultInt32(); - call = CreateCall([](FString *b) -> int { return (VM_SWORD)b->ToLong(); }); + call = CreateCall(CastS2I); call->setRet(0, resultD); call->setArg(0, regS[B]); cc.mov(regD[A], resultD); break; case CAST_S2F: resultF = newResultXmmSd(); - call = CreateCall([](FString *b) -> double { return b->ToDouble(); }); + call = CreateCall(CastS2F); call->setRet(0, resultF); call->setArg(0, regS[B]); cc.movsd(regF[A], resultF); break; case CAST_S2N: resultD = newResultInt32(); - call = CreateCall([](FString *b) -> int { return b->Len() == 0 ? FName(NAME_None) : FName(*b); }); + call = CreateCall(CastS2N); call->setRet(0, resultD); call->setArg(0, regS[B]); cc.mov(regD[A], resultD); break; case CAST_N2S: - call = CreateCall([](FString *a, int b) { FName name = FName(ENamedName(b)); *a = name.IsValidName() ? name.GetChars() : ""; }); + call = CreateCall(CastN2S); call->setArg(0, regS[A]); call->setArg(1, regD[B]); break; case CAST_S2Co: resultD = newResultInt32(); - call = CreateCall([](FString *b) -> int { return V_GetColor(nullptr, *b); }); + call = CreateCall(CastS2Co); call->setRet(0, resultD); call->setArg(0, regS[B]); cc.mov(regD[A], resultD); break; case CAST_Co2S: - call = CreateCall([](FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %02x", c.r, c.g, c.b); }); + call = CreateCall(CastCo2S); call->setArg(0, regS[A]); call->setArg(1, regD[B]); break; case CAST_S2So: resultD = newResultInt32(); - call = CreateCall([](FString *b) -> int { return FSoundID(*b); }); + call = CreateCall(CastS2So); call->setRet(0, resultD); call->setArg(0, regS[B]); cc.mov(regD[A], resultD); break; case CAST_So2S: - call = CreateCall([](FString *a, int b) { *a = S_sfx[b].name; }); + call = CreateCall(CastSo2S); call->setArg(0, regS[A]); call->setArg(1, regD[B]); break; case CAST_SID2S: - call = CreateCall([](FString *a, unsigned int b) { *a = (b >= sprites.Size()) ? "TNT1" : sprites[b].name; }); + call = CreateCall(CastSID2S); call->setArg(0, regS[A]); call->setArg(1, regD[B]); break; case CAST_TID2S: - call = CreateCall([](FString *a, int b) { auto tex = TexMan[*(FTextureID*)&b]; *a = (tex == nullptr) ? "(null)" : tex->Name.GetChars(); }); + call = CreateCall(CastTID2S); call->setArg(0, regS[A]); call->setArg(1, regD[B]); break; @@ -161,6 +178,8 @@ void JitCompiler::EmitCAST() } } +static int CastB_S(FString *s) { return s->Len() > 0; } + void JitCompiler::EmitCASTB() { if (C == CASTB_I) @@ -189,19 +208,22 @@ void JitCompiler::EmitCASTB() else { auto result = newResultInt32(); - auto call = CreateCall([](FString *s) -> int { return s->Len() > 0; }); + auto call = CreateCall(CastB_S); call->setRet(0, result); call->setArg(0, regS[B]); cc.mov(regD[A], result); } } +static DObject *DynCast(DObject *obj, PClass *cls) +{ + return (obj && obj->IsKindOf(cls)) ? obj : nullptr; +} + void JitCompiler::EmitDYNCAST_R() { auto result = newResultIntPtr(); - auto call = CreateCall([](DObject *obj, PClass *cls) -> DObject* { - return (obj && obj->IsKindOf(cls)) ? obj : nullptr; - }); + auto call = CreateCall(DynCast); call->setRet(0, result); call->setArg(0, regA[B]); call->setArg(1, regA[C]); @@ -213,21 +235,22 @@ void JitCompiler::EmitDYNCAST_K() auto result = newResultIntPtr(); auto c = newTempIntPtr(); cc.mov(c, asmjit::imm_ptr(konsta[C].o)); - auto call = CreateCall([](DObject *obj, PClass *cls) -> DObject* { - return (obj && obj->IsKindOf(cls)) ? obj : nullptr; - }); + auto call = CreateCall(DynCast); call->setRet(0, result); call->setArg(0, regA[B]); call->setArg(1, c); cc.mov(regA[A], result); } +static PClass *DynCastC(PClass *cls1, PClass *cls2) +{ + return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr; +} + void JitCompiler::EmitDYNCASTC_R() { auto result = newResultIntPtr(); - auto call = CreateCall([](PClass *cls1, PClass *cls2) -> PClass* { - return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr; - }); + auto call = CreateCall(DynCastC); call->setRet(0, result); call->setArg(0, regA[B]); call->setArg(1, regA[C]); @@ -241,9 +264,7 @@ void JitCompiler::EmitDYNCASTC_K() auto c = newTempIntPtr(); cc.mov(c, asmjit::imm_ptr(konsta[C].o)); typedef PClass*(*FuncPtr)(PClass*, PClass*); - auto call = CreateCall([](PClass *cls1, PClass *cls2) -> PClass* { - return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr; - }); + auto call = CreateCall(DynCastC); call->setRet(0, result); call->setArg(0, regA[B]); call->setArg(1, c); diff --git a/src/scripting/vm/jitintern.h b/src/scripting/vm/jitintern.h index 1e70ec6ed..69422557f 100644 --- a/src/scripting/vm/jitintern.h +++ b/src/scripting/vm/jitintern.h @@ -43,7 +43,6 @@ private: void IncrementVMCalls(); void SetupFrame(); void SetupSimpleFrame(); - void SetupSimpleFrameMissingArgs(); void SetupFullVMFrame(); void BindLabels(); void EmitOpcode(); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 828909779..e498d4c14 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -209,8 +209,6 @@ struct VMValue const FString *sp; }; - // Unfortunately, FString cannot be used directly. - // Fortunately, it is relatively simple. const FString &s() const { return *sp; } VMValue() @@ -376,6 +374,12 @@ private: }; int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults/*, VMException **trap = NULL*/); +int VMCallWithDefaults(VMFunction *func, TArray ¶ms, VMReturn *results, int numresults/*, VMException **trap = NULL*/); + +inline int VMCallAction(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults/*, VMException **trap = NULL*/) +{ + return VMCall(func, params, numparams, results, numresults); +} // Use this in the prototype for a native function. #define VM_ARGS VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 374911ec6..72046d0a2 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -221,10 +221,24 @@ int VMScriptFunction::PCToLine(const VMOP *pc) return -1; } +static bool CanJit(VMScriptFunction *func) +{ + // Asmjit has a 256 register limit. Stay safely away from it as the jit compiler uses a few for temporaries as well. + // Any function exceeding the limit will use the VM - a fair punishment to someone for writing a function so bloated ;) + + int maxregs = 200; + if (func->NumRegA + func->NumRegD + func->NumRegF + func->NumRegS < maxregs) + return true; + + Printf(TEXTCOLOR_ORANGE "%s is using too many registers (%d of max %d)! Function will not use native code.\n", func->PrintableName.GetChars(), func->NumRegA + func->NumRegD + func->NumRegF + func->NumRegS, maxregs); + + return false; +} + int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret) { #ifdef ARCH_X64 - if (vm_jit) + if (vm_jit && CanJit(static_cast(func))) { func->ScriptCall = JitCompile(static_cast(func)); if (!func->ScriptCall) @@ -577,6 +591,18 @@ int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results, #endif } +int VMCallWithDefaults(VMFunction *func, TArray ¶ms, VMReturn *results, int numresults/*, VMException **trap = NULL*/) +{ + if (func->DefaultArgs.Size() > params.Size()) + { + auto oldp = params.Size(); + params.Resize(func->DefaultArgs.Size()); + memcpy(¶ms[oldp], &func->DefaultArgs[oldp], (params.Size() - oldp) * sizeof(VMValue)); + } + return VMCall(func, params.Data(), params.Size(), results, numresults); +} + + // Exception stuff for the VM is intentionally placed there, because having this in vmexec.cpp would subject it to inlining // which we do not want because it increases the local stack requirements of Exec which are already too high. FString CVMAbortException::stacktrace; diff --git a/src/tarray.h b/src/tarray.h index 167f85fa9..8acb083de 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -278,13 +278,30 @@ public: return Count++; } - void Append(const TArray &item) + unsigned Append(const TArray &item) { - unsigned start = Reserve(item.Size()); + unsigned start = Count; + + Grow(item.Size()); + for (unsigned i = 0; i < item.Size(); i++) { - Array[start + i] = item[i]; + new(&Array[start + i]) T(item[i]); } + return start; + } + + unsigned Append(TArray &&item) + { + unsigned start = Count; + + Grow(item.Size()); + + for (unsigned i = 0; i < item.Size(); i++) + { + new(&Array[start + i]) T(std::move(item[i])); + } + return start; } bool Pop ()