diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 6ef902500..7cd4455f0 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -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); diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 07a3f1758..26e2ccd99 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -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 *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(argex)->GetValue().GetName()); + emitters.AddParameterIntConst(-static_cast(argex)->GetValue().GetName()); } else { assert(argex->ValueType->GetRegType() == REGT_INT); if (argex->isConstant()) { - build->EmitParamInt(static_cast(argex)->GetValue().GetInt()); + emitters.AddParameterIntConst(static_cast(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 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(desttype))); + EmitterArray emitters; + emitters.AddParameter(clsname, false); + emitters.AddParameterPointerConst(const_cast(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)); } diff --git a/src/scripting/backend/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp index c9df0c5e6..6c16e1a3a 100644 --- a/src/scripting/backend/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -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; +} diff --git a/src/scripting/backend/vmbuilder.h b/src/scripting/backend/vmbuilder.h index cbac7a239..eb28f20d9 100644 --- a/src/scripting/backend/vmbuilder.h +++ b/src/scripting/backend/vmbuilder.h @@ -3,6 +3,7 @@ #include "dobject.h" #include "vmintern.h" +#include 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> 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 diff --git a/src/tarray.h b/src/tarray.h index 8acb083de..c31763df1 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -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++) {