This commit is contained in:
Rachael Alexanderson 2018-11-18 00:40:03 -05:00
commit 58407c6c8e
5 changed files with 276 additions and 209 deletions

View file

@ -634,126 +634,102 @@ static int GetLine (void)
// misc1 = vrange (arg +3), misc2 = hrange (arg+4)
static int CreateMushroomFunc(VMFunctionBuilder &buildit, int value1, int value2)
static void CreateMushroomFunc(EmitterArray &emitters, int value1, int value2)
{ // A_Mushroom
int typereg = buildit.GetConstantAddress(PClass::FindClass("FatShot"));
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, typereg); // itemtype
buildit.Emit(OP_PARAMI, 0); // numspawns
buildit.Emit(OP_PARAMI, 1); // flag
// vrange
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1? DEHToDouble(value1) : 4.0));
// hrange
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value2? DEHToDouble(value2) : 0.5));
return 5;
emitters.AddParameterPointerConst(PClass::FindClass("FatShot")); // itemtype
emitters.AddParameterIntConst(0); // numspawns
emitters.AddParameterIntConst(1); // flag MSF_Classic
emitters.AddParameterFloatConst(value1? DEHToDouble(value1) : 4.0); // vrange
emitters.AddParameterFloatConst(value2? DEHToDouble(value2) : 0.5); // hrange
}
// misc1 = type (arg +0), misc2 = Z-pos (arg +2)
static int CreateSpawnFunc(VMFunctionBuilder &buildit, int value1, int value2)
static void CreateSpawnFunc(EmitterArray &emitters, int value1, int value2)
{ // A_SpawnItem
if (InfoNames[value1-1] == NULL)
if (InfoNames[value1-1] == nullptr)
{
I_Error("No class found for dehackednum %d!\n", value1+1);
return 0;
}
int typereg = buildit.GetConstantAddress(InfoNames[value1-1]);
int heightreg = buildit.GetConstantFloat(value2);
int distreg = buildit.GetConstantFloat(0);
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, typereg); // itemtype
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, distreg); // distance
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, heightreg); // height
buildit.Emit(OP_PARAMI, 0); // useammo
buildit.Emit(OP_PARAMI, 0); // transfer_translation
return 5;
emitters.AddParameterPointerConst(InfoNames[value1-1]); // itemtype
emitters.AddParameterFloatConst(value2); // distance
emitters.AddParameterFloatConst(0); // height
emitters.AddParameterIntConst(0); // useammo
emitters.AddParameterIntConst(0); // transfer_translation
}
// misc1 = angle (in degrees) (arg +0 but factor in current actor angle too)
static int CreateTurnFunc(VMFunctionBuilder &buildit, int value1, int value2)
static void CreateTurnFunc(EmitterArray &emitters, int value1, int value2)
{ // A_Turn
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1)); // angle
return 1;
emitters.AddParameterFloatConst(value1); // angle
}
// misc1 = angle (in degrees) (arg +0)
static int CreateFaceFunc(VMFunctionBuilder &buildit, int value1, int value2)
static void CreateFaceFunc(EmitterArray &emitters, int value1, int value2)
{ // A_FaceTarget
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1)); // angle
buildit.Emit(OP_PARAMI, 0); // flags
buildit.Emit(OP_PARAMI, AAPTR_DEFAULT); // ptr
return 3;
emitters.AddParameterFloatConst(value1); // angle
emitters.AddParameterIntConst(0); // flags
emitters.AddParameterIntConst(AAPTR_DEFAULT); // ptr
}
// misc1 = damage, misc 2 = sound
static int CreateScratchFunc(VMFunctionBuilder &buildit, int value1, int value2)
static void CreateScratchFunc(EmitterArray &emitters, int value1, int value2)
{ // A_CustomMeleeAttack
buildit.EmitParamInt(value1); // damage
buildit.EmitParamInt(value2? SoundMap[value2 - 1] : 0); // hit sound
buildit.Emit(OP_PARAMI, 0); // miss sound
buildit.Emit(OP_PARAMI, NAME_None); // damage type
buildit.Emit(OP_PARAMI, true); // bleed
return 5;
emitters.AddParameterIntConst(value1); // damage
emitters.AddParameterIntConst(value2 ? (int)SoundMap[value2 - 1] : 0); // hit sound
emitters.AddParameterIntConst(0); // miss sound
emitters.AddParameterIntConst(NAME_None); // damage type
emitters.AddParameterIntConst(true); // bleed
}
// misc1 = sound, misc2 = attenuation none (true) or normal (false)
static int CreatePlaySoundFunc(VMFunctionBuilder &buildit, int value1, int value2)
static void CreatePlaySoundFunc(EmitterArray &emitters, int value1, int value2)
{ // A_PlaySound
int float1 = buildit.GetConstantFloat(1);
int attenreg = buildit.GetConstantFloat(value2 ? ATTN_NONE : ATTN_NORM);
buildit.EmitParamInt(SoundMap[value1-1]); // soundid
buildit.Emit(OP_PARAMI, CHAN_BODY); // channel
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, float1); // volume
buildit.Emit(OP_PARAMI, false); // looping
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, attenreg); // attenuation
buildit.Emit(OP_PARAMI, false); // local
return 6;
emitters.AddParameterIntConst(value1 ? (int)SoundMap[value1 - 1] : 0); // soundid
emitters.AddParameterIntConst(CHAN_BODY); // channel
emitters.AddParameterFloatConst(1); // volume
emitters.AddParameterIntConst(false); // looping
emitters.AddParameterFloatConst(value2 ? ATTN_NONE : ATTN_NORM); // attenuation
emitters.AddParameterIntConst(false); // local
}
// misc1 = state, misc2 = probability
static int CreateRandomJumpFunc(VMFunctionBuilder &buildit, int value1, int value2)
static void CreateRandomJumpFunc(EmitterArray &emitters, int value1, int value2)
{ // A_Jump
int statereg = buildit.GetConstantAddress(FindState(value1));
buildit.EmitParamInt(value2); // maxchance
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, statereg); // jumpto
return 2;
emitters.AddParameterIntConst(value2); // maxchance
emitters.AddParameterPointerConst(FindState(value1)); // jumpto
}
// misc1 = Boom linedef type, misc2 = sector tag
static int CreateLineEffectFunc(VMFunctionBuilder &buildit, int value1, int value2)
static void CreateLineEffectFunc(EmitterArray &emitters, int value1, int value2)
{ // A_LineEffect
// This is the second MBF codepointer that couldn't be translated easily.
// Calling P_TranslateLineDef() here was a simple matter, as was adding an
// extra parameter to A_CallSpecial so as to replicate the LINEDONE stuff,
// but unfortunately DEHACKED lumps are processed before the map translation
// arrays are initialized so this didn't work.
buildit.EmitParamInt(value1); // special
buildit.EmitParamInt(value2); // tag
return 2;
emitters.AddParameterIntConst(value1); // special
emitters.AddParameterIntConst(value2); // tag
}
// No misc, but it's basically A_Explode with an added effect
static int CreateNailBombFunc(VMFunctionBuilder &buildit, int value1, int value2)
static void CreateNailBombFunc(EmitterArray &emitters, int value1, int value2)
{ // A_Explode
// This one does not actually have MBF-style parameters. But since
// we're aliasing it to an extension of A_Explode...
int typereg = buildit.GetConstantAddress(PClass::FindClass(NAME_BulletPuff));
buildit.Emit(OP_PARAMI, -1); // damage
buildit.Emit(OP_PARAMI, -1); // distance
buildit.Emit(OP_PARAMI, 1); // flags (1=XF_HURTSOURCE)
buildit.Emit(OP_PARAMI, 0); // alert
buildit.Emit(OP_PARAMI, 0); // fulldamagedistance
buildit.Emit(OP_PARAMI, 30); // nails
buildit.Emit(OP_PARAMI, 10); // naildamage
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, typereg); // itemtype
buildit.Emit(OP_PARAMI, NAME_None); // damage type
return 9;
emitters.AddParameterIntConst(-1); // damage
emitters.AddParameterIntConst(-1); // distance
emitters.AddParameterIntConst(1); // flags (1=XF_HURTSOURCE)
emitters.AddParameterIntConst(0); // alert
emitters.AddParameterIntConst(0); // fulldamagedistance
emitters.AddParameterIntConst(30); // nails
emitters.AddParameterIntConst(10); // naildamage
emitters.AddParameterPointerConst(PClass::FindClass(NAME_BulletPuff)); // itemtype
emitters.AddParameterIntConst(NAME_None); // damage type
}
// This array must be in sync with the Aliases array in DEHSUPP.
static int (*MBFCodePointerFactories[])(VMFunctionBuilder&, int, int) =
static void (*MBFCodePointerFactories[])(EmitterArray&, int, int) =
{
// Die and Detonate are not in this list because these codepointers have
// no dehacked arguments and therefore do not need special handling.
@ -800,13 +776,15 @@ void SetDehParams(FState *state, int codepointer)
// self, stateowner, state (all are pointers)
buildit.Registers[REGT_POINTER].Get(numargs);
// Emit code to pass the standard action function parameters.
EmitterArray emitters;
for (int i = 0; i < numargs; i++)
{
buildit.Emit(OP_PARAM, REGT_POINTER, i);
emitters.AddParameterPointer(i, false);
}
// Emit code for action parameters.
int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2);
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation), numargs + argcount, 0);
MBFCodePointerFactories[codepointer](emitters, value1, value2);
int count = emitters.EmitParameters(&buildit);
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation), count, 0);
// Attach it to the state.
VMScriptFunction *sfunc = new VMScriptFunction;
buildit.MakeFunction(sfunc);

View file

@ -485,7 +485,7 @@ PPrototype *FxExpression::ReturnProto()
//
//==========================================================================
static int EncodeRegType(ExpEmit reg)
int EncodeRegType(ExpEmit reg)
{
int regtype = reg.RegType;
if (reg.Fixed && reg.Target)
@ -508,36 +508,6 @@ static int EncodeRegType(ExpEmit reg)
return regtype;
}
//==========================================================================
//
//
//
//==========================================================================
static int EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos, TArray<ExpEmit> *tempstrings = nullptr)
{
ExpEmit where = operand->Emit(build);
if (where.RegType == REGT_NIL)
{
pos.Message(MSG_ERROR, "Attempted to pass a non-value");
build->Emit(OP_PARAM, where.RegType, where.RegNum);
return 1;
}
else
{
build->Emit(OP_PARAM, EncodeRegType(where), where.RegNum);
if (tempstrings != nullptr && where.RegType == REGT_STRING && !where.Fixed && !where.Konst)
{
tempstrings->Push(where); // keep temp strings until after the function call.
}
else
{
where.Free(build);
}
return where.RegCount;
}
}
//==========================================================================
//
@ -5539,10 +5509,13 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build)
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));
EmitParameter(build, min, ScriptPosition);
EmitParameter(build, max, ScriptPosition);
build->Emit(opcode, build->GetConstantAddress(callfunc), 3, 1);
EmitterArray emitters;
emitters.AddParameterPointerConst(rng);
emitters.AddParameter(build, min);
emitters.AddParameter(build, max);
int count = emitters.EmitParameters(build);
build->Emit(opcode, build->GetConstantAddress(callfunc), count, 1);
if (EmitTail)
{
@ -5653,10 +5626,12 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function;
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng));
build->EmitParamInt(0);
build->EmitParamInt(choices.Size() - 1);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), 3, 1);
EmitterArray emitters;
emitters.AddParameterPointerConst(rng);
emitters.AddParameterIntConst(0);
emitters.AddParameterIntConst(choices.Size() - 1);
int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1);
ExpEmit resultreg(build, REGT_INT);
build->Emit(OP_RESULT, 0, REGT_INT, resultreg.RegNum);
@ -5775,10 +5750,12 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build)
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));
EmitParameter(build, min, ScriptPosition);
EmitParameter(build, max, ScriptPosition);
build->Emit(opcode, build->GetConstantAddress(callfunc), 3, 1);
EmitterArray emitters;
emitters.AddParameterPointerConst(rng);
emitters.AddParameter(build, min);
emitters.AddParameter(build, max);
int count = emitters.EmitParameters(build);
build->Emit(opcode, build->GetConstantAddress(callfunc), count, 1);
if (EmitTail)
{
@ -5877,9 +5854,12 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build)
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));
EmitParameter(build, mask, ScriptPosition);
build->Emit(opcode, build->GetConstantAddress(callfunc), 2, 1);
EmitterArray emitters;
emitters.AddParameterPointerConst(rng);
emitters.AddParameter(build, mask);
int count = emitters.EmitParameters(build);
build->Emit(opcode, build->GetConstantAddress(callfunc), count, 1);
if (EmitTail)
{
@ -5960,9 +5940,12 @@ ExpEmit FxRandomSeed::Emit(VMFunctionBuilder *build)
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));
EmitParameter(build, seed, ScriptPosition);
build->Emit(opcode, build->GetConstantAddress(callfunc), 2, 0);
EmitterArray emitters;
emitters.AddParameterPointerConst(rng);
emitters.AddParameter(build, seed);
int count = emitters.EmitParameters(build);
build->Emit(opcode, build->GetConstantAddress(callfunc), count, 0);
ExpEmit call;
if (EmitTail) call.Final = true;
@ -8642,10 +8625,13 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
{
unsigned i = 0;
build->Emit(OP_PARAMI, abs(Special)); // pass special number
EmitterArray emitters;
emitters.AddParameterIntConst(abs(Special)); // pass special number
ExpEmit selfemit(Self->Emit(build));
build->Emit(OP_PARAM, selfemit.Konst ? REGT_POINTER | REGT_KONST : REGT_POINTER, selfemit.RegNum); // pass special number
emitters.AddParameterPointer(selfemit.RegNum, selfemit.Konst);
for (; i < ArgList.Size(); ++i)
{
FxExpression *argex = ArgList[i];
@ -8653,20 +8639,18 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
{
assert(argex->ValueType == TypeName);
assert(argex->isConstant());
build->EmitParamInt(-static_cast<FxConstant *>(argex)->GetValue().GetName());
emitters.AddParameterIntConst(-static_cast<FxConstant *>(argex)->GetValue().GetName());
}
else
{
assert(argex->ValueType->GetRegType() == REGT_INT);
if (argex->isConstant())
{
build->EmitParamInt(static_cast<FxConstant *>(argex)->GetValue().GetInt());
emitters.AddParameterIntConst(static_cast<FxConstant *>(argex)->GetValue().GetInt());
}
else
{
ExpEmit arg(argex->Emit(build));
build->Emit(OP_PARAM, arg.RegType, arg.RegNum);
arg.Free(build);
emitters.AddParameter(build, argex);
}
}
}
@ -8681,16 +8665,18 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
ArgList.ShrinkToFit();
if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use
int count = emitters.EmitParameters(build);
selfemit.Free(build);
if (EmitTail)
{
build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc), 2 + i, 0);
build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc), count, 0);
ExpEmit call;
call.Final = true;
return call;
}
ExpEmit dest(build, REGT_INT);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), 2 + i, 1);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1);
build->Emit(OP_RESULT, 0, REGT_INT, dest.RegNum);
return dest;
}
@ -9079,8 +9065,6 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{
TArray<ExpEmit> tempstrings;
assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits);
int count = 0;
@ -9093,7 +9077,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{
ArgList.DeleteAndClear();
ArgList.ShrinkToFit();
for (auto & exp : tempstrings) exp.Free(build);
return reg;
}
}
@ -9102,6 +9085,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
bool staticcall = ((vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual);
count = 0;
EmitterArray emitters;
// Emit code to pass implied parameters
ExpEmit selfemit;
if (Function->Variants[0].Flags & VARF_Method)
@ -9128,64 +9112,51 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
}
}
if ((selfemit.Fixed && selfemit.Target) || selfemit.RegType == REGT_STRING)
{
// Address of a local variable.
build->Emit(OP_PARAM, selfemit.RegType | REGT_ADDROF, selfemit.RegNum);
}
else
{
build->Emit(OP_PARAM, selfemit.RegType, selfemit.RegNum);
}
count += 1;
emitters.AddParameter(selfemit, (selfemit.Fixed && selfemit.Target) || selfemit.RegType == REGT_STRING);
if (Function->Variants[0].Flags & VARF_Action)
{
static_assert(NAP == 3, "This code needs to be updated if NAP changes");
if (build->NumImplicits == NAP && selfemit.RegNum == 0) // only pass this function's stateowner and stateinfo if the subfunction is run in self's context.
{
build->Emit(OP_PARAM, REGT_POINTER, 1);
build->Emit(OP_PARAM, REGT_POINTER, 2);
emitters.AddParameterPointer(1, false);
emitters.AddParameterPointer(2, false);
}
else
{
// pass self as stateowner, otherwise all attempts of the subfunction to retrieve a state from a name would fail.
build->Emit(OP_PARAM, selfemit.RegType, selfemit.RegNum);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(nullptr));
emitters.AddParameter(selfemit, (selfemit.Fixed && selfemit.Target) || selfemit.RegType == REGT_STRING);
emitters.AddParameterPointerConst(nullptr);
}
count += 2;
}
if (staticcall) selfemit.Free(build);
}
else staticcall = true;
// Emit code to pass explicit parameters
for (unsigned i = 0; i < ArgList.Size(); ++i)
{
count += EmitParameter(build, ArgList[i], ScriptPosition, &tempstrings);
emitters.AddParameter(build, ArgList[i]);
}
// Complete the parameter list from the defaults.
auto &defaults = Function->Variants[0].Implementation->DefaultArgs;
for (unsigned i = count; i < defaults.Size(); i++)
for (unsigned i = emitters.Count(); i < defaults.Size(); i++)
{
FxConstant *constant;
switch (defaults[i].Type)
{
default:
case REGT_INT:
constant = new FxConstant(defaults[i].i, ScriptPosition);
emitters.AddParameterIntConst(defaults[i].i);
break;
case REGT_FLOAT:
constant = new FxConstant(defaults[i].f, ScriptPosition);
emitters.AddParameterFloatConst(defaults[i].f);
break;
case REGT_POINTER:
constant = new FxConstant(defaults[i].a, ScriptPosition);
emitters.AddParameterPointerConst(defaults[i].a);
break;
case REGT_STRING:
constant = new FxConstant(defaults[i].s(), ScriptPosition);
emitters.AddParameterStringConst(defaults[i].s());
break;
}
count += EmitParameter(build, constant, ScriptPosition, &tempstrings);
delete constant;
}
count = emitters.EmitParameters(build);
ArgList.DeleteAndClear();
ArgList.ShrinkToFit();
@ -9200,7 +9171,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
build->Emit(OP_TAIL_K, funcaddr, count, 0);
ExpEmit call;
call.Final = true;
for (auto & exp : tempstrings) exp.Free(build);
return call;
}
else if (vmfunc->Proto->ReturnTypes.Size() > 0)
@ -9211,13 +9181,11 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
else
{ // Call, expecting no results
build->Emit(OP_CALL_K, funcaddr, count, 0);
for (auto & exp : tempstrings) exp.Free(build);
return ExpEmit();
}
}
else
{
selfemit.Free(build);
ExpEmit funcreg(build, REGT_POINTER);
build->Emit(OP_VTBL, funcreg.RegNum, selfemit.RegNum, vmfunc->VirtualIndex);
@ -9226,7 +9194,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
build->Emit(OP_TAIL, funcreg.RegNum, count, 0);
ExpEmit call;
call.Final = true;
for (auto & exp : tempstrings) exp.Free(build);
return call;
}
else if (vmfunc->Proto->ReturnTypes.Size() > 0)
@ -9237,7 +9204,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
else
{ // Call, expecting no results
build->Emit(OP_CALL, funcreg.RegNum, count, 0);
for (auto & exp : tempstrings) exp.Free(build);
return ExpEmit();
}
}
@ -9247,7 +9213,6 @@ handlereturns:
// Regular call, will not write to ReturnRegs
ExpEmit reg(build, vmfunc->Proto->ReturnTypes[0]->GetRegType(), vmfunc->Proto->ReturnTypes[0]->GetRegCount());
build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum);
for (auto & exp : tempstrings) exp.Free(build);
return reg;
}
else
@ -9261,7 +9226,6 @@ handlereturns:
ReturnRegs.Push(reg);
}
}
for (auto & exp : tempstrings) exp.Free(build);
return ExpEmit();
}
@ -10773,9 +10737,10 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
assert(pstr->mDestructor != nullptr);
ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(build->ConstructedStructs[i]->StackOffset));
build->Emit(OP_PARAM, reg.RegType, reg.RegNum);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor), 1, 0);
reg.Free(build);
EmitterArray emitters;
emitters.AddParameter(reg, false);
int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor), count, 0);
}
// If we return nothing, use a regular RET opcode.
@ -10970,8 +10935,9 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
ExpEmit clsname = basex->Emit(build);
assert(!clsname.Konst);
ExpEmit dest(build, REGT_POINTER);
build->Emit(OP_PARAM, clsname.RegType, clsname.RegNum);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(const_cast<PClass *>(desttype)));
EmitterArray emitters;
emitters.AddParameter(clsname, false);
emitters.AddParameterPointerConst(const_cast<PClass *>(desttype));
// Call the BuiltinNameToClass function to convert from 'name' to class.
VMFunction *callfunc;
@ -10981,9 +10947,9 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function;
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), 2, 1);
int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1);
build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum);
clsname.Free(build);
return dest;
}
@ -11079,8 +11045,10 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)
{
ExpEmit clsname = basex->Emit(build);
build->Emit(OP_PARAM, clsname.RegType, clsname.RegNum);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(desttype));
EmitterArray emitters;
emitters.AddParameter(clsname, false);
emitters.AddParameterPointerConst(desttype);
VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast);
@ -11088,9 +11056,9 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function;
clsname.Free(build);
ExpEmit dest(build, REGT_POINTER);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), 2, 1);
int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1);
build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum);
return dest;
}
@ -11465,9 +11433,10 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
{
ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
build->Emit(OP_PARAM, reg.RegType, reg.RegNum);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mConstructor), 1, 0);
reg.Free(build);
EmitterArray emitters;
emitters.AddParameter(reg, false);
int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mConstructor), count, 0);
}
if (pstr->mDestructor != nullptr) build->ConstructedStructs.Push(this);
}
@ -11491,9 +11460,10 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build)
{
ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
build->Emit(OP_PARAM, reg.RegType, reg.RegNum);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor), 1, 0);
reg.Free(build);
EmitterArray emitters;
emitters.AddParameter(reg, false);
int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor), count, 0);
}
build->ConstructedStructs.Delete(build->ConstructedStructs.Find(this));
}

View file

@ -654,28 +654,6 @@ size_t VMFunctionBuilder::Emit(int opcode, int opabc)
return Code.Push(op);
}
//==========================================================================
//
// VMFunctionBuilder :: EmitParamInt
//
// Passes a constant integer parameter, using either PARAMI and an immediate
// value or PARAM and a constant register, as appropriate.
//
//==========================================================================
size_t VMFunctionBuilder::EmitParamInt(int value)
{
// Immediates for PARAMI must fit in 24 bits.
if (((value << 8) >> 8) == value)
{
return Emit(OP_PARAMI, value);
}
else
{
return Emit(OP_PARAM, REGT_INT | REGT_KONST, GetConstantInt(value));
}
}
//==========================================================================
//
// VMFunctionBuilder :: EmitLoadInt
@ -951,3 +929,112 @@ void FFunctionBuildList::DumpJit()
fclose(dump);
}
void EmitterArray::AddParameter(VMFunctionBuilder *build, FxExpression *operand)
{
ExpEmit where = operand->Emit(build);
if (where.RegType == REGT_NIL)
{
operand->ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value");
}
numparams += where.RegCount;
emitters.push_back([=](VMFunctionBuilder *build) -> int
{
auto op = where;
if (op.RegType == REGT_NIL)
{
build->Emit(OP_PARAM, op.RegType, op.RegNum);
return 1;
}
else
{
build->Emit(OP_PARAM, EncodeRegType(op), op.RegNum);
op.Free(build);
return op.RegCount;
}
});
}
void EmitterArray::AddParameter(ExpEmit &emit, bool reference)
{
numparams += emit.RegCount;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
build->Emit(OP_PARAM, emit.RegType + (reference * REGT_ADDROF), emit.RegNum);
auto op = emit;
op.Free(build);
return emit.RegCount;
});
}
void EmitterArray::AddParameterPointerConst(void *konst)
{
numparams++;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(konst));
return 1;
});
}
void EmitterArray::AddParameterPointer(int index, bool konst)
{
numparams++;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
build->Emit(OP_PARAM, konst ? REGT_POINTER | REGT_KONST : REGT_POINTER, index);
return 1;
});
}
void EmitterArray::AddParameterFloatConst(double konst)
{
numparams++;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
build->Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(konst));
return 1;
});
}
void EmitterArray::AddParameterIntConst(int konst)
{
numparams++;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
// Immediates for PARAMI must fit in 24 bits.
if (((konst << 8) >> 8) == konst)
{
build->Emit(OP_PARAMI, konst);
}
else
{
build->Emit(OP_PARAM, REGT_INT | REGT_KONST, build->GetConstantInt(konst));
}
return 1;
});
}
void EmitterArray::AddParameterStringConst(const FString &konst)
{
numparams++;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
build->Emit(OP_PARAM, REGT_STRING | REGT_KONST, build->GetConstantString(konst));
return 1;
});
}
int EmitterArray::EmitParameters(VMFunctionBuilder *build)
{
int paramcount = 0;
for (auto &func : emitters)
{
paramcount += func(build);
}
assert(paramcount == numparams);
return paramcount;
}

View file

@ -3,6 +3,7 @@
#include "dobject.h"
#include "vmintern.h"
#include <vector>
class VMFunctionBuilder;
class FxExpression;
@ -68,7 +69,6 @@ public:
size_t Emit(int opcode, int opa, int opb, int opc);
size_t Emit(int opcode, int opa, VM_SHALF opbc);
size_t Emit(int opcode, int opabc);
size_t EmitParamInt(int value);
size_t EmitLoadInt(int regnum, int value);
size_t EmitRetInt(int retnum, bool final, int value);
@ -154,4 +154,34 @@ public:
};
extern FFunctionBuildList FunctionBuildList;
//==========================================================================
//
// Function call parameter collector
//
//==========================================================================
extern int EncodeRegType(ExpEmit reg);
class EmitterArray
{
// std::function and TArray are not compatible so this has to use std::vector instead.
std::vector<std::function<int(VMFunctionBuilder *)>> emitters;
unsigned numparams = 0;
public:
void AddParameter(VMFunctionBuilder *build, FxExpression *operand);
void AddParameter(ExpEmit &emit, bool reference);
void AddParameterPointerConst(void *konst);
void AddParameterPointer(int index, bool konst);
void AddParameterFloatConst(double konst);
void AddParameterIntConst(int konst);
void AddParameterStringConst(const FString &konst);
int EmitParameters(VMFunctionBuilder *build);
unsigned Count() const
{
return numparams;
}
};
#endif

View file

@ -283,6 +283,7 @@ public:
unsigned start = Count;
Grow(item.Size());
Count += item.Size();
for (unsigned i = 0; i < item.Size(); i++)
{
@ -296,6 +297,7 @@ public:
unsigned start = Count;
Grow(item.Size());
Count += item.Size();
for (unsigned i = 0; i < item.Size(); i++)
{