- generate register type info for the parameter lists of all functions.

Currently used for loading parameters into registers.
For checking parameters of native functions some more work is needed to get the info to the function. Currently it doesn't receive the function descriptor.
This commit is contained in:
Christoph Oelckers 2018-11-18 17:10:55 +01:00
parent 1ef772d017
commit a981737855
11 changed files with 84 additions and 46 deletions

View file

@ -749,6 +749,7 @@ static void (*MBFCodePointerFactories[])(FunctionCallEmitter&, int, int) =
void SetDehParams(FState *state, int codepointer)
{
static uint8_t regts[] = { REGT_POINTER, REGT_POINTER, REGT_POINTER };
int value1 = state->GetMisc1();
int value2 = state->GetMisc2();
if (!(value1|value2)) return;
@ -788,6 +789,7 @@ void SetDehParams(FState *state, int codepointer)
buildit.Emit(OP_RET, RET_FINAL, REGT_NIL, 0);
// Attach it to the state.
VMScriptFunction *sfunc = new VMScriptFunction;
sfunc->RegTypes = regts; // These functions are built after running the script compiler so they don't get this info.
buildit.MakeFunction(sfunc);
sfunc->NumArgs = numargs;
sfunc->ImplicitArgs = numargs;

View file

@ -688,7 +688,7 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLineDamaged);
DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame)
//DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderOverlay)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerEntered)
@ -972,6 +972,7 @@ static FRenderEvent E_SetupRenderEvent()
void DStaticEventHandler::RenderFrame()
{
/* This is intentionally and permanently disabled.
IFVIRTUAL(DStaticEventHandler, RenderFrame)
{
// don't create excessive DObjects if not going to be processed anyway
@ -981,6 +982,7 @@ void DStaticEventHandler::RenderFrame()
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, nullptr, 0);
}
*/
}
void DStaticEventHandler::RenderOverlay(EHudState state)

View file

@ -4689,14 +4689,6 @@ void AActor::Tick ()
}
}
DEFINE_ACTION_FUNCTION(AActor, Tick)
{
PARAM_SELF_PROLOGUE(AActor);
self->Tick();
return 0;
}
//==========================================================================
//
// AActor :: CheckNoDelay
@ -8282,13 +8274,6 @@ DEFINE_ACTION_FUNCTION(AActor, SetDamage)
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, GetDefaultByType)
{
PARAM_PROLOGUE;
PARAM_CLASS(cls, AActor);
ACTION_RETURN_OBJECT(cls == nullptr? nullptr : GetDefaultByType(cls));
}
// This combines all 3 variations of the internal function
DEFINE_ACTION_FUNCTION(AActor, VelFromAngle)
{

View file

@ -1899,13 +1899,6 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt)
ACTION_RETURN_INT(self->GetLightLevel());
}
DEFINE_ACTION_FUNCTION(_Sector, ClearSpecial)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
self->ClearSpecial();
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, PortalBlocksView)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);

View file

@ -259,7 +259,7 @@ void ExpEmit::Reuse(VMFunctionBuilder *build)
//
//==========================================================================
static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func)
static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func, const uint8_t *reginfo)
{
PSymbol *sym = Namespaces.GlobalNamespace->Symbols.FindSymbol(funcname, false);
if (sym == nullptr)
@ -267,6 +267,7 @@ static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCall
PSymbolVMFunction *symfunc = Create<PSymbolVMFunction>(funcname);
VMNativeFunction *calldec = new VMNativeFunction(func, funcname);
calldec->PrintableName = funcname.GetChars();
calldec->RegTypes = reginfo;
symfunc->Function = calldec;
sym = symfunc;
Namespaces.GlobalNamespace->Symbols.AddSymbol(sym);
@ -5487,7 +5488,8 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build)
{
// Call DecoRandom to generate a random number.
VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom);
static const uint8_t reginfo[] = { REGT_POINTER, REGT_INT, REGT_INT };
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom, reginfo);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
@ -5595,7 +5597,8 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
// Call BuiltinRandom to generate a random number.
VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom);
static const uint8_t reginfo[] = { REGT_POINTER, REGT_INT, REGT_INT };
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom, reginfo);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
@ -5714,7 +5717,8 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build)
{
// Call the BuiltinFRandom function to generate a floating point random number..
VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinFRandom, BuiltinFRandom);
static uint8_t reginfo[] = { REGT_POINTER, REGT_FLOAT, REGT_FLOAT };
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinFRandom, BuiltinFRandom, reginfo);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
@ -5793,7 +5797,8 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build)
{
// Call the BuiltinRandom function to generate the random number.
VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom2, BuiltinRandom2);
static uint8_t reginfo[] = { REGT_POINTER, REGT_INT };
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom2, BuiltinRandom2, reginfo);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
@ -5865,7 +5870,8 @@ ExpEmit FxRandomSeed::Emit(VMFunctionBuilder *build)
{
// Call DecoRandom to generate a random number.
VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandomSeed, BuiltinRandomSeed);
static uint8_t reginfo[] = { REGT_POINTER, REGT_INT };
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandomSeed, BuiltinRandomSeed, reginfo);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
@ -8567,7 +8573,8 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
}
// Call the BuiltinCallLineSpecial function to perform the desired special.
VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial, BuiltinCallLineSpecial);
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);
@ -10776,7 +10783,8 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
// Call the BuiltinNameToClass function to convert from 'name' to class.
VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinNameToClass, BuiltinNameToClass);
static uint8_t reginfo[] = { REGT_INT, REGT_POINTER };
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinNameToClass, BuiltinNameToClass, reginfo);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
@ -10885,7 +10893,8 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)
emitters.AddParameterPointerConst(desttype);
VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast);
static uint8_t reginfo[] = { REGT_POINTER, REGT_POINTER };
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast, reginfo);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);

View file

@ -909,6 +909,7 @@ void FFunctionBuildList::Build()
fprintf(dump, "\n*************************************************************************\n%i code bytes\n%i data bytes", codesize * 4, datasize);
fclose(dump);
}
VMFunction::CreateRegUseInfo();
FScriptPosition::StrictErrors = false;
if (Args->CheckParm("-dumpjit")) DumpJit();
mItems.Clear();

View file

@ -943,6 +943,8 @@ void InitThingdef()
auto fcp = NewStruct("FCheckPosition", nullptr);
fcp->mConstructor = *FindFunction(fcp, "_Constructor")->VMPointer;
fcp->mDestructor = *FindFunction(fcp, "_Destructor")->VMPointer;
static const uint8_t reguse[] = { REGT_POINTER };
fcp->mConstructor->RegTypes = fcp->mDestructor->RegTypes = reguse;
fcp->Size = sizeof(FCheckPosition);
fcp->Align = alignof(FCheckPosition);
@ -991,11 +993,6 @@ void SynthesizeFlagFields()
}
}
}
DEFINE_ACTION_FUNCTION(DObject, GameType)
{
PARAM_PROLOGUE;
ACTION_RETURN_INT(gameinfo.gametype);
}
DEFINE_ACTION_FUNCTION(DObject, BAM)
{

View file

@ -319,10 +319,11 @@ class VMFunction
{
public:
bool Unsafe = false;
int VarFlags = 0; // [ZZ] this replaces 5+ bool fields
uint8_t ImplicitArgs = 0; // either 0 for static, 1 for method or 3 for action
int VarFlags = 0; // [ZZ] this replaces 5+ bool fields
unsigned VirtualIndex = ~0u;
FName Name;
const uint8_t *RegTypes = nullptr;
TArray<VMValue> DefaultArgs;
FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong.
@ -352,8 +353,16 @@ public:
}
AllFunctions.Clear();
}
static void CreateRegUseInfo()
{
for (auto f : AllFunctions)
{
f->CreateRegUse();
}
}
static TArray<VMFunction *> AllFunctions;
protected:
void CreateRegUse();
};
class VMNativeFunction : public VMFunction

View file

@ -193,17 +193,20 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam)
const VMRegisters calleereg(callee);
assert(calleefunc != NULL && !(calleefunc->VarFlags & VARF_Native));
assert(numparam == calleefunc->NumArgs || ((int)calleefunc->DefaultArgs.Size() == calleefunc->NumArgs));
assert(numparam == calleefunc->NumArgs);
assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3);
regd = regf = regs = rega = 0;
for (int i = 0; i < calleefunc->NumArgs; ++i)
const uint8_t *reginfo = calleefunc->RegTypes;
assert(reginfo != nullptr);
for (int i = 0; i < calleefunc->NumArgs; ++i, reginfo++)
{
// get all actual parameters and fill the rest from the defaults.
VMValue &p = i < numparam? params[i] : calleefunc->DefaultArgs[i];
if (p.Type < REGT_STRING)
// copy all parameters to the local registers.
VMValue &p = params[i];
assert(*reginfo == p.Type);
if (*reginfo < REGT_STRING)
{
if (p.Type == REGT_INT)
if (*reginfo == REGT_INT)
{
calleereg.d[regd++] = p.i;
}
@ -212,13 +215,13 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam)
calleereg.f[regf++] = p.f;
}
}
else if (p.Type == REGT_STRING)
else if (*reginfo == REGT_STRING)
{
calleereg.s[regs++] = p.s();
}
else
{
assert(p.Type == REGT_POINTER);
assert(*reginfo == REGT_POINTER);
calleereg.a[rega++] = p.a;
}
}

View file

@ -65,6 +65,42 @@ IMPLEMENT_CLASS(VMException, false, false)
TArray<VMFunction *> VMFunction::AllFunctions;
// Creates the register type list for a function.
// Native functions only need this to assert their parameters in debug mode, script functions use this to load their registers from the VMValues.
void VMFunction::CreateRegUse()
{
#ifdef NDEBUG
if (VarFlags & VARF_Native) return; // we do not need this for native functions in release builds.
#endif
int count = 0;
if (!Proto)
{
if (RegTypes) return;
Printf(TEXTCOLOR_ORANGE "Function without prototype needs register info manually set: %s\n", PrintableName.GetChars());
return;
}
assert(Proto->isPrototype());
for (auto arg : Proto->ArgumentTypes)
{
count += arg? arg->GetRegCount() : 1;
}
uint8_t *regp;
RegTypes = regp = (uint8_t*)ClassDataAllocator.Alloc(count);
count = 0;
for (auto arg : Proto->ArgumentTypes)
{
if (arg == nullptr)
{
// Marker for start of varargs.
*regp++ = REGT_NIL;
}
else for (int i = 0; i < arg->GetRegCount(); i++)
{
*regp++ = arg->GetRegType();
}
}
}
VMScriptFunction::VMScriptFunction(FName name)
{
Name = name;

View file

@ -34,6 +34,7 @@ struct SectorPortal native play
struct Vertex native play
{
native readonly Vector2 p;
native int Index();
}
struct Side native play