Implement Static Function Pointers
This commit is contained in:
parent
88b5d9aba1
commit
e3704605d8
23 changed files with 876 additions and 51 deletions
|
|
@ -949,6 +949,18 @@ void FFunctionBuildList::DumpJit(bool include_gzdoom_pk3)
|
|||
#endif // HAVE_VM_JIT
|
||||
}
|
||||
|
||||
FunctionCallEmitter::FunctionCallEmitter(VMFunction *func)
|
||||
{
|
||||
target = func;
|
||||
is_vararg = target->VarFlags & VARF_VarArg;
|
||||
}
|
||||
|
||||
FunctionCallEmitter::FunctionCallEmitter(class PFunctionPointer *func)
|
||||
{
|
||||
fnptr = func;
|
||||
is_vararg = false; // function pointers cannot point to vararg functions
|
||||
}
|
||||
|
||||
|
||||
void FunctionCallEmitter::AddParameter(VMFunctionBuilder *build, FxExpression *operand)
|
||||
{
|
||||
|
|
@ -959,7 +971,7 @@ void FunctionCallEmitter::AddParameter(VMFunctionBuilder *build, FxExpression *o
|
|||
operand->ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value");
|
||||
}
|
||||
numparams += where.RegCount;
|
||||
if (target->VarFlags & VARF_VarArg)
|
||||
if (is_vararg)
|
||||
for (unsigned i = 0; i < where.RegCount; i++) reginfo.Push(where.RegType & REGT_TYPE);
|
||||
|
||||
emitters.push_back([=](VMFunctionBuilder *build) -> int
|
||||
|
|
@ -982,7 +994,7 @@ void FunctionCallEmitter::AddParameter(VMFunctionBuilder *build, FxExpression *o
|
|||
void FunctionCallEmitter::AddParameter(ExpEmit &emit, bool reference)
|
||||
{
|
||||
numparams += emit.RegCount;
|
||||
if (target->VarFlags & VARF_VarArg)
|
||||
if (is_vararg)
|
||||
{
|
||||
if (reference) reginfo.Push(REGT_POINTER);
|
||||
else for (unsigned i = 0; i < emit.RegCount; i++) reginfo.Push(emit.RegType & REGT_TYPE);
|
||||
|
|
@ -999,7 +1011,7 @@ void FunctionCallEmitter::AddParameter(ExpEmit &emit, bool reference)
|
|||
void FunctionCallEmitter::AddParameterPointerConst(void *konst)
|
||||
{
|
||||
numparams++;
|
||||
if (target->VarFlags & VARF_VarArg)
|
||||
if (is_vararg)
|
||||
reginfo.Push(REGT_POINTER);
|
||||
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
||||
{
|
||||
|
|
@ -1011,7 +1023,7 @@ void FunctionCallEmitter::AddParameterPointerConst(void *konst)
|
|||
void FunctionCallEmitter::AddParameterPointer(int index, bool konst)
|
||||
{
|
||||
numparams++;
|
||||
if (target->VarFlags & VARF_VarArg)
|
||||
if (is_vararg)
|
||||
reginfo.Push(REGT_POINTER);
|
||||
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
||||
{
|
||||
|
|
@ -1023,7 +1035,7 @@ void FunctionCallEmitter::AddParameterPointer(int index, bool konst)
|
|||
void FunctionCallEmitter::AddParameterFloatConst(double konst)
|
||||
{
|
||||
numparams++;
|
||||
if (target->VarFlags & VARF_VarArg)
|
||||
if (is_vararg)
|
||||
reginfo.Push(REGT_FLOAT);
|
||||
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
||||
{
|
||||
|
|
@ -1035,7 +1047,7 @@ void FunctionCallEmitter::AddParameterFloatConst(double konst)
|
|||
void FunctionCallEmitter::AddParameterIntConst(int konst)
|
||||
{
|
||||
numparams++;
|
||||
if (target->VarFlags & VARF_VarArg)
|
||||
if (is_vararg)
|
||||
reginfo.Push(REGT_INT);
|
||||
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
||||
{
|
||||
|
|
@ -1055,7 +1067,7 @@ void FunctionCallEmitter::AddParameterIntConst(int konst)
|
|||
void FunctionCallEmitter::AddParameterStringConst(const FString &konst)
|
||||
{
|
||||
numparams++;
|
||||
if (target->VarFlags & VARF_VarArg)
|
||||
if (is_vararg)
|
||||
reginfo.Push(REGT_STRING);
|
||||
emitters.push_back([=](VMFunctionBuilder *build) ->int
|
||||
{
|
||||
|
|
@ -1074,7 +1086,7 @@ ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray<ExpEmit>
|
|||
paramcount += func(build);
|
||||
}
|
||||
assert(paramcount == numparams);
|
||||
if (target->VarFlags & VARF_VarArg)
|
||||
if (is_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.
|
||||
|
|
@ -1084,9 +1096,24 @@ ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray<ExpEmit>
|
|||
paramcount++;
|
||||
}
|
||||
|
||||
if(fnptr)
|
||||
{
|
||||
ExpEmit reg(build, REGT_POINTER);
|
||||
|
||||
assert(fnptr->Scope != -1);
|
||||
assert(fnptr->PointedType != TypeVoid);
|
||||
|
||||
// OP_LP , Load from memory. rA = *(rB + rkC)
|
||||
// reg = &PFunction->Variants[0] -- PFunction::Variant*
|
||||
build->Emit(OP_LP, reg.RegNum, virtualselfreg, build->GetConstantInt(offsetof(PFunction, Variants) + offsetof(FArray, Array)));
|
||||
// reg = (&PFunction->Variants[0])->Implementation -- VMFunction*
|
||||
build->Emit(OP_LP, reg.RegNum, reg.RegNum, build->GetConstantInt(offsetof(PFunction::Variant, Implementation)));
|
||||
|
||||
if (virtualselfreg == -1)
|
||||
build->Emit(OP_CALL, reg.RegNum, paramcount, vm_jit? static_cast<PPrototype*>(fnptr->PointedType)->ReturnTypes.Size() : returns.Size());
|
||||
|
||||
reg.Free(build);
|
||||
}
|
||||
else if (virtualselfreg == -1)
|
||||
{
|
||||
build->Emit(OP_CALL_K, build->GetConstantAddress(target), paramcount, vm_jit ? target->Proto->ReturnTypes.Size() : returns.Size());
|
||||
}
|
||||
|
|
@ -1110,9 +1137,13 @@ ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray<ExpEmit>
|
|||
}
|
||||
if (vm_jit) // The JIT compiler needs this, but the VM interpreter does not.
|
||||
{
|
||||
for (unsigned i = returns.Size(); i < target->Proto->ReturnTypes.Size(); i++)
|
||||
assert(!fnptr || fnptr->PointedType != TypeVoid);
|
||||
|
||||
PPrototype * proto = fnptr ? static_cast<PPrototype*>(fnptr->PointedType) : target->Proto;
|
||||
|
||||
for (unsigned i = returns.Size(); i < proto->ReturnTypes.Size(); i++)
|
||||
{
|
||||
ExpEmit reg(build, target->Proto->ReturnTypes[i]->RegType, target->Proto->ReturnTypes[i]->RegCount);
|
||||
ExpEmit reg(build, proto->ReturnTypes[i]->RegType, proto->ReturnTypes[i]->RegCount);
|
||||
build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum);
|
||||
reg.Free(build);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue