This commit is contained in:
Rachael Alexanderson 2018-11-17 00:33:18 -05:00
commit e2e0b0c15f
17 changed files with 434 additions and 338 deletions

View file

@ -148,6 +148,7 @@ void FState::CheckCallerType(AActor *self, AActor *stateowner)
}
}
TArray<VMValue> 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)

View file

@ -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<PFunction>(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<PFunction>(c->FindSymbol("Init", false));
VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
auto unsafe = dyn_cast<PField>(c->FindSymbol("mUnsafe", false));

View file

@ -477,7 +477,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc)
}
DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew();
params[0] = item;
VMCall(func->Variants[0].Implementation, &params[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, &params[0], params.Size(), nullptr, 0);
VMCallWithDefaults(func->Variants[0].Implementation, params, nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
success = true;

View file

@ -827,6 +827,7 @@ xx(Key)
// Decorate compatibility functions
xx(BuiltinTypeCheck)
xx(BuiltinRandom)
xx(BuiltinRandom2)
xx(BuiltinFRandom)
xx(BuiltinCallLineSpecial)
xx(BuiltinNameToClass)

View file

@ -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, &params[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, &params[0], params.Size(), &ret, 1);
VMCallWithDefaults(func, params, &ret, 1);
retval = DoubleToACS(d);
}
else if (rettype == TypeString)
{
FString d;
VMReturn ret(&d);
VMCall(func, &params[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, &params[0], params.Size(), nullptr, 0);
VMCallWithDefaults(func, params, nullptr, 0);
}
}
}

View file

@ -96,12 +96,13 @@ static FRandom pr_bfgselfdamage("BFGSelfDamage");
// until there is no next state
//
//==========================================================================
extern TArray<VMValue> 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)
{

View file

@ -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<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
{
assert(numparam >= 1 && numparam <= 3);
FRandom *rng = reinterpret_cast<FRandom *>(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<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
{
assert(numparam == 1 || numparam == 3);
FRandom *rng = reinterpret_cast<FRandom *>(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<VMValue> &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<VMValue> &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<AActor*>(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();

View file

@ -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;

View file

@ -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<void, VMFrame *, VMValue *, int>([](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<VMFrameStack *, VMScriptFunction *, VMValue *, int>([](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<VMFrameStack *, VMScriptFunction *, VMValue *, int>(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<void, VMFrameStack *>([](VMFrameStack *stack) {
try
{
stack->PopFrame();
CurrentJitExceptInfo->vmframes--;
}
catch (...)
{
VMThrowException(std::current_exception());
}
});
auto popFrame = CreateCall<void, VMFrameStack *>(PopFullVMFrame);
popFrame->setArg(0, stack);
}
}

View file

@ -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<VMFunction*, DObject*, int>([](DObject *o, int c) -> VMFunction* {
auto p = o->GetClass();
assert(c < (int)p->Virtuals.Size());
return p->Virtuals[c];
});
auto call = CreateCall<VMFunction*, DObject*, int>(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<void, DObject*, VMFunction*, int>([](DObject *o, VMFunction *f, int b) {
try
{
FScopeBarrier::ValidateCall(o->GetClass(), f, b - 1);
}
catch (...)
{
VMThrowException(std::current_exception());
}
});
auto call = CreateCall<void, DObject*, VMFunction*, int>(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<void, VMReturn*, FString*>([](VMReturn* ret, FString* str) -> void {
ret->SetString(*str);
});
auto call = CreateCall<void, VMReturn*, FString*>(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<DObject*, PClass*, int>([](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<DObject*, PClass*, int>(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<void, PClass*, int>([](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<void, PClass*, int>(ThrowNewK);
call->setArg(0, regcls);
}
else
{
auto result = newResultIntPtr();
auto call = CreateCall<DObject*, PClass*, int>([](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<DObject*, PClass*, int>(CreateNewK);
call->setRet(0, result);
call->setArg(0, regcls);
call->setArg(1, asmjit::Imm(C));

View file

@ -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<uint8_t*, DObject*>([](DObject *o) { return o->GetClass()->Meta; });
auto call = CreateCall<uint8_t*, DObject*>(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<PClass*, DObject*>([](DObject *o) { return o->GetClass(); });
auto call = CreateCall<PClass*, DObject*>(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*,DObject*>([](DObject *p) { return GC::ReadBarrier(p); });
auto call = CreateCall<DObject*, DObject*>(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*, DObject*>([](DObject *p) { return GC::ReadBarrier(p); });
auto call = CreateCall<DObject*, DObject*>(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<void, FString*, char**>([](FString* to, char** from) { *to = *from; });
auto call = CreateCall<void, FString*, char**>(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<void, FString*, char**>([](FString* to, char** from) { *to = *from; });
auto call = CreateCall<void, FString*, char**>(SetString);
call->setArg(0, regS[A]);
call->setArg(1, ptr);
}

View file

@ -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<void, FString*, FString*, FString*>([](FString* to, FString* first, FString* second) {
*to = *first + *second;
});
auto call = CreateCall<void, FString*, FString*, FString*>(ConcatString);
call->setArg(0, regS[A]);
call->setArg(1, regS[B]);
call->setArg(2, rc);
}
static int StringLength(FString* str)
{
return static_cast<int>(str->Len());
}
void JitCompiler::EmitLENS()
{
auto result = newResultInt32();
auto call = CreateCall<int, FString*>([](FString* str) -> int {
return static_cast<int>(str->Len());
});
auto call = CreateCall<int, FString*>(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<bool>(A & CMP_APPROX) ?
CreateCall<int, FString*, FString*>(compareNoCaseLambda) :
CreateCall<int, FString*, FString*>(compareLambda);
auto call = CreateCall<int, FString*, FString*>(static_cast<bool>(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, double, double>([](double a, double b) -> double
{
return a - floor(a / b) * b;
});
auto call = CreateCall<double, double, double>(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, double, double>([](double a, double b) -> double {
return a - floor(a / b) * b;
});
auto call = CreateCall<double, double, double>(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, double, double>([](double a, double b) -> double {
return a - floor(a / b) * b;
});
auto call = CreateCall<double, double, double>(DoubleModF);
call->setRet(0, result);
call->setArg(0, tmp);
call->setArg(1, regF[C]);

View file

@ -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<void, FString*, int>([](FString *a, int b) { a->Format("%d", b); });
call = CreateCall<void, FString*, int>(CastI2S);
call->setArg(0, regS[A]);
call->setArg(1, regD[B]);
break;
case CAST_U2S:
call = CreateCall<void, FString*, int>([](FString *a, int b) { a->Format("%u", b); });
call = CreateCall<void, FString*, int>(CastU2S);
call->setArg(0, regS[A]);
call->setArg(1, regD[B]);
break;
case CAST_F2S:
call = CreateCall<void, FString*, double>([](FString *a, double b) { a->Format("%.5f", b); });
call = CreateCall<void, FString*, double>(CastF2S);
call->setArg(0, regS[A]);
call->setArg(1, regF[B]);
break;
case CAST_V22S:
call = CreateCall<void, FString*, double, double>([](FString *a, double b, double b1) { a->Format("(%.5f, %.5f)", b, b1); });
call = CreateCall<void, FString*, double, double>(CastV22S);
call->setArg(0, regS[A]);
call->setArg(1, regF[B]);
call->setArg(2, regF[B + 1]);
break;
case CAST_V32S:
call = CreateCall<void, FString*, double, double, double>([](FString *a, double b, double b1, double b2) { a->Format("(%.5f, %.5f, %.5f)", b, b1, b2); });
call = CreateCall<void, FString*, double, double, double>(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<void, FString*, void*>([](FString *a, void *b) { if (b == nullptr) *a = "null"; else a->Format("%p", b); });
call = CreateCall<void, FString*, void*>(CastP2S);
call->setArg(0, regS[A]);
call->setArg(1, regA[B]);
break;
case CAST_S2I:
resultD = newResultInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return (VM_SWORD)b->ToLong(); });
call = CreateCall<int, FString*>(CastS2I);
call->setRet(0, resultD);
call->setArg(0, regS[B]);
cc.mov(regD[A], resultD);
break;
case CAST_S2F:
resultF = newResultXmmSd();
call = CreateCall<double, FString*>([](FString *b) -> double { return b->ToDouble(); });
call = CreateCall<double, FString*>(CastS2F);
call->setRet(0, resultF);
call->setArg(0, regS[B]);
cc.movsd(regF[A], resultF);
break;
case CAST_S2N:
resultD = newResultInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return b->Len() == 0 ? FName(NAME_None) : FName(*b); });
call = CreateCall<int, FString*>(CastS2N);
call->setRet(0, resultD);
call->setArg(0, regS[B]);
cc.mov(regD[A], resultD);
break;
case CAST_N2S:
call = CreateCall<void, FString*, int>([](FString *a, int b) { FName name = FName(ENamedName(b)); *a = name.IsValidName() ? name.GetChars() : ""; });
call = CreateCall<void, FString*, int>(CastN2S);
call->setArg(0, regS[A]);
call->setArg(1, regD[B]);
break;
case CAST_S2Co:
resultD = newResultInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return V_GetColor(nullptr, *b); });
call = CreateCall<int, FString*>(CastS2Co);
call->setRet(0, resultD);
call->setArg(0, regS[B]);
cc.mov(regD[A], resultD);
break;
case CAST_Co2S:
call = CreateCall<void, FString*, int>([](FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %02x", c.r, c.g, c.b); });
call = CreateCall<void, FString*, int>(CastCo2S);
call->setArg(0, regS[A]);
call->setArg(1, regD[B]);
break;
case CAST_S2So:
resultD = newResultInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return FSoundID(*b); });
call = CreateCall<int, FString*>(CastS2So);
call->setRet(0, resultD);
call->setArg(0, regS[B]);
cc.mov(regD[A], resultD);
break;
case CAST_So2S:
call = CreateCall<void, FString*, int>([](FString *a, int b) { *a = S_sfx[b].name; });
call = CreateCall<void, FString*, int>(CastSo2S);
call->setArg(0, regS[A]);
call->setArg(1, regD[B]);
break;
case CAST_SID2S:
call = CreateCall<void, FString*, unsigned int>([](FString *a, unsigned int b) { *a = (b >= sprites.Size()) ? "TNT1" : sprites[b].name; });
call = CreateCall<void, FString*, unsigned int>(CastSID2S);
call->setArg(0, regS[A]);
call->setArg(1, regD[B]);
break;
case CAST_TID2S:
call = CreateCall<void, FString*, int>([](FString *a, int b) { auto tex = TexMan[*(FTextureID*)&b]; *a = (tex == nullptr) ? "(null)" : tex->Name.GetChars(); });
call = CreateCall<void, FString*, int>(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<int, FString*>([](FString *s) -> int { return s->Len() > 0; });
auto call = CreateCall<int, FString*>(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*, DObject*, PClass*>([](DObject *obj, PClass *cls) -> DObject* {
return (obj && obj->IsKindOf(cls)) ? obj : nullptr;
});
auto call = CreateCall<DObject*, DObject*, PClass*>(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*, DObject*, PClass*>([](DObject *obj, PClass *cls) -> DObject* {
return (obj && obj->IsKindOf(cls)) ? obj : nullptr;
});
auto call = CreateCall<DObject*, DObject*, PClass*>(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*, PClass*, PClass*>([](PClass *cls1, PClass *cls2) -> PClass* {
return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr;
});
auto call = CreateCall<PClass*, PClass*, PClass*>(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*, PClass*, PClass*>([](PClass *cls1, PClass *cls2) -> PClass* {
return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr;
});
auto call = CreateCall<PClass*, PClass*, PClass*>(DynCastC);
call->setRet(0, result);
call->setArg(0, regA[B]);
call->setArg(1, c);

View file

@ -43,7 +43,6 @@ private:
void IncrementVMCalls();
void SetupFrame();
void SetupSimpleFrame();
void SetupSimpleFrameMissingArgs();
void SetupFullVMFrame();
void BindLabels();
void EmitOpcode();

View file

@ -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<VMValue> &params, 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<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret

View file

@ -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<VMScriptFunction*>(func)))
{
func->ScriptCall = JitCompile(static_cast<VMScriptFunction*>(func));
if (!func->ScriptCall)
@ -577,6 +591,18 @@ int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results,
#endif
}
int VMCallWithDefaults(VMFunction *func, TArray<VMValue> &params, VMReturn *results, int numresults/*, VMException **trap = NULL*/)
{
if (func->DefaultArgs.Size() > params.Size())
{
auto oldp = params.Size();
params.Resize(func->DefaultArgs.Size());
memcpy(&params[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;

View file

@ -278,13 +278,30 @@ public:
return Count++;
}
void Append(const TArray<T> &item)
unsigned Append(const TArray<T> &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<T> &&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 ()