diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 0946b6328..44e675ed2 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -634,7 +634,7 @@ static int GetLine (void) // misc1 = vrange (arg +3), misc2 = hrange (arg+4) -static void CreateMushroomFunc(EmitterArray &emitters, int value1, int value2) +static void CreateMushroomFunc(FunctionCallEmitter &emitters, int value1, int value2) { // A_Mushroom emitters.AddParameterPointerConst(PClass::FindClass("FatShot")); // itemtype emitters.AddParameterIntConst(0); // numspawns @@ -644,7 +644,7 @@ static void CreateMushroomFunc(EmitterArray &emitters, int value1, int value2) } // misc1 = type (arg +0), misc2 = Z-pos (arg +2) -static void CreateSpawnFunc(EmitterArray &emitters, int value1, int value2) +static void CreateSpawnFunc(FunctionCallEmitter &emitters, int value1, int value2) { // A_SpawnItem if (InfoNames[value1-1] == nullptr) { @@ -659,13 +659,13 @@ static void CreateSpawnFunc(EmitterArray &emitters, int value1, int value2) // misc1 = angle (in degrees) (arg +0 but factor in current actor angle too) -static void CreateTurnFunc(EmitterArray &emitters, int value1, int value2) +static void CreateTurnFunc(FunctionCallEmitter &emitters, int value1, int value2) { // A_Turn emitters.AddParameterFloatConst(value1); // angle } // misc1 = angle (in degrees) (arg +0) -static void CreateFaceFunc(EmitterArray &emitters, int value1, int value2) +static void CreateFaceFunc(FunctionCallEmitter &emitters, int value1, int value2) { // A_FaceTarget emitters.AddParameterFloatConst(value1); // angle emitters.AddParameterIntConst(0); // flags @@ -673,7 +673,7 @@ static void CreateFaceFunc(EmitterArray &emitters, int value1, int value2) } // misc1 = damage, misc 2 = sound -static void CreateScratchFunc(EmitterArray &emitters, int value1, int value2) +static void CreateScratchFunc(FunctionCallEmitter &emitters, int value1, int value2) { // A_CustomMeleeAttack emitters.AddParameterIntConst(value1); // damage emitters.AddParameterIntConst(value2 ? (int)SoundMap[value2 - 1] : 0); // hit sound @@ -683,7 +683,7 @@ static void CreateScratchFunc(EmitterArray &emitters, int value1, int value2) } // misc1 = sound, misc2 = attenuation none (true) or normal (false) -static void CreatePlaySoundFunc(EmitterArray &emitters, int value1, int value2) +static void CreatePlaySoundFunc(FunctionCallEmitter &emitters, int value1, int value2) { // A_PlaySound emitters.AddParameterIntConst(value1 ? (int)SoundMap[value1 - 1] : 0); // soundid emitters.AddParameterIntConst(CHAN_BODY); // channel @@ -694,14 +694,14 @@ static void CreatePlaySoundFunc(EmitterArray &emitters, int value1, int value2) } // misc1 = state, misc2 = probability -static void CreateRandomJumpFunc(EmitterArray &emitters, int value1, int value2) +static void CreateRandomJumpFunc(FunctionCallEmitter &emitters, int value1, int value2) { // A_Jump emitters.AddParameterIntConst(value2); // maxchance emitters.AddParameterPointerConst(FindState(value1)); // jumpto } // misc1 = Boom linedef type, misc2 = sector tag -static void CreateLineEffectFunc(EmitterArray &emitters, int value1, int value2) +static void CreateLineEffectFunc(FunctionCallEmitter &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 @@ -713,7 +713,7 @@ static void CreateLineEffectFunc(EmitterArray &emitters, int value1, int value2) } // No misc, but it's basically A_Explode with an added effect -static void CreateNailBombFunc(EmitterArray &emitters, int value1, int value2) +static void CreateNailBombFunc(FunctionCallEmitter &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... @@ -729,7 +729,7 @@ static void CreateNailBombFunc(EmitterArray &emitters, int value1, int value2) } // This array must be in sync with the Aliases array in DEHSUPP. -static void (*MBFCodePointerFactories[])(EmitterArray&, int, int) = +static void (*MBFCodePointerFactories[])(FunctionCallEmitter&, int, int) = { // Die and Detonate are not in this list because these codepointers have // no dehacked arguments and therefore do not need special handling. @@ -776,7 +776,7 @@ 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; + FunctionCallEmitter emitters; for (int i = 0; i < numargs; i++) { emitters.AddParameterPointer(i, false); diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index bccef9061..b746e322a 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -5494,7 +5494,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) assert(min && max); callfunc = ((PSymbolVMFunction *)sym)->Function; - EmitterArray emitters; + FunctionCallEmitter emitters; emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, min); @@ -5601,7 +5601,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - EmitterArray emitters; + FunctionCallEmitter emitters; emitters.AddParameterPointerConst(rng); emitters.AddParameterIntConst(0); emitters.AddParameterIntConst(choices.Size() - 1); @@ -5722,7 +5722,7 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) assert(min && max); callfunc = ((PSymbolVMFunction *)sym)->Function; - EmitterArray emitters; + FunctionCallEmitter emitters; emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, min); emitters.AddParameter(build, max); @@ -5800,7 +5800,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - EmitterArray emitters; + FunctionCallEmitter emitters; emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, mask); @@ -5872,7 +5872,7 @@ ExpEmit FxRandomSeed::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - EmitterArray emitters; + FunctionCallEmitter emitters; emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, seed); @@ -8539,7 +8539,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) { unsigned i = 0; - EmitterArray emitters; + FunctionCallEmitter emitters; emitters.AddParameterIntConst(abs(Special)); // pass special number emitters.AddParameter(build, Self); @@ -8983,7 +8983,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) bool staticcall = ((vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual); count = 0; - EmitterArray emitters; + FunctionCallEmitter emitters; // Emit code to pass implied parameters ExpEmit selfemit; if (Function->Variants[0].Flags & VARF_Method) @@ -9054,63 +9054,18 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) break; } } - count = emitters.EmitParameters(build); - ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); - // Get a constant register for this function - if (staticcall) - { - int funcaddr = build->GetConstantAddress(vmfunc); - // Emit the call - if (vmfunc->Proto->ReturnTypes.Size() > 0) - { // Call, expecting one result - build->Emit(OP_CALL_K, funcaddr, count, MAX(1, AssignCount)); - goto handlereturns; - } - else - { // Call, expecting no results - build->Emit(OP_CALL_K, funcaddr, count, 0); - return ExpEmit(); - } - } - else - { - ExpEmit funcreg(build, REGT_POINTER); + emitters.AddTarget(vmfunc, staticcall? -1 : selfemit.RegNum); + int resultcount = vmfunc->Proto->ReturnTypes.Size() == 0 ? 0 : MAX(AssignCount, 1); - build->Emit(OP_VTBL, funcreg.RegNum, selfemit.RegNum, vmfunc->VirtualIndex); - if (vmfunc->Proto->ReturnTypes.Size() > 0) - { // Call, expecting one result - build->Emit(OP_CALL, funcreg.RegNum, count, MAX(1, AssignCount)); - goto handlereturns; - } - else - { // Call, expecting no results - build->Emit(OP_CALL, funcreg.RegNum, count, 0); - return ExpEmit(); - } - } -handlereturns: - if (AssignCount == 0) + assert((unsigned)resultcount <= vmfunc->Proto->ReturnTypes.Size()); + for (int i = 0; i < resultcount; i++) { - // 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); - return reg; + emitters.AddReturn(vmfunc->Proto->ReturnTypes[i]->GetRegType(), vmfunc->Proto->ReturnTypes[i]->GetRegCount()); } - else - { - // Multi-Assignment call, this must fill in the ReturnRegs array so that the multi-assignment operator can dispatch the return values. - assert((unsigned)AssignCount <= vmfunc->Proto->ReturnTypes.Size()); - for (int i = 0; i < AssignCount; i++) - { - ExpEmit reg(build, vmfunc->Proto->ReturnTypes[i]->GetRegType(), vmfunc->Proto->ReturnTypes[i]->GetRegCount()); - build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); - ReturnRegs.Push(reg); - } - } - return ExpEmit(); + return emitters.EmitCall(build, resultcount > 1? &ReturnRegs : nullptr); } //========================================================================== @@ -10621,7 +10576,7 @@ 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)); - EmitterArray emitters; + FunctionCallEmitter emitters; emitters.AddParameter(reg, false); emitters.AddTarget(pstr->mDestructor); emitters.EmitCall(build); @@ -10816,7 +10771,7 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) { return ExpEmit(build->GetConstantAddress(nullptr), REGT_POINTER, true); } - EmitterArray emitters; + FunctionCallEmitter emitters; emitters.AddParameter(build, basex); emitters.AddParameterPointerConst(const_cast(desttype)); @@ -10925,7 +10880,7 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build) { ExpEmit clsname = basex->Emit(build); - EmitterArray emitters; + FunctionCallEmitter emitters; emitters.AddParameter(clsname, false); emitters.AddParameterPointerConst(desttype); @@ -11311,7 +11266,7 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) { ExpEmit reg(build, REGT_POINTER); build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); - EmitterArray emitters; + FunctionCallEmitter emitters; emitters.AddParameter(reg, false); emitters.AddTarget(pstr->mConstructor); emitters.EmitCall(build); @@ -11338,7 +11293,7 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build) { ExpEmit reg(build, REGT_POINTER); build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); - EmitterArray emitters; + FunctionCallEmitter emitters; emitters.AddParameter(reg, false); emitters.AddTarget(pstr->mDestructor); emitters.EmitCall(build); diff --git a/src/scripting/backend/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp index 40d187390..1aa5c09f7 100644 --- a/src/scripting/backend/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -931,7 +931,7 @@ void FFunctionBuildList::DumpJit() } -void EmitterArray::AddParameter(VMFunctionBuilder *build, FxExpression *operand) +void FunctionCallEmitter::AddParameter(VMFunctionBuilder *build, FxExpression *operand) { ExpEmit where = operand->Emit(build); @@ -958,7 +958,7 @@ void EmitterArray::AddParameter(VMFunctionBuilder *build, FxExpression *operand) }); } -void EmitterArray::AddParameter(ExpEmit &emit, bool reference) +void FunctionCallEmitter::AddParameter(ExpEmit &emit, bool reference) { numparams += emit.RegCount; emitters.push_back([=](VMFunctionBuilder *build) ->int @@ -970,7 +970,7 @@ void EmitterArray::AddParameter(ExpEmit &emit, bool reference) }); } -void EmitterArray::AddParameterPointerConst(void *konst) +void FunctionCallEmitter::AddParameterPointerConst(void *konst) { numparams++; emitters.push_back([=](VMFunctionBuilder *build) ->int @@ -980,7 +980,7 @@ void EmitterArray::AddParameterPointerConst(void *konst) }); } -void EmitterArray::AddParameterPointer(int index, bool konst) +void FunctionCallEmitter::AddParameterPointer(int index, bool konst) { numparams++; emitters.push_back([=](VMFunctionBuilder *build) ->int @@ -990,7 +990,7 @@ void EmitterArray::AddParameterPointer(int index, bool konst) }); } -void EmitterArray::AddParameterFloatConst(double konst) +void FunctionCallEmitter::AddParameterFloatConst(double konst) { numparams++; emitters.push_back([=](VMFunctionBuilder *build) ->int @@ -1000,7 +1000,7 @@ void EmitterArray::AddParameterFloatConst(double konst) }); } -void EmitterArray::AddParameterIntConst(int konst) +void FunctionCallEmitter::AddParameterIntConst(int konst) { numparams++; emitters.push_back([=](VMFunctionBuilder *build) ->int @@ -1018,7 +1018,7 @@ void EmitterArray::AddParameterIntConst(int konst) }); } -void EmitterArray::AddParameterStringConst(const FString &konst) +void FunctionCallEmitter::AddParameterStringConst(const FString &konst) { numparams++; emitters.push_back([=](VMFunctionBuilder *build) ->int @@ -1028,7 +1028,7 @@ void EmitterArray::AddParameterStringConst(const FString &konst) }); } -int EmitterArray::EmitParameters(VMFunctionBuilder *build) +ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray *ReturnRegs) { int paramcount = 0; for (auto &func : emitters) @@ -1036,18 +1036,27 @@ int EmitterArray::EmitParameters(VMFunctionBuilder *build) paramcount += func(build); } assert(paramcount == numparams); - return paramcount; -} + if (virtualselfreg == -1) + { + build->Emit(OP_CALL_K, build->GetConstantAddress(target), paramcount, returns.Size()); + } + else + { + ExpEmit funcreg(build, REGT_POINTER); -ExpEmit EmitterArray::EmitCall(VMFunctionBuilder *build) -{ - int count = EmitParameters(build); - build->Emit(OP_CALL_K, build->GetConstantAddress(target), count, returns.Size()); - if (returns.Size() == 0) return ExpEmit(); + build->Emit(OP_VTBL, funcreg.RegNum, virtualselfreg, target->VirtualIndex); + build->Emit(OP_CALL, funcreg.RegNum, paramcount, returns.Size()); + } - ExpEmit out(build, returns[0]); - build->Emit(OP_RESULT, 0, returns[0], out.RegNum); - return out; + assert(returns.Size() < 2 || ReturnRegs != nullptr); + for (unsigned i = 0; i < returns.Size(); i++) + { + ExpEmit reg(build, returns[i].first, returns[i].second); + build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); + if (ReturnRegs) ReturnRegs->Push(reg); + else return reg; + } + return ExpEmit(); } diff --git a/src/scripting/backend/vmbuilder.h b/src/scripting/backend/vmbuilder.h index 2b019eee4..07ba89ad4 100644 --- a/src/scripting/backend/vmbuilder.h +++ b/src/scripting/backend/vmbuilder.h @@ -163,13 +163,14 @@ extern FFunctionBuildList FunctionBuildList; //========================================================================== extern int EncodeRegType(ExpEmit reg); -class EmitterArray +class FunctionCallEmitter { // std::function and TArray are not compatible so this has to use std::vector instead. std::vector> emitters; - TArray returns; + TArray> returns; unsigned numparams = 0; // This counts the number of pushed elements, which can differ from the number of emitters with vectors. VMFunction *target = nullptr; + int virtualselfreg = -1; public: void AddParameter(VMFunctionBuilder *build, FxExpression *operand); @@ -179,15 +180,15 @@ public: void AddParameterFloatConst(double konst); void AddParameterIntConst(int konst); void AddParameterStringConst(const FString &konst); - int EmitParameters(VMFunctionBuilder *build); - ExpEmit EmitCall(VMFunctionBuilder *build); - void AddReturn(int regtype) + ExpEmit EmitCall(VMFunctionBuilder *build, TArray *ReturnRegs = nullptr); + void AddReturn(int regtype, int regcount = 1) { - returns.Push(regtype); + returns.Push({ regtype, regcount }); } - void AddTarget(VMFunction *func) + void AddTarget(VMFunction *func, int virtreg = -1) { target = func; + virtualselfreg = virtreg; } unsigned Count() const {