mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-01-31 13:00:59 +00:00
- moved the type infomation entirely out of VMValue.
For the varargs functions that used the Type field to validate their parameters, now a hidden additional argument is passed which contains a byte array with the type info for the current call's arguments. Since this is static per call location it can be better prepared once when the code is being compiled instead of being put in a runtime created array for each invocation. Everything else uses the per-function instance of the same data. The only thing that still needed the type field with a VMValue is the defaults array, so this uses a different struct type now to store its data.
This commit is contained in:
parent
a981737855
commit
a9ec819557
18 changed files with 265 additions and 164 deletions
|
@ -62,7 +62,6 @@
|
||||||
#include "g_levellocals.h"
|
#include "g_levellocals.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
FString FStringFormat(VM_ARGS); // extern from thingdef_data.cpp
|
|
||||||
|
|
||||||
#include "gi.h"
|
#include "gi.h"
|
||||||
|
|
||||||
|
@ -1294,7 +1293,9 @@ DEFINE_ACTION_FUNCTION(_Console, HideConsole)
|
||||||
DEFINE_ACTION_FUNCTION(_Console, Printf)
|
DEFINE_ACTION_FUNCTION(_Console, Printf)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
FString s = FStringFormat(param, numparam, ret, numret);
|
PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array
|
||||||
|
|
||||||
|
FString s = FStringFormat(VM_ARGS_NAMES);
|
||||||
Printf("%s\n", s.GetChars());
|
Printf("%s\n", s.GetChars());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -777,14 +777,13 @@ void SetDehParams(FState *state, int codepointer)
|
||||||
// self, stateowner, state (all are pointers)
|
// self, stateowner, state (all are pointers)
|
||||||
buildit.Registers[REGT_POINTER].Get(numargs);
|
buildit.Registers[REGT_POINTER].Get(numargs);
|
||||||
// Emit code to pass the standard action function parameters.
|
// Emit code to pass the standard action function parameters.
|
||||||
FunctionCallEmitter emitters;
|
FunctionCallEmitter emitters(sym->Variants[0].Implementation);
|
||||||
for (int i = 0; i < numargs; i++)
|
for (int i = 0; i < numargs; i++)
|
||||||
{
|
{
|
||||||
emitters.AddParameterPointer(i, false);
|
emitters.AddParameterPointer(i, false);
|
||||||
}
|
}
|
||||||
// Emit code for action parameters.
|
// Emit code for action parameters.
|
||||||
MBFCodePointerFactories[codepointer](emitters, value1, value2);
|
MBFCodePointerFactories[codepointer](emitters, value1, value2);
|
||||||
emitters.AddTarget(sym->Variants[0].Implementation);
|
|
||||||
emitters.EmitCall(&buildit);
|
emitters.EmitCall(&buildit);
|
||||||
buildit.Emit(OP_RET, RET_FINAL, REGT_NIL, 0);
|
buildit.Emit(OP_RET, RET_FINAL, REGT_NIL, 0);
|
||||||
// Attach it to the state.
|
// Attach it to the state.
|
||||||
|
|
|
@ -181,7 +181,13 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info,
|
||||||
|
|
||||||
if (ActionFunc->DefaultArgs.Size() > 0)
|
if (ActionFunc->DefaultArgs.Size() > 0)
|
||||||
{
|
{
|
||||||
auto index = actionParams.Append(ActionFunc->DefaultArgs);
|
auto defs = ActionFunc->DefaultArgs;
|
||||||
|
auto index = actionParams.Reserve(defs.Size());
|
||||||
|
for (unsigned i = 0; i < defs.Size(); i++)
|
||||||
|
{
|
||||||
|
actionParams[i + index] = defs[i];
|
||||||
|
}
|
||||||
|
|
||||||
if (ActionFunc->ImplicitArgs >= 1)
|
if (ActionFunc->ImplicitArgs >= 1)
|
||||||
{
|
{
|
||||||
actionParams[index] = self;
|
actionParams[index] = self;
|
||||||
|
|
|
@ -175,7 +175,13 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state)
|
||||||
|
|
||||||
if (state->ActionFunc->DefaultArgs.Size() > 0)
|
if (state->ActionFunc->DefaultArgs.Size() > 0)
|
||||||
{
|
{
|
||||||
auto index = actionParams.Append(state->ActionFunc->DefaultArgs);
|
auto defs = state->ActionFunc->DefaultArgs;
|
||||||
|
auto index = actionParams.Reserve(defs.Size());
|
||||||
|
for (unsigned i = 0; i < defs.Size(); i++)
|
||||||
|
{
|
||||||
|
actionParams[i + index] = defs[i];
|
||||||
|
}
|
||||||
|
|
||||||
if (state->ActionFunc->ImplicitArgs >= 1)
|
if (state->ActionFunc->ImplicitArgs >= 1)
|
||||||
{
|
{
|
||||||
actionParams[index] = actor;
|
actionParams[index] = actor;
|
||||||
|
|
|
@ -5471,7 +5471,7 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int BuiltinRandom(VMValue *param, int numparam, VMReturn *ret, int numret)
|
int BuiltinRandom(VM_ARGS)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
PARAM_POINTER(rng, FRandom);
|
PARAM_POINTER(rng, FRandom);
|
||||||
|
@ -5496,12 +5496,11 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build)
|
||||||
assert(min && max);
|
assert(min && max);
|
||||||
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||||
|
|
||||||
FunctionCallEmitter emitters;
|
FunctionCallEmitter emitters(callfunc);
|
||||||
|
|
||||||
emitters.AddParameterPointerConst(rng);
|
emitters.AddParameterPointerConst(rng);
|
||||||
emitters.AddParameter(build, min);
|
emitters.AddParameter(build, min);
|
||||||
emitters.AddParameter(build, max);
|
emitters.AddParameter(build, max);
|
||||||
emitters.AddTarget(callfunc);
|
|
||||||
emitters.AddReturn(REGT_INT);
|
emitters.AddReturn(REGT_INT);
|
||||||
return emitters.EmitCall(build);
|
return emitters.EmitCall(build);
|
||||||
}
|
}
|
||||||
|
@ -5604,11 +5603,10 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
|
||||||
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
||||||
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||||
|
|
||||||
FunctionCallEmitter emitters;
|
FunctionCallEmitter emitters(callfunc);
|
||||||
emitters.AddParameterPointerConst(rng);
|
emitters.AddParameterPointerConst(rng);
|
||||||
emitters.AddParameterIntConst(0);
|
emitters.AddParameterIntConst(0);
|
||||||
emitters.AddParameterIntConst(choices.Size() - 1);
|
emitters.AddParameterIntConst(choices.Size() - 1);
|
||||||
emitters.AddTarget(callfunc);
|
|
||||||
emitters.AddReturn(REGT_INT);
|
emitters.AddReturn(REGT_INT);
|
||||||
auto resultreg = emitters.EmitCall(build);
|
auto resultreg = emitters.EmitCall(build);
|
||||||
|
|
||||||
|
@ -5696,7 +5694,7 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int BuiltinFRandom(VMValue *param, int numparam, VMReturn *ret, int numret)
|
int BuiltinFRandom(VM_ARGS)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
PARAM_POINTER(rng, FRandom);
|
PARAM_POINTER(rng, FRandom);
|
||||||
|
@ -5725,11 +5723,10 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build)
|
||||||
assert(min && max);
|
assert(min && max);
|
||||||
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||||
|
|
||||||
FunctionCallEmitter emitters;
|
FunctionCallEmitter emitters(callfunc);
|
||||||
emitters.AddParameterPointerConst(rng);
|
emitters.AddParameterPointerConst(rng);
|
||||||
emitters.AddParameter(build, min);
|
emitters.AddParameter(build, min);
|
||||||
emitters.AddParameter(build, max);
|
emitters.AddParameter(build, max);
|
||||||
emitters.AddTarget(callfunc);
|
|
||||||
emitters.AddReturn(REGT_FLOAT);
|
emitters.AddReturn(REGT_FLOAT);
|
||||||
return emitters.EmitCall(build);
|
return emitters.EmitCall(build);
|
||||||
}
|
}
|
||||||
|
@ -5779,7 +5776,7 @@ FxExpression *FxRandom2::Resolve(FCompileContext &ctx)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int BuiltinRandom2(VMValue *param, int numparam, VMReturn *ret, int numret)
|
int BuiltinRandom2(VM_ARGS)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
PARAM_POINTER(rng, FRandom);
|
PARAM_POINTER(rng, FRandom);
|
||||||
|
@ -5804,11 +5801,10 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build)
|
||||||
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
||||||
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||||
|
|
||||||
FunctionCallEmitter emitters;
|
FunctionCallEmitter emitters(callfunc);
|
||||||
|
|
||||||
emitters.AddParameterPointerConst(rng);
|
emitters.AddParameterPointerConst(rng);
|
||||||
emitters.AddParameter(build, mask);
|
emitters.AddParameter(build, mask);
|
||||||
emitters.AddTarget(callfunc);
|
|
||||||
emitters.AddReturn(REGT_INT);
|
emitters.AddReturn(REGT_INT);
|
||||||
return emitters.EmitCall(build);
|
return emitters.EmitCall(build);
|
||||||
}
|
}
|
||||||
|
@ -5857,7 +5853,7 @@ FxExpression *FxRandomSeed::Resolve(FCompileContext &ctx)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int BuiltinRandomSeed(VMValue *param, int numparam, VMReturn *ret, int numret)
|
int BuiltinRandomSeed(VM_ARGS)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
PARAM_POINTER(rng, FRandom)
|
PARAM_POINTER(rng, FRandom)
|
||||||
|
@ -5877,11 +5873,9 @@ ExpEmit FxRandomSeed::Emit(VMFunctionBuilder *build)
|
||||||
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
||||||
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||||
|
|
||||||
FunctionCallEmitter emitters;
|
FunctionCallEmitter emitters(callfunc);
|
||||||
|
|
||||||
emitters.AddParameterPointerConst(rng);
|
emitters.AddParameterPointerConst(rng);
|
||||||
emitters.AddParameter(build, seed);
|
emitters.AddParameter(build, seed);
|
||||||
emitters.AddTarget(callfunc);
|
|
||||||
return emitters.EmitCall(build);
|
return emitters.EmitCall(build);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6320,7 +6314,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
||||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
|
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
|
||||||
auto sn = static_cast<PSymbolConstNumeric*>(sym);
|
auto sn = static_cast<PSymbolConstNumeric*>(sym);
|
||||||
|
|
||||||
VMValue vmv;
|
TypedVMValue vmv;
|
||||||
if (sn->ValueType->isIntCompatible()) vmv = sn->Value;
|
if (sn->ValueType->isIntCompatible()) vmv = sn->Value;
|
||||||
else vmv = sn->Float;
|
else vmv = sn->Float;
|
||||||
auto x = new FxConstant(sn->ValueType, vmv, ScriptPosition);
|
auto x = new FxConstant(sn->ValueType, vmv, ScriptPosition);
|
||||||
|
@ -8526,7 +8520,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int BuiltinCallLineSpecial(VMValue *param, int numparam, VMReturn *ret, int numret)
|
int BuiltinCallLineSpecial(VM_ARGS)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
PARAM_INT(special);
|
PARAM_INT(special);
|
||||||
|
@ -8544,7 +8538,15 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
|
|
||||||
FunctionCallEmitter emitters;
|
// Call the BuiltinCallLineSpecial function to perform the desired special.
|
||||||
|
static uint8_t reginfo[] = { REGT_INT, REGT_POINTER, REGT_INT, REGT_INT, REGT_INT, REGT_INT, REGT_INT };
|
||||||
|
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial, BuiltinCallLineSpecial, reginfo);
|
||||||
|
|
||||||
|
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||||
|
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
||||||
|
VMFunction *callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||||
|
|
||||||
|
FunctionCallEmitter emitters(callfunc);
|
||||||
|
|
||||||
emitters.AddParameterIntConst(abs(Special)); // pass special number
|
emitters.AddParameterIntConst(abs(Special)); // pass special number
|
||||||
emitters.AddParameter(build, Self);
|
emitters.AddParameter(build, Self);
|
||||||
|
@ -8571,18 +8573,9 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Call the BuiltinCallLineSpecial function to perform the desired special.
|
|
||||||
VMFunction *callfunc;
|
|
||||||
static uint8_t reginfo[] = { REGT_INT, REGT_POINTER, REGT_INT, REGT_INT, REGT_INT, REGT_INT, REGT_INT };
|
|
||||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial, BuiltinCallLineSpecial, reginfo);
|
|
||||||
|
|
||||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
|
||||||
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
|
||||||
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
|
||||||
ArgList.DeleteAndClear();
|
ArgList.DeleteAndClear();
|
||||||
ArgList.ShrinkToFit();
|
ArgList.ShrinkToFit();
|
||||||
|
|
||||||
emitters.AddTarget(callfunc);
|
|
||||||
emitters.AddReturn(REGT_INT);
|
emitters.AddReturn(REGT_INT);
|
||||||
return emitters.EmitCall(build);
|
return emitters.EmitCall(build);
|
||||||
}
|
}
|
||||||
|
@ -8989,7 +8982,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
bool staticcall = ((vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual);
|
bool staticcall = ((vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual);
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
FunctionCallEmitter emitters;
|
FunctionCallEmitter emitters(vmfunc);
|
||||||
// Emit code to pass implied parameters
|
// Emit code to pass implied parameters
|
||||||
ExpEmit selfemit;
|
ExpEmit selfemit;
|
||||||
if (Function->Variants[0].Flags & VARF_Method)
|
if (Function->Variants[0].Flags & VARF_Method)
|
||||||
|
@ -9063,7 +9056,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
ArgList.DeleteAndClear();
|
ArgList.DeleteAndClear();
|
||||||
ArgList.ShrinkToFit();
|
ArgList.ShrinkToFit();
|
||||||
|
|
||||||
emitters.AddTarget(vmfunc, staticcall? -1 : selfemit.RegNum);
|
if (!staticcall) emitters.SetVirtualReg(selfemit.RegNum);
|
||||||
int resultcount = vmfunc->Proto->ReturnTypes.Size() == 0 ? 0 : MAX(AssignCount, 1);
|
int resultcount = vmfunc->Proto->ReturnTypes.Size() == 0 ? 0 : MAX(AssignCount, 1);
|
||||||
|
|
||||||
assert((unsigned)resultcount <= vmfunc->Proto->ReturnTypes.Size());
|
assert((unsigned)resultcount <= vmfunc->Proto->ReturnTypes.Size());
|
||||||
|
@ -10582,9 +10575,8 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
|
||||||
assert(pstr->mDestructor != nullptr);
|
assert(pstr->mDestructor != nullptr);
|
||||||
ExpEmit reg(build, REGT_POINTER);
|
ExpEmit reg(build, REGT_POINTER);
|
||||||
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(build->ConstructedStructs[i]->StackOffset));
|
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(build->ConstructedStructs[i]->StackOffset));
|
||||||
FunctionCallEmitter emitters;
|
FunctionCallEmitter emitters(pstr->mDestructor);
|
||||||
emitters.AddParameter(reg, false);
|
emitters.AddParameter(reg, false);
|
||||||
emitters.AddTarget(pstr->mDestructor);
|
|
||||||
emitters.EmitCall(build);
|
emitters.EmitCall(build);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10752,7 +10744,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int BuiltinNameToClass(VMValue *param, int numparam, VMReturn *ret, int numret)
|
int BuiltinNameToClass(VM_ARGS)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
PARAM_NAME(clsname);
|
PARAM_NAME(clsname);
|
||||||
|
@ -10777,9 +10769,6 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
return ExpEmit(build->GetConstantAddress(nullptr), REGT_POINTER, true);
|
return ExpEmit(build->GetConstantAddress(nullptr), REGT_POINTER, true);
|
||||||
}
|
}
|
||||||
FunctionCallEmitter emitters;
|
|
||||||
emitters.AddParameter(build, basex);
|
|
||||||
emitters.AddParameterPointerConst(const_cast<PClass *>(desttype));
|
|
||||||
|
|
||||||
// Call the BuiltinNameToClass function to convert from 'name' to class.
|
// Call the BuiltinNameToClass function to convert from 'name' to class.
|
||||||
VMFunction *callfunc;
|
VMFunction *callfunc;
|
||||||
|
@ -10790,7 +10779,9 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
|
||||||
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
||||||
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||||
|
|
||||||
emitters.AddTarget(callfunc);
|
FunctionCallEmitter emitters(callfunc);
|
||||||
|
emitters.AddParameter(build, basex);
|
||||||
|
emitters.AddParameterPointerConst(const_cast<PClass *>(desttype));
|
||||||
emitters.AddReturn(REGT_POINTER);
|
emitters.AddReturn(REGT_POINTER);
|
||||||
return emitters.EmitCall(build);
|
return emitters.EmitCall(build);
|
||||||
}
|
}
|
||||||
|
@ -10875,7 +10866,7 @@ FxExpression *FxClassPtrCast::Resolve(FCompileContext &ctx)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int BuiltinClassCast(VMValue *param, int numparam, VMReturn *ret, int numret)
|
int BuiltinClassCast(VM_ARGS)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
PARAM_CLASS(from, DObject);
|
PARAM_CLASS(from, DObject);
|
||||||
|
@ -10887,11 +10878,6 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
ExpEmit clsname = basex->Emit(build);
|
ExpEmit clsname = basex->Emit(build);
|
||||||
|
|
||||||
FunctionCallEmitter emitters;
|
|
||||||
|
|
||||||
emitters.AddParameter(clsname, false);
|
|
||||||
emitters.AddParameterPointerConst(desttype);
|
|
||||||
|
|
||||||
VMFunction *callfunc;
|
VMFunction *callfunc;
|
||||||
static uint8_t reginfo[] = { REGT_POINTER, REGT_POINTER };
|
static uint8_t reginfo[] = { REGT_POINTER, REGT_POINTER };
|
||||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast, reginfo);
|
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast, reginfo);
|
||||||
|
@ -10899,7 +10885,11 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)
|
||||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||||
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
||||||
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||||
emitters.AddTarget(callfunc);
|
|
||||||
|
FunctionCallEmitter emitters(callfunc);
|
||||||
|
emitters.AddParameter(clsname, false);
|
||||||
|
emitters.AddParameterPointerConst(desttype);
|
||||||
|
|
||||||
emitters.AddReturn(REGT_POINTER);
|
emitters.AddReturn(REGT_POINTER);
|
||||||
return emitters.EmitCall(build);
|
return emitters.EmitCall(build);
|
||||||
}
|
}
|
||||||
|
@ -11274,9 +11264,8 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
ExpEmit reg(build, REGT_POINTER);
|
ExpEmit reg(build, REGT_POINTER);
|
||||||
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
|
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
|
||||||
FunctionCallEmitter emitters;
|
FunctionCallEmitter emitters(pstr->mConstructor);
|
||||||
emitters.AddParameter(reg, false);
|
emitters.AddParameter(reg, false);
|
||||||
emitters.AddTarget(pstr->mConstructor);
|
|
||||||
emitters.EmitCall(build);
|
emitters.EmitCall(build);
|
||||||
}
|
}
|
||||||
if (pstr->mDestructor != nullptr) build->ConstructedStructs.Push(this);
|
if (pstr->mDestructor != nullptr) build->ConstructedStructs.Push(this);
|
||||||
|
@ -11301,9 +11290,8 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
ExpEmit reg(build, REGT_POINTER);
|
ExpEmit reg(build, REGT_POINTER);
|
||||||
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
|
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
|
||||||
FunctionCallEmitter emitters;
|
FunctionCallEmitter emitters(pstr->mDestructor);
|
||||||
emitters.AddParameter(reg, false);
|
emitters.AddParameter(reg, false);
|
||||||
emitters.AddTarget(pstr->mDestructor);
|
|
||||||
emitters.EmitCall(build);
|
emitters.EmitCall(build);
|
||||||
}
|
}
|
||||||
build->ConstructedStructs.Delete(build->ConstructedStructs.Find(this));
|
build->ConstructedStructs.Delete(build->ConstructedStructs.Find(this));
|
||||||
|
|
|
@ -514,7 +514,7 @@ public:
|
||||||
isresolved = true;
|
isresolved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FxConstant(PType *type, VMValue &vmval, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos)
|
FxConstant(PType *type, TypedVMValue &vmval, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos)
|
||||||
{
|
{
|
||||||
isresolved = true;
|
isresolved = true;
|
||||||
switch (vmval.Type)
|
switch (vmval.Type)
|
||||||
|
|
|
@ -941,6 +941,8 @@ void FunctionCallEmitter::AddParameter(VMFunctionBuilder *build, FxExpression *o
|
||||||
operand->ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value");
|
operand->ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value");
|
||||||
}
|
}
|
||||||
numparams += where.RegCount;
|
numparams += where.RegCount;
|
||||||
|
if (target->VarFlags & VARF_VarArg)
|
||||||
|
for (unsigned i = 0; i < where.RegCount; i++) reginfo.Push(where.RegType & REGT_TYPE);
|
||||||
|
|
||||||
emitters.push_back([=](VMFunctionBuilder *build) -> int
|
emitters.push_back([=](VMFunctionBuilder *build) -> int
|
||||||
{
|
{
|
||||||
|
@ -962,6 +964,11 @@ void FunctionCallEmitter::AddParameter(VMFunctionBuilder *build, FxExpression *o
|
||||||
void FunctionCallEmitter::AddParameter(ExpEmit &emit, bool reference)
|
void FunctionCallEmitter::AddParameter(ExpEmit &emit, bool reference)
|
||||||
{
|
{
|
||||||
numparams += emit.RegCount;
|
numparams += emit.RegCount;
|
||||||
|
if (target->VarFlags & VARF_VarArg)
|
||||||
|
{
|
||||||
|
if (reference) reginfo.Push(REGT_POINTER);
|
||||||
|
else for (unsigned i = 0; i < emit.RegCount; i++) reginfo.Push(emit.RegType & REGT_TYPE);
|
||||||
|
}
|
||||||
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
||||||
{
|
{
|
||||||
build->Emit(OP_PARAM, emit.RegType + (reference * REGT_ADDROF), emit.RegNum);
|
build->Emit(OP_PARAM, emit.RegType + (reference * REGT_ADDROF), emit.RegNum);
|
||||||
|
@ -974,6 +981,8 @@ void FunctionCallEmitter::AddParameter(ExpEmit &emit, bool reference)
|
||||||
void FunctionCallEmitter::AddParameterPointerConst(void *konst)
|
void FunctionCallEmitter::AddParameterPointerConst(void *konst)
|
||||||
{
|
{
|
||||||
numparams++;
|
numparams++;
|
||||||
|
if (target->VarFlags & VARF_VarArg)
|
||||||
|
reginfo.Push(REGT_POINTER);
|
||||||
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
||||||
{
|
{
|
||||||
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(konst));
|
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(konst));
|
||||||
|
@ -984,6 +993,8 @@ void FunctionCallEmitter::AddParameterPointerConst(void *konst)
|
||||||
void FunctionCallEmitter::AddParameterPointer(int index, bool konst)
|
void FunctionCallEmitter::AddParameterPointer(int index, bool konst)
|
||||||
{
|
{
|
||||||
numparams++;
|
numparams++;
|
||||||
|
if (target->VarFlags & VARF_VarArg)
|
||||||
|
reginfo.Push(REGT_POINTER);
|
||||||
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
||||||
{
|
{
|
||||||
build->Emit(OP_PARAM, konst ? REGT_POINTER | REGT_KONST : REGT_POINTER, index);
|
build->Emit(OP_PARAM, konst ? REGT_POINTER | REGT_KONST : REGT_POINTER, index);
|
||||||
|
@ -994,6 +1005,8 @@ void FunctionCallEmitter::AddParameterPointer(int index, bool konst)
|
||||||
void FunctionCallEmitter::AddParameterFloatConst(double konst)
|
void FunctionCallEmitter::AddParameterFloatConst(double konst)
|
||||||
{
|
{
|
||||||
numparams++;
|
numparams++;
|
||||||
|
if (target->VarFlags & VARF_VarArg)
|
||||||
|
reginfo.Push(REGT_FLOAT);
|
||||||
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
||||||
{
|
{
|
||||||
build->Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(konst));
|
build->Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(konst));
|
||||||
|
@ -1004,6 +1017,8 @@ void FunctionCallEmitter::AddParameterFloatConst(double konst)
|
||||||
void FunctionCallEmitter::AddParameterIntConst(int konst)
|
void FunctionCallEmitter::AddParameterIntConst(int konst)
|
||||||
{
|
{
|
||||||
numparams++;
|
numparams++;
|
||||||
|
if (target->VarFlags & VARF_VarArg)
|
||||||
|
reginfo.Push(REGT_INT);
|
||||||
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
||||||
{
|
{
|
||||||
// Immediates for PARAMI must fit in 24 bits.
|
// Immediates for PARAMI must fit in 24 bits.
|
||||||
|
@ -1022,6 +1037,8 @@ void FunctionCallEmitter::AddParameterIntConst(int konst)
|
||||||
void FunctionCallEmitter::AddParameterStringConst(const FString &konst)
|
void FunctionCallEmitter::AddParameterStringConst(const FString &konst)
|
||||||
{
|
{
|
||||||
numparams++;
|
numparams++;
|
||||||
|
if (target->VarFlags & VARF_VarArg)
|
||||||
|
reginfo.Push(REGT_STRING);
|
||||||
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
||||||
{
|
{
|
||||||
build->Emit(OP_PARAM, REGT_STRING | REGT_KONST, build->GetConstantString(konst));
|
build->Emit(OP_PARAM, REGT_STRING | REGT_KONST, build->GetConstantString(konst));
|
||||||
|
@ -1037,6 +1054,16 @@ ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray<ExpEmit>
|
||||||
paramcount += func(build);
|
paramcount += func(build);
|
||||||
}
|
}
|
||||||
assert(paramcount == numparams);
|
assert(paramcount == numparams);
|
||||||
|
if (target->VarFlags & VARF_VarArg)
|
||||||
|
{
|
||||||
|
// Pass a hidden type information parameter to vararg functions.
|
||||||
|
// It would really be nicer to actually pass real types but that'd require a far more complex interface on the compiler side than what we have.
|
||||||
|
uint8_t *regbuffer = (uint8_t*)ClassDataAllocator.Alloc(reginfo.Size()); // Allocate in the arena so that the pointer does not need to be maintained.
|
||||||
|
memcpy(regbuffer, reginfo.Data(), reginfo.Size());
|
||||||
|
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(regbuffer));
|
||||||
|
paramcount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (virtualselfreg == -1)
|
if (virtualselfreg == -1)
|
||||||
{
|
{
|
||||||
|
|
|
@ -169,11 +169,22 @@ class FunctionCallEmitter
|
||||||
// std::function and TArray are not compatible so this has to use std::vector instead.
|
// std::function and TArray are not compatible so this has to use std::vector instead.
|
||||||
std::vector<std::function<int(VMFunctionBuilder *)>> emitters;
|
std::vector<std::function<int(VMFunctionBuilder *)>> emitters;
|
||||||
TArray<std::pair<int, int>> returns;
|
TArray<std::pair<int, int>> returns;
|
||||||
|
TArray<uint8_t> reginfo;
|
||||||
unsigned numparams = 0; // This counts the number of pushed elements, which can differ from the number of emitters with vectors.
|
unsigned numparams = 0; // This counts the number of pushed elements, which can differ from the number of emitters with vectors.
|
||||||
VMFunction *target = nullptr;
|
VMFunction *target = nullptr;
|
||||||
int virtualselfreg = -1;
|
int virtualselfreg = -1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
FunctionCallEmitter(VMFunction *func)
|
||||||
|
{
|
||||||
|
target = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetVirtualReg(int virtreg)
|
||||||
|
{
|
||||||
|
virtualselfreg = virtreg;
|
||||||
|
}
|
||||||
|
|
||||||
void AddParameter(VMFunctionBuilder *build, FxExpression *operand);
|
void AddParameter(VMFunctionBuilder *build, FxExpression *operand);
|
||||||
void AddParameter(ExpEmit &emit, bool reference);
|
void AddParameter(ExpEmit &emit, bool reference);
|
||||||
void AddParameterPointerConst(void *konst);
|
void AddParameterPointerConst(void *konst);
|
||||||
|
@ -186,11 +197,6 @@ public:
|
||||||
{
|
{
|
||||||
returns.Push({ regtype, regcount });
|
returns.Push({ regtype, regcount });
|
||||||
}
|
}
|
||||||
void AddTarget(VMFunction *func, int virtreg = -1)
|
|
||||||
{
|
|
||||||
target = func;
|
|
||||||
virtualselfreg = virtreg;
|
|
||||||
}
|
|
||||||
unsigned Count() const
|
unsigned Count() const
|
||||||
{
|
{
|
||||||
return numparams;
|
return numparams;
|
||||||
|
|
|
@ -1020,10 +1020,16 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Replace)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FString FStringFormat(VM_ARGS)
|
FString FStringFormat(VM_ARGS, int offset)
|
||||||
{
|
{
|
||||||
assert(param[0].Type == REGT_STRING);
|
PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array
|
||||||
FString fmtstring = param[0].s().GetChars();
|
assert(va_reginfo[offset] == REGT_STRING);
|
||||||
|
|
||||||
|
FString fmtstring = param[offset].s().GetChars();
|
||||||
|
|
||||||
|
param += offset;
|
||||||
|
numparam -= offset;
|
||||||
|
va_reginfo += offset;
|
||||||
|
|
||||||
// note: we don't need a real printf format parser.
|
// note: we don't need a real printf format parser.
|
||||||
// enough to simply find the subtitution tokens and feed them to the real printf after checking types.
|
// enough to simply find the subtitution tokens and feed them to the real printf after checking types.
|
||||||
|
@ -1074,7 +1080,7 @@ FString FStringFormat(VM_ARGS)
|
||||||
in_fmt = false;
|
in_fmt = false;
|
||||||
// fail if something was found, but it's not a string
|
// fail if something was found, but it's not a string
|
||||||
if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format.");
|
if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format.");
|
||||||
if (param[argnum].Type != REGT_STRING) ThrowAbortException(X_FORMAT_ERROR, "Expected a string for format %s.", fmt_current.GetChars());
|
if (va_reginfo[argnum] != REGT_STRING) ThrowAbortException(X_FORMAT_ERROR, "Expected a string for format %s.", fmt_current.GetChars());
|
||||||
// append
|
// append
|
||||||
output.AppendFormat(fmt_current.GetChars(), param[argnum].s().GetChars());
|
output.AppendFormat(fmt_current.GetChars(), param[argnum].s().GetChars());
|
||||||
if (!haveargnums) argnum = ++argauto;
|
if (!haveargnums) argnum = ++argauto;
|
||||||
|
@ -1090,7 +1096,7 @@ FString FStringFormat(VM_ARGS)
|
||||||
in_fmt = false;
|
in_fmt = false;
|
||||||
// fail if something was found, but it's not a string
|
// fail if something was found, but it's not a string
|
||||||
if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format.");
|
if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format.");
|
||||||
if (param[argnum].Type != REGT_POINTER) ThrowAbortException(X_FORMAT_ERROR, "Expected a pointer for format %s.", fmt_current.GetChars());
|
if (va_reginfo[argnum] != REGT_POINTER) ThrowAbortException(X_FORMAT_ERROR, "Expected a pointer for format %s.", fmt_current.GetChars());
|
||||||
// append
|
// append
|
||||||
output.AppendFormat(fmt_current.GetChars(), param[argnum].a);
|
output.AppendFormat(fmt_current.GetChars(), param[argnum].a);
|
||||||
if (!haveargnums) argnum = ++argauto;
|
if (!haveargnums) argnum = ++argauto;
|
||||||
|
@ -1112,10 +1118,10 @@ FString FStringFormat(VM_ARGS)
|
||||||
in_fmt = false;
|
in_fmt = false;
|
||||||
// fail if something was found, but it's not an int
|
// fail if something was found, but it's not an int
|
||||||
if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format.");
|
if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format.");
|
||||||
if (param[argnum].Type != REGT_INT &&
|
if (va_reginfo[argnum] != REGT_INT &&
|
||||||
param[argnum].Type != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars());
|
va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars());
|
||||||
// append
|
// append
|
||||||
output.AppendFormat(fmt_current.GetChars(), param[argnum].ToInt());
|
output.AppendFormat(fmt_current.GetChars(), param[argnum].ToInt(va_reginfo[argnum]));
|
||||||
if (!haveargnums) argnum = ++argauto;
|
if (!haveargnums) argnum = ++argauto;
|
||||||
else argnum = -1;
|
else argnum = -1;
|
||||||
break;
|
break;
|
||||||
|
@ -1136,10 +1142,10 @@ FString FStringFormat(VM_ARGS)
|
||||||
in_fmt = false;
|
in_fmt = false;
|
||||||
// fail if something was found, but it's not a float
|
// fail if something was found, but it's not a float
|
||||||
if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format.");
|
if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format.");
|
||||||
if (param[argnum].Type != REGT_INT &&
|
if (va_reginfo[argnum] != REGT_INT &&
|
||||||
param[argnum].Type != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars());
|
va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars());
|
||||||
// append
|
// append
|
||||||
output.AppendFormat(fmt_current.GetChars(), param[argnum].ToDouble());
|
output.AppendFormat(fmt_current.GetChars(), param[argnum].ToDouble(va_reginfo[argnum]));
|
||||||
if (!haveargnums) argnum = ++argauto;
|
if (!haveargnums) argnum = ++argauto;
|
||||||
else argnum = -1;
|
else argnum = -1;
|
||||||
break;
|
break;
|
||||||
|
@ -1181,7 +1187,7 @@ FString FStringFormat(VM_ARGS)
|
||||||
DEFINE_ACTION_FUNCTION(FStringStruct, Format)
|
DEFINE_ACTION_FUNCTION(FStringStruct, Format)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
FString s = FStringFormat(param, numparam, ret, numret);
|
FString s = FStringFormat(VM_ARGS_NAMES);
|
||||||
ACTION_RETURN_STRING(s);
|
ACTION_RETURN_STRING(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1189,7 +1195,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat)
|
||||||
{
|
{
|
||||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||||
// first parameter is the self pointer
|
// first parameter is the self pointer
|
||||||
FString s = FStringFormat(param+1, numparam-1, ret, numret);
|
FString s = FStringFormat(VM_ARGS_NAMES, 1);
|
||||||
(*self) += s;
|
(*self) += s;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,8 +129,6 @@ int JitCompiler::StoreCallParams(bool simpleFrameTarget)
|
||||||
{
|
{
|
||||||
int abcs = ParamOpcodes[i]->i24;
|
int abcs = ParamOpcodes[i]->i24;
|
||||||
cc.mov(asmjit::x86::dword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, i)), abcs);
|
cc.mov(asmjit::x86::dword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, i)), abcs);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(asmjit::x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_INT);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,71 +138,47 @@ int JitCompiler::StoreCallParams(bool simpleFrameTarget)
|
||||||
{
|
{
|
||||||
case REGT_NIL:
|
case REGT_NIL:
|
||||||
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), (int64_t)0);
|
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), (int64_t)0);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_NIL);
|
|
||||||
break;
|
break;
|
||||||
case REGT_INT:
|
case REGT_INT:
|
||||||
cc.mov(x86::dword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, i)), regD[bc]);
|
cc.mov(x86::dword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, i)), regD[bc]);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_INT);
|
|
||||||
break;
|
break;
|
||||||
case REGT_INT | REGT_ADDROF:
|
case REGT_INT | REGT_ADDROF:
|
||||||
cc.lea(stackPtr, x86::ptr(vmframe, offsetD + (int)(bc * sizeof(int32_t))));
|
cc.lea(stackPtr, x86::ptr(vmframe, offsetD + (int)(bc * sizeof(int32_t))));
|
||||||
cc.mov(x86::dword_ptr(stackPtr), regD[bc]);
|
cc.mov(x86::dword_ptr(stackPtr), regD[bc]);
|
||||||
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), stackPtr);
|
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), stackPtr);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER);
|
|
||||||
break;
|
break;
|
||||||
case REGT_INT | REGT_KONST:
|
case REGT_INT | REGT_KONST:
|
||||||
cc.mov(x86::dword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, i)), konstd[bc]);
|
cc.mov(x86::dword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, i)), konstd[bc]);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_INT);
|
|
||||||
break;
|
break;
|
||||||
case REGT_STRING:
|
case REGT_STRING:
|
||||||
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, sp)), regS[bc]);
|
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, sp)), regS[bc]);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_STRING);
|
|
||||||
break;
|
break;
|
||||||
case REGT_STRING | REGT_ADDROF:
|
case REGT_STRING | REGT_ADDROF:
|
||||||
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), regS[bc]);
|
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), regS[bc]);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER);
|
|
||||||
break;
|
break;
|
||||||
case REGT_STRING | REGT_KONST:
|
case REGT_STRING | REGT_KONST:
|
||||||
cc.mov(tmp, asmjit::imm_ptr(&konsts[bc]));
|
cc.mov(tmp, asmjit::imm_ptr(&konsts[bc]));
|
||||||
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, sp)), tmp);
|
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, sp)), tmp);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_STRING);
|
|
||||||
break;
|
break;
|
||||||
case REGT_POINTER:
|
case REGT_POINTER:
|
||||||
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), regA[bc]);
|
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), regA[bc]);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER);
|
|
||||||
break;
|
break;
|
||||||
case REGT_POINTER | REGT_ADDROF:
|
case REGT_POINTER | REGT_ADDROF:
|
||||||
cc.lea(stackPtr, x86::ptr(vmframe, offsetA + (int)(bc * sizeof(void*))));
|
cc.lea(stackPtr, x86::ptr(vmframe, offsetA + (int)(bc * sizeof(void*))));
|
||||||
cc.mov(x86::ptr(stackPtr), regA[bc]);
|
cc.mov(x86::ptr(stackPtr), regA[bc]);
|
||||||
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), stackPtr);
|
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), stackPtr);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER);
|
|
||||||
break;
|
break;
|
||||||
case REGT_POINTER | REGT_KONST:
|
case REGT_POINTER | REGT_KONST:
|
||||||
cc.mov(tmp, asmjit::imm_ptr(konsta[bc].v));
|
cc.mov(tmp, asmjit::imm_ptr(konsta[bc].v));
|
||||||
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), tmp);
|
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), tmp);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER);
|
|
||||||
break;
|
break;
|
||||||
case REGT_FLOAT:
|
case REGT_FLOAT:
|
||||||
cc.movsd(x86::qword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, f)), regF[bc]);
|
cc.movsd(x86::qword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, f)), regF[bc]);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_FLOAT);
|
|
||||||
break;
|
break;
|
||||||
case REGT_FLOAT | REGT_MULTIREG2:
|
case REGT_FLOAT | REGT_MULTIREG2:
|
||||||
for (int j = 0; j < 2; j++)
|
for (int j = 0; j < 2; j++)
|
||||||
{
|
{
|
||||||
cc.movsd(x86::qword_ptr(vmframe, offsetParams + (slot + j) * sizeof(VMValue) + myoffsetof(VMValue, f)), regF[bc + j]);
|
cc.movsd(x86::qword_ptr(vmframe, offsetParams + (slot + j) * sizeof(VMValue) + myoffsetof(VMValue, f)), regF[bc + j]);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + (slot + j) * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_FLOAT);
|
|
||||||
}
|
}
|
||||||
numparams++;
|
numparams++;
|
||||||
break;
|
break;
|
||||||
|
@ -212,8 +186,6 @@ int JitCompiler::StoreCallParams(bool simpleFrameTarget)
|
||||||
for (int j = 0; j < 3; j++)
|
for (int j = 0; j < 3; j++)
|
||||||
{
|
{
|
||||||
cc.movsd(x86::qword_ptr(vmframe, offsetParams + (slot + j) * sizeof(VMValue) + myoffsetof(VMValue, f)), regF[bc + j]);
|
cc.movsd(x86::qword_ptr(vmframe, offsetParams + (slot + j) * sizeof(VMValue) + myoffsetof(VMValue, f)), regF[bc + j]);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + (slot + j) * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_FLOAT);
|
|
||||||
}
|
}
|
||||||
numparams += 2;
|
numparams += 2;
|
||||||
break;
|
break;
|
||||||
|
@ -226,15 +198,11 @@ int JitCompiler::StoreCallParams(bool simpleFrameTarget)
|
||||||
cc.movsd(x86::qword_ptr(stackPtr, j * sizeof(double)), regF[bc + j]);
|
cc.movsd(x86::qword_ptr(stackPtr, j * sizeof(double)), regF[bc + j]);
|
||||||
}
|
}
|
||||||
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), stackPtr);
|
cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), stackPtr);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER);
|
|
||||||
break;
|
break;
|
||||||
case REGT_FLOAT | REGT_KONST:
|
case REGT_FLOAT | REGT_KONST:
|
||||||
cc.mov(tmp, asmjit::imm_ptr(konstf + bc));
|
cc.mov(tmp, asmjit::imm_ptr(konstf + bc));
|
||||||
cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp));
|
cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp));
|
||||||
cc.movsd(x86::qword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, f)), tmp2);
|
cc.movsd(x86::qword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, f)), tmp2);
|
||||||
if (!simpleFrameTarget)
|
|
||||||
cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_FLOAT);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -196,8 +196,7 @@ struct VMReturn
|
||||||
|
|
||||||
struct VMRegisters;
|
struct VMRegisters;
|
||||||
|
|
||||||
|
struct TypedVMValue
|
||||||
struct VMValue
|
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
@ -211,11 +210,90 @@ struct VMValue
|
||||||
|
|
||||||
const FString &s() const { return *sp; }
|
const FString &s() const { return *sp; }
|
||||||
|
|
||||||
VMValue()
|
TypedVMValue()
|
||||||
{
|
{
|
||||||
a = NULL;
|
a = NULL;
|
||||||
Type = REGT_NIL;
|
Type = REGT_NIL;
|
||||||
}
|
}
|
||||||
|
TypedVMValue(const TypedVMValue &o)
|
||||||
|
{
|
||||||
|
biggest = o.biggest;
|
||||||
|
}
|
||||||
|
TypedVMValue(int v)
|
||||||
|
{
|
||||||
|
i = v;
|
||||||
|
Type = REGT_INT;
|
||||||
|
}
|
||||||
|
TypedVMValue(double v)
|
||||||
|
{
|
||||||
|
f = v;
|
||||||
|
Type = REGT_FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedVMValue(const FString *s)
|
||||||
|
{
|
||||||
|
sp = s;
|
||||||
|
Type = REGT_STRING;
|
||||||
|
}
|
||||||
|
TypedVMValue(DObject *v)
|
||||||
|
{
|
||||||
|
a = v;
|
||||||
|
Type = REGT_POINTER;
|
||||||
|
}
|
||||||
|
TypedVMValue(void *v)
|
||||||
|
{
|
||||||
|
a = v;
|
||||||
|
Type = REGT_POINTER;
|
||||||
|
}
|
||||||
|
TypedVMValue &operator=(const TypedVMValue &o)
|
||||||
|
{
|
||||||
|
biggest = o.biggest;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
TypedVMValue &operator=(int v)
|
||||||
|
{
|
||||||
|
i = v;
|
||||||
|
Type = REGT_INT;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
TypedVMValue &operator=(double v)
|
||||||
|
{
|
||||||
|
f = v;
|
||||||
|
Type = REGT_FLOAT;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
TypedVMValue &operator=(const FString *v)
|
||||||
|
{
|
||||||
|
sp = v;
|
||||||
|
Type = REGT_STRING;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
TypedVMValue &operator=(DObject *v)
|
||||||
|
{
|
||||||
|
a = v;
|
||||||
|
Type = REGT_POINTER;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct VMValue
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
void *a;
|
||||||
|
double f;
|
||||||
|
struct { int foo[2]; } biggest;
|
||||||
|
const FString *sp;
|
||||||
|
};
|
||||||
|
|
||||||
|
const FString &s() const { return *sp; }
|
||||||
|
|
||||||
|
VMValue()
|
||||||
|
{
|
||||||
|
a = NULL;
|
||||||
|
}
|
||||||
VMValue(const VMValue &o)
|
VMValue(const VMValue &o)
|
||||||
{
|
{
|
||||||
biggest = o.biggest;
|
biggest = o.biggest;
|
||||||
|
@ -223,12 +301,10 @@ struct VMValue
|
||||||
VMValue(int v)
|
VMValue(int v)
|
||||||
{
|
{
|
||||||
i = v;
|
i = v;
|
||||||
Type = REGT_INT;
|
|
||||||
}
|
}
|
||||||
VMValue(double v)
|
VMValue(double v)
|
||||||
{
|
{
|
||||||
f = v;
|
f = v;
|
||||||
Type = REGT_FLOAT;
|
|
||||||
}
|
}
|
||||||
VMValue(const char *s) = delete;
|
VMValue(const char *s) = delete;
|
||||||
VMValue(const FString &s) = delete;
|
VMValue(const FString &s) = delete;
|
||||||
|
@ -236,39 +312,38 @@ struct VMValue
|
||||||
VMValue(const FString *s)
|
VMValue(const FString *s)
|
||||||
{
|
{
|
||||||
sp = s;
|
sp = s;
|
||||||
Type = REGT_STRING;
|
|
||||||
}
|
}
|
||||||
VMValue(DObject *v)
|
VMValue(DObject *v)
|
||||||
{
|
{
|
||||||
a = v;
|
a = v;
|
||||||
Type = REGT_POINTER;
|
|
||||||
}
|
}
|
||||||
VMValue(void *v)
|
VMValue(void *v)
|
||||||
{
|
{
|
||||||
a = v;
|
a = v;
|
||||||
Type = REGT_POINTER;
|
|
||||||
}
|
}
|
||||||
VMValue &operator=(const VMValue &o)
|
VMValue &operator=(const VMValue &o)
|
||||||
{
|
{
|
||||||
biggest = o.biggest;
|
biggest = o.biggest;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
VMValue &operator=(const TypedVMValue &o)
|
||||||
|
{
|
||||||
|
memcpy(&biggest, &o.biggest, sizeof(biggest));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
VMValue &operator=(int v)
|
VMValue &operator=(int v)
|
||||||
{
|
{
|
||||||
i = v;
|
i = v;
|
||||||
Type = REGT_INT;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
VMValue &operator=(double v)
|
VMValue &operator=(double v)
|
||||||
{
|
{
|
||||||
f = v;
|
f = v;
|
||||||
Type = REGT_FLOAT;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
VMValue &operator=(const FString *v)
|
VMValue &operator=(const FString *v)
|
||||||
{
|
{
|
||||||
sp = v;
|
sp = v;
|
||||||
Type = REGT_STRING;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
VMValue &operator=(const FString &v) = delete;
|
VMValue &operator=(const FString &v) = delete;
|
||||||
|
@ -276,10 +351,9 @@ struct VMValue
|
||||||
VMValue &operator=(DObject *v)
|
VMValue &operator=(DObject *v)
|
||||||
{
|
{
|
||||||
a = v;
|
a = v;
|
||||||
Type = REGT_POINTER;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
int ToInt()
|
int ToInt(int Type)
|
||||||
{
|
{
|
||||||
if (Type == REGT_INT)
|
if (Type == REGT_INT)
|
||||||
{
|
{
|
||||||
|
@ -296,7 +370,7 @@ struct VMValue
|
||||||
// FIXME
|
// FIXME
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
double ToDouble()
|
double ToDouble(int Type)
|
||||||
{
|
{
|
||||||
if (Type == REGT_FLOAT)
|
if (Type == REGT_FLOAT)
|
||||||
{
|
{
|
||||||
|
@ -324,7 +398,7 @@ public:
|
||||||
unsigned VirtualIndex = ~0u;
|
unsigned VirtualIndex = ~0u;
|
||||||
FName Name;
|
FName Name;
|
||||||
const uint8_t *RegTypes = nullptr;
|
const uint8_t *RegTypes = nullptr;
|
||||||
TArray<VMValue> DefaultArgs;
|
TArray<TypedVMValue> DefaultArgs;
|
||||||
FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong.
|
FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong.
|
||||||
|
|
||||||
class PPrototype *Proto;
|
class PPrototype *Proto;
|
||||||
|
@ -365,10 +439,22 @@ protected:
|
||||||
void CreateRegUse();
|
void CreateRegUse();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Use this in the prototype for a native function.
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define VM_ARGS VMValue *param, int numparam, VMReturn *ret, int numret
|
||||||
|
#define VM_ARGS_NAMES param, numparam, ret, numret
|
||||||
|
#define VM_INVOKE(param, numparam, ret, numret, reginfo) (param), (numparam), (ret), (numret)
|
||||||
|
#else
|
||||||
|
#define VM_ARGS VMValue *param, int numparam, VMReturn *ret, int numret, const uint8_t *reginfo
|
||||||
|
#define VM_ARGS_NAMES param, numparam, ret, numret, reginfo
|
||||||
|
#define VM_INVOKE(param, numparam, ret, numret, reginfo) (param), (numparam), (ret), (numret), (reginfo)
|
||||||
|
#endif
|
||||||
|
|
||||||
class VMNativeFunction : public VMFunction
|
class VMNativeFunction : public VMFunction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef int (*NativeCallType)(VMValue *param, int numparam, VMReturn *ret, int numret);
|
typedef int (*NativeCallType)(VM_ARGS);
|
||||||
|
|
||||||
// 8 is VARF_Native. I can't write VARF_Native because of circular references between this and dobject/dobjtype.
|
// 8 is VARF_Native. I can't write VARF_Native because of circular references between this and dobject/dobjtype.
|
||||||
VMNativeFunction() : NativeCall(NULL) { VarFlags = 8; ScriptCall = &VMNativeFunction::NativeScriptCall; }
|
VMNativeFunction() : NativeCall(NULL) { VarFlags = 8; ScriptCall = &VMNativeFunction::NativeScriptCall; }
|
||||||
|
@ -390,10 +476,6 @@ inline int VMCallAction(VMFunction *func, VMValue *params, int numparams, VMRetu
|
||||||
return VMCall(func, params, numparams, results, numresults);
|
return VMCall(func, params, numparams, results, numresults);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use this in the prototype for a native function.
|
|
||||||
#define VM_ARGS VMValue *param, int numparam, VMReturn *ret, int numret
|
|
||||||
#define VM_ARGS_NAMES param, numparam, ret, numret
|
|
||||||
|
|
||||||
// Use these to collect the parameters in a native function.
|
// Use these to collect the parameters in a native function.
|
||||||
// variable name <x> at position <p>
|
// variable name <x> at position <p>
|
||||||
void NullParam(const char *varname);
|
void NullParam(const char *varname);
|
||||||
|
@ -404,31 +486,28 @@ bool AssertObject(void * ob);
|
||||||
|
|
||||||
#define PARAM_NULLCHECK(ptr, var) (ptr == nullptr? NullParam(#var), ptr : ptr)
|
#define PARAM_NULLCHECK(ptr, var) (ptr == nullptr? NullParam(#var), ptr : ptr)
|
||||||
|
|
||||||
#define ASSERTINT(p) assert((p).Type == REGT_INT)
|
// This cannot assert because there is no info for varargs
|
||||||
#define ASSERTFLOAT(p) assert((p).Type == REGT_FLOAT)
|
#define PARAM_VA_POINTER(x) const uint8_t *x = (const uint8_t *)param[numparam-1].a;
|
||||||
#define ASSERTSTRING(p) assert((p).Type == REGT_STRING)
|
|
||||||
#define ASSERTOBJECT(p) assert((p).Type == REGT_POINTER && AssertObject(p.a))
|
|
||||||
#define ASSERTPOINTER(p) assert((p).Type == REGT_POINTER)
|
|
||||||
|
|
||||||
// For required parameters.
|
// For required parameters.
|
||||||
#define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i;
|
#define PARAM_INT_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); int x = param[p].i;
|
||||||
#define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); unsigned x = param[p].i;
|
#define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); unsigned x = param[p].i;
|
||||||
#define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); bool x = !!param[p].i;
|
#define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); bool x = !!param[p].i;
|
||||||
#define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FName x = ENamedName(param[p].i);
|
#define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); FName x = ENamedName(param[p].i);
|
||||||
#define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i;
|
#define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); FSoundID x = param[p].i;
|
||||||
#define PARAM_COLOR_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); PalEntry x; x.d = param[p].i;
|
#define PARAM_COLOR_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); PalEntry x; x.d = param[p].i;
|
||||||
#define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); double x = param[p].f;
|
#define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_FLOAT); double x = param[p].f;
|
||||||
#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); DAngle x = param[p].f;
|
#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_FLOAT); DAngle x = param[p].f;
|
||||||
#define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_STRING); FString x = param[p].s();
|
#define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_STRING); FString x = param[p].s();
|
||||||
#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, self->GetClass());
|
#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, self->GetClass());
|
||||||
#define PARAM_STATE_ACTION_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, stateowner->GetClass());
|
#define PARAM_STATE_ACTION_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, stateowner->GetClass());
|
||||||
#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a;
|
#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER); type *x = (type *)param[p].a;
|
||||||
#define PARAM_POINTERTYPE_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type x = (type )param[p].a;
|
#define PARAM_POINTERTYPE_AT(p,x,type) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER); type x = (type )param[p].a;
|
||||||
#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && AssertObject(param[p].a)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
|
#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER && AssertObject(param[p].a)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
|
||||||
#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
|
#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
|
||||||
#define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x);
|
#define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x);
|
||||||
#define PARAM_OBJECT_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (AssertObject(param[p].a))); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
|
#define PARAM_OBJECT_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER && (AssertObject(param[p].a))); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
|
||||||
#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
|
#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
|
||||||
|
|
||||||
|
|
||||||
// The above, but with an automatically increasing position index.
|
// The above, but with an automatically increasing position index.
|
||||||
|
@ -454,7 +533,7 @@ bool AssertObject(void * ob);
|
||||||
#define PARAM_OBJECT_NOT_NULL(x,type) ++paramnum; PARAM_OBJECT_NOT_NULL_AT(paramnum,x,type)
|
#define PARAM_OBJECT_NOT_NULL(x,type) ++paramnum; PARAM_OBJECT_NOT_NULL_AT(paramnum,x,type)
|
||||||
#define PARAM_CLASS_NOT_NULL(x,base) ++paramnum; PARAM_CLASS_NOT_NULL_AT(paramnum,x,base)
|
#define PARAM_CLASS_NOT_NULL(x,base) ++paramnum; PARAM_CLASS_NOT_NULL_AT(paramnum,x,base)
|
||||||
|
|
||||||
typedef int(*actionf_p)(VMValue *param, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/
|
typedef int(*actionf_p)(VM_ARGS);
|
||||||
|
|
||||||
struct FieldDesc
|
struct FieldDesc
|
||||||
{
|
{
|
||||||
|
@ -591,7 +670,7 @@ class PFunction;
|
||||||
VMFunction *FindVMFunction(PClass *cls, const char *name);
|
VMFunction *FindVMFunction(PClass *cls, const char *name);
|
||||||
#define DECLARE_VMFUNC(cls, name) static VMFunction *name; if (name == nullptr) name = FindVMFunction(RUNTIME_CLASS(cls), #name);
|
#define DECLARE_VMFUNC(cls, name) static VMFunction *name; if (name == nullptr) name = FindVMFunction(RUNTIME_CLASS(cls), #name);
|
||||||
|
|
||||||
FString FStringFormat(VM_ARGS);
|
FString FStringFormat(VM_ARGS, int offset = 0);
|
||||||
|
|
||||||
|
|
||||||
unsigned GetVirtualIndex(PClass *cls, const char *funcname);
|
unsigned GetVirtualIndex(PClass *cls, const char *funcname);
|
||||||
|
|
|
@ -203,7 +203,6 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam)
|
||||||
{
|
{
|
||||||
// copy all parameters to the local registers.
|
// copy all parameters to the local registers.
|
||||||
VMValue &p = params[i];
|
VMValue &p = params[i];
|
||||||
assert(*reginfo == p.Type);
|
|
||||||
if (*reginfo < REGT_STRING)
|
if (*reginfo < REGT_STRING)
|
||||||
{
|
{
|
||||||
if (*reginfo == REGT_INT)
|
if (*reginfo == REGT_INT)
|
||||||
|
|
|
@ -697,7 +697,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
VMCycles[0].Unclock();
|
VMCycles[0].Unclock();
|
||||||
numret = static_cast<VMNativeFunction *>(call)->NativeCall(reg.param + f->NumParam - b, b, returns, C);
|
numret = static_cast<VMNativeFunction *>(call)->NativeCall(VM_INVOKE(reg.param + f->NumParam - b, b, returns, C, call->RegTypes));
|
||||||
VMCycles[0].Clock();
|
VMCycles[0].Clock();
|
||||||
}
|
}
|
||||||
catch (CVMAbortException &err)
|
catch (CVMAbortException &err)
|
||||||
|
|
|
@ -296,7 +296,7 @@ int VMNativeFunction::NativeScriptCall(VMFunction *func, VMValue *params, int nu
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
VMCycles[0].Unclock();
|
VMCycles[0].Unclock();
|
||||||
numret = static_cast<VMNativeFunction *>(func)->NativeCall(params, numparams, returns, numret);
|
numret = static_cast<VMNativeFunction *>(func)->NativeCall(VM_INVOKE(params, numparams, returns, numret, func->RegTypes));
|
||||||
VMCycles[0].Clock();
|
VMCycles[0].Clock();
|
||||||
|
|
||||||
return numret;
|
return numret;
|
||||||
|
@ -571,7 +571,7 @@ int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results,
|
||||||
{
|
{
|
||||||
if (func->VarFlags & VARF_Native)
|
if (func->VarFlags & VARF_Native)
|
||||||
{
|
{
|
||||||
return static_cast<VMNativeFunction *>(func)->NativeCall(params, numparams, results, numresults);
|
return static_cast<VMNativeFunction *>(func)->NativeCall(VM_INVOKE(params, numparams, results, numresults, func->RegTypes));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -730,7 +730,7 @@ void ThrowAbortException(VMScriptFunction *sfunc, VMOP *line, EVMAbortException
|
||||||
DEFINE_ACTION_FUNCTION(DObject, ThrowAbortException)
|
DEFINE_ACTION_FUNCTION(DObject, ThrowAbortException)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
FString s = FStringFormat(param, numparam, ret, numret);
|
FString s = FStringFormat(VM_ARGS_NAMES);
|
||||||
ThrowAbortException(X_OTHER, s.GetChars());
|
ThrowAbortException(X_OTHER, s.GetChars());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2287,7 +2287,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
||||||
TArray<PType *> rets(1);
|
TArray<PType *> rets(1);
|
||||||
TArray<PType *> args;
|
TArray<PType *> args;
|
||||||
TArray<uint32_t> argflags;
|
TArray<uint32_t> argflags;
|
||||||
TArray<VMValue> argdefaults;
|
TArray<TypedVMValue> argdefaults;
|
||||||
TArray<FName> argnames;
|
TArray<FName> argnames;
|
||||||
|
|
||||||
rets.Clear();
|
rets.Clear();
|
||||||
|
@ -2495,7 +2495,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int elementcount = 1;
|
int elementcount = 1;
|
||||||
VMValue vmval[3]; // default is REGT_NIL which means 'no default value' here.
|
TypedVMValue vmval[3]; // default is REGT_NIL which means 'no default value' here.
|
||||||
if (p->Type != nullptr)
|
if (p->Type != nullptr)
|
||||||
{
|
{
|
||||||
auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false);
|
auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false);
|
||||||
|
|
|
@ -171,10 +171,12 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawTexture)
|
||||||
PARAM_FLOAT(x);
|
PARAM_FLOAT(x);
|
||||||
PARAM_FLOAT(y);
|
PARAM_FLOAT(y);
|
||||||
|
|
||||||
|
PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array
|
||||||
|
|
||||||
if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
||||||
|
|
||||||
FTexture *tex = animate ? TexMan(FSetTextureID(texid)) : TexMan[FSetTextureID(texid)];
|
FTexture *tex = animate ? TexMan(FSetTextureID(texid)) : TexMan[FSetTextureID(texid)];
|
||||||
VMVa_List args = { param + 4, 0, numparam - 4 };
|
VMVa_List args = { param + 4, 0, numparam - 5, va_reginfo };
|
||||||
screen->DrawTexture(tex, x, y, args);
|
screen->DrawTexture(tex, x, y, args);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -225,10 +227,12 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawShape)
|
||||||
PARAM_BOOL(animate);
|
PARAM_BOOL(animate);
|
||||||
PARAM_POINTER(shape, DShape2D);
|
PARAM_POINTER(shape, DShape2D);
|
||||||
|
|
||||||
|
PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array
|
||||||
|
|
||||||
if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
||||||
|
|
||||||
FTexture *tex = animate ? TexMan(FSetTextureID(texid)) : TexMan[FSetTextureID(texid)];
|
FTexture *tex = animate ? TexMan(FSetTextureID(texid)) : TexMan[FSetTextureID(texid)];
|
||||||
VMVa_List args = { param + 3, 0, numparam - 3 };
|
VMVa_List args = { param + 3, 0, numparam - 4, va_reginfo };
|
||||||
|
|
||||||
screen->DrawShape(tex, shape, args);
|
screen->DrawShape(tex, shape, args);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -418,7 +422,7 @@ int ListGetInt(VMVa_List &tags)
|
||||||
{
|
{
|
||||||
if (tags.curindex < tags.numargs)
|
if (tags.curindex < tags.numargs)
|
||||||
{
|
{
|
||||||
if (tags.args[tags.curindex].Type == REGT_INT)
|
if (tags.reginfo[tags.curindex] == REGT_INT)
|
||||||
{
|
{
|
||||||
return tags.args[tags.curindex++].i;
|
return tags.args[tags.curindex++].i;
|
||||||
}
|
}
|
||||||
|
@ -429,11 +433,18 @@ int ListGetInt(VMVa_List &tags)
|
||||||
|
|
||||||
static inline double ListGetDouble(VMVa_List &tags)
|
static inline double ListGetDouble(VMVa_List &tags)
|
||||||
{
|
{
|
||||||
if (tags.curindex < tags.numargs && tags.args[tags.curindex].Type == REGT_FLOAT)
|
if (tags.curindex < tags.numargs)
|
||||||
|
{
|
||||||
|
if (tags.reginfo[tags.curindex] == REGT_FLOAT)
|
||||||
{
|
{
|
||||||
return tags.args[tags.curindex++].f;
|
return tags.args[tags.curindex++].f;
|
||||||
}
|
}
|
||||||
|
if (tags.reginfo[tags.curindex] == REGT_INT)
|
||||||
|
{
|
||||||
|
return tags.args[tags.curindex++].i;
|
||||||
|
}
|
||||||
ThrowAbortException(X_OTHER, "Invalid parameter in draw function, float expected");
|
ThrowAbortException(X_OTHER, "Invalid parameter in draw function, float expected");
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -191,8 +191,10 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawChar)
|
||||||
PARAM_FLOAT(y);
|
PARAM_FLOAT(y);
|
||||||
PARAM_INT(chr);
|
PARAM_INT(chr);
|
||||||
|
|
||||||
|
PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array
|
||||||
|
|
||||||
if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
||||||
VMVa_List args = { param + 5, 0, numparam - 5 };
|
VMVa_List args = { param + 5, 0, numparam - 6, va_reginfo };
|
||||||
screen->DrawChar(font, cr, x, y, chr, args);
|
screen->DrawChar(font, cr, x, y, chr, args);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -321,8 +323,10 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawText)
|
||||||
PARAM_FLOAT(y);
|
PARAM_FLOAT(y);
|
||||||
PARAM_STRING(chr);
|
PARAM_STRING(chr);
|
||||||
|
|
||||||
|
PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array
|
||||||
|
|
||||||
if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
||||||
VMVa_List args = { param + 5, 0, numparam - 5 };
|
VMVa_List args = { param + 5, 0, numparam - 6, va_reginfo };
|
||||||
const char *txt = chr[0] == '$' ? GStrings(&chr[1]) : chr.GetChars();
|
const char *txt = chr[0] == '$' ? GStrings(&chr[1]) : chr.GetChars();
|
||||||
screen->DrawText(font, cr, x, y, txt, args);
|
screen->DrawText(font, cr, x, y, txt, args);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -287,6 +287,7 @@ struct VMVa_List
|
||||||
VMValue *args;
|
VMValue *args;
|
||||||
int curindex;
|
int curindex;
|
||||||
int numargs;
|
int numargs;
|
||||||
|
const uint8_t *reginfo;
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
// VIDEO
|
// VIDEO
|
||||||
|
|
Loading…
Reference in a new issue