diff --git a/src/dobjtype.h b/src/dobjtype.h index d31dac3ce..952f4d627 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -708,11 +708,15 @@ protected: class PStruct : public PNamedType { DECLARE_CLASS(PStruct, PNamedType); + public: PStruct(FName name, PTypeBase *outer); TArray Fields; bool HasNativeFields; + // Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use thes two functions for it. + VMFunction *mConstructor = nullptr; + VMFunction *mDestructor = nullptr; virtual PField *AddField(FName name, PType *type, DWORD flags=0); virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0); diff --git a/src/p_map.cpp b/src/p_map.cpp index d48fb4e5a..a3427d486 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -84,6 +84,28 @@ TArray spechit; TArray portalhit; +// FCheckPosition requires explicit contstruction and destruction when used in the VM +DEFINE_ACTION_FUNCTION(_FCheckPosition, _Constructor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition); + new(self) FCheckPosition; + return 0; +} + +DEFINE_ACTION_FUNCTION(_FCheckPosition, _Destructor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition); + self->~FCheckPosition(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_FCheckPosition, ClearLastRipped) +{ + PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition); + self->LastRipped.Clear(); + return 0; +} + //========================================================================== // // CanCollideWith diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index d8c1aa3dd..b2f9d40eb 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5160,6 +5160,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; + 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, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); @@ -5410,6 +5411,7 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; + 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, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); @@ -5504,6 +5506,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; + 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, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); @@ -7801,6 +7804,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use if (EmitTail) { build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 0); @@ -8072,6 +8076,8 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits); int count = 0; + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use + if (count == 1) { ExpEmit reg; @@ -9508,6 +9514,19 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) { ExpEmit out(0, REGT_NIL); + // call the destructors for all structs requiring one. + // go in reverse order of construction + for (int i = build->ConstructedStructs.Size() - 1; i >= 0; i--) + { + auto pstr = static_cast(build->ConstructedStructs[i]->ValueType); + 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, 0, reg.RegType, reg.RegNum); + build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor, ATAG_OBJECT), 1, 0); + reg.Free(build); + } + // If we return nothing, use a regular RET opcode. // Otherwise just return the value we're given. if (Value == nullptr) @@ -10173,6 +10192,19 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) else { // Init arrays and structs. + if (ValueType->IsA(RUNTIME_CLASS(PStruct))) + { + auto pstr = static_cast(ValueType); + if (pstr->mConstructor != nullptr) + { + ExpEmit reg(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); + build->Emit(OP_PARAM, 0, reg.RegType, reg.RegNum); + build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mConstructor, ATAG_OBJECT), 1, 0); + reg.Free(build); + } + if (pstr->mDestructor != nullptr) build->ConstructedStructs.Push(this); + } } return ExpEmit(); } @@ -10184,6 +10216,22 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build) { build->Registers[ValueType->GetRegType()].Return(RegNum, RegCount); } + else + { + if (ValueType->IsA(RUNTIME_CLASS(PStruct))) + { + auto pstr = static_cast(ValueType); + if (pstr->mDestructor != nullptr) + { + ExpEmit reg(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); + build->Emit(OP_PARAM, 0, reg.RegType, reg.RegNum); + build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor, ATAG_OBJECT), 1, 0); + reg.Free(build); + } + build->ConstructedStructs.Delete(build->ConstructedStructs.Find(this)); + } + } // Stack space will not be released because that would make controlled destruction impossible. // For that all local stack variables need to live for the entire execution of a function. } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 08afa6d93..a0a66a776 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -1993,6 +1993,7 @@ class FxLocalVariableDeclaration : public FxExpression public: int StackOffset = -1; int RegNum = -1; + bool constructed = false; FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p); ~FxLocalVariableDeclaration(); diff --git a/src/scripting/codegeneration/dynarrays.cpp b/src/scripting/codegeneration/dynarrays.cpp index 4489bbcb2..05e18a3ca 100644 --- a/src/scripting/codegeneration/dynarrays.cpp +++ b/src/scripting/codegeneration/dynarrays.cpp @@ -37,9 +37,7 @@ ** */ -#define private public // this file needs public access to TArray's private 'Count' field so just hack the visibility qualifiers here #include "tarray.h" -#undef private #include "dobject.h" #include "thingdef.h" // We need one specific type for each of the 7 integral VM types and instantiate the needed functions for each of them. @@ -775,10 +773,10 @@ DEFINE_ACTION_FUNCTION(FDynArray_String, Clear) return 0; } -DEFINE_FIELD_NAMED(FDynArray_I8, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_I16, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_I32, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_F32, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_F64, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_Ptr, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_String, Count, Size) // clashes with type 'Inventory'. +DEFINE_FIELD_NAMED_X(DynArray_I8, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_I16, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_I32, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_F32, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_F64, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_Ptr, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_String, FArray, Count, Size) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index f57509d81..407fd6307 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -50,6 +50,8 @@ #include "zstring.h" #include "d_event.h" #include "g_levellocals.h" +#include "vm.h" +#include "p_checkposition.h" static TArray properties; static TArray AFTable; @@ -856,6 +858,14 @@ void InitThingdef() qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); } + // Add the constructor and destructor to FCheckPosition. + auto fcp = NewStruct("FCheckPosition", nullptr); + fcp->mConstructor = *FindFunction(fcp, "_Constructor")->VMPointer; + fcp->mDestructor = *FindFunction(fcp, "_Destructor")->VMPointer; + fcp->Size = sizeof(FCheckPosition); + fcp->Align = alignof(FCheckPosition); + + FieldTable.Clear(); if (FieldTable.Size() == 0) { diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 2e98e865e..1035c2f8e 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1116,9 +1116,9 @@ struct AFuncDesc MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##icls##_##name; #define DEFINE_FIELD_NAMED_X(cls, icls, name, scriptname) \ - static const FieldDesc VMField_##icls##_##scriptname = { "A" #cls, #scriptname, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ - extern FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr; \ - MSVC_FSEG FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##icls##_##scriptname; + static const FieldDesc VMField_##cls##_##scriptname = { "A" #cls, #scriptname, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ + extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; #define DEFINE_FIELD_X_BIT(cls, icls, name, bitval) \ static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), bitval }; \ diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index da099256e..b7746f1ce 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -5,6 +5,7 @@ class VMFunctionBuilder; class FxExpression; +class FxLocalVariableDeclaration; struct ExpEmit { @@ -92,6 +93,7 @@ public: // keep the frame pointer, if needed, in a register because the LFP opcode is hideously inefficient, requiring more than 20 instructions on x64. ExpEmit FramePointer; + TArray ConstructedStructs; private: struct AddrKonst diff --git a/src/tarray.h b/src/tarray.h index fc9a62587..fe0d8c1e2 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -71,8 +71,8 @@ protected: struct FArray { void *Array; - unsigned int Most; unsigned int Count; + unsigned int Most; }; // T is the type stored in the array. diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index b71b8126a..00720ce79 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -1,3 +1,37 @@ +struct FCheckPosition +{ +/* + + // in + native Actor thing; + native Vector3 pos; + + // out + native sector sector; + native double floorz; + native double ceilingz; + native double dropoffz; + nativeTextureID floorpic; + native int floorterrain; + native sector floorsector; + native TextureID ceilingpic; + native sector ceilingsector; + native bool touchmidtex; + native bool abovemidtex; + native bool floatok; + native bool FromPMove; + native line ceilingline; + native AActor stepthing; + native bool DoRipping; + native bool portalstep; + + native int PushTime; +*/ + + native void ClearLastRipped(); +} + + class Actor : Thinker native { const DEFAULT_HEALTH = 1000;