From 808188ff184cb935126cd2a0a37ad135ea2adacf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 24 Oct 2016 13:18:13 +0200 Subject: [PATCH] - added handling for structs. When defined inside classes or other structs the double member access will be merged, so there is no performance hit by using structs to group data. --- src/scripting/codegeneration/codegen.cpp | 134 +++++++++++++++++++---- src/scripting/codegeneration/codegen.h | 22 +++- src/scripting/thingdef_data.cpp | 25 +++-- 3 files changed, 145 insertions(+), 36 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index f882b8b2b..bcea7e9fa 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -4226,14 +4226,15 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) PSymbolTable *symtbl; auto ptype = static_cast(Object->ValueType)->PointedType; - if (ptype->IsKindOf(RUNTIME_CLASS(PClass))) + if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) // PClass is a child class of PStruct so this covers both. { - PClass *cls = static_cast(ptype); + PStruct *cls = static_cast(ptype); + bool isclass = cls->IsKindOf(RUNTIME_CLASS(PClass)); if ((sym = cls->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr) { if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) { - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars()); + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as %s constant\n", Identifier.GetChars(), isclass? "class" : "struct"); newex = FxConstant::MakeConstant(sym, ScriptPosition); } else if (sym->IsKindOf(RUNTIME_CLASS(PField))) @@ -4263,7 +4264,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) delete this; return nullptr; } - auto x = new FxClassMember(Object, vsym, ScriptPosition); + auto x = isclass? new FxClassMember(Object, vsym, ScriptPosition) : new FxStructMember(Object, vsym, ScriptPosition); delete this; return x->Resolve(ctx); } @@ -4281,14 +4282,41 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) return nullptr; } } - else if (ptype->IsA(RUNTIME_CLASS(PStruct))) - { - // todo - } } else if (Object->ValueType->IsA(RUNTIME_CLASS(PStruct))) { - // todo + if ((sym = Object->ValueType->Symbols.FindSymbol(Identifier, false)) != nullptr) + { + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + { + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as struct constant\n", Identifier.GetChars()); + newex = FxConstant::MakeConstant(sym, ScriptPosition); + } + else if (sym->IsKindOf(RUNTIME_CLASS(PField))) + { + PField *vsym = static_cast(sym); + + if (vsym->Flags & VARF_Deprecated) + { + ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars()); + } + auto x = new FxStructMember(Object, vsym, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars()); + delete this; + return nullptr; + } + } + else + { + ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars()); + delete this; + return nullptr; + } } ScriptPosition.Message(MSG_ERROR, "Left side of %s is not a struct or class", Identifier.GetChars()); @@ -4381,13 +4409,13 @@ ExpEmit FxSelf::Emit(VMFunctionBuilder *build) // //========================================================================== -FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition &pos) -: FxExpression(EFX_ClassMember, pos) +FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos) + : FxExpression(EFX_StructMember, pos) { classx = x; membervar = mem; AddressRequested = false; - //if (classx->IsDefaultObject()) Readonly=true; + AddressWritable = true; // must be true unless classx tells us otherwise if requested. } //========================================================================== @@ -4396,7 +4424,7 @@ FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition // //========================================================================== -FxClassMember::~FxClassMember() +FxStructMember::~FxStructMember() { SAFE_DELETE(classx); } @@ -4407,10 +4435,10 @@ FxClassMember::~FxClassMember() // //========================================================================== -bool FxClassMember::RequestAddress(bool *writable) +bool FxStructMember::RequestAddress(bool *writable) { AddressRequested = true; - if (writable != nullptr) *writable = !(membervar->Flags & VARF_ReadOnly); + if (writable != nullptr) *writable = AddressWritable && !(membervar->Flags & VARF_ReadOnly); return true; } @@ -4420,23 +4448,50 @@ bool FxClassMember::RequestAddress(bool *writable) // //========================================================================== -FxExpression *FxClassMember::Resolve(FCompileContext &ctx) +FxExpression *FxStructMember::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); SAFE_RESOLVE(classx, ctx); - PPointer *ptrtype = dyn_cast(classx->ValueType); - if (ptrtype == NULL || !ptrtype->IsKindOf(RUNTIME_CLASS(DObject))) + if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { - ScriptPosition.Message(MSG_ERROR, "Member variable requires a class or object"); - delete this; - return NULL; + PPointer *ptrtype = dyn_cast(classx->ValueType); + if (ptrtype == nullptr || !ptrtype->PointedType->IsA(RUNTIME_CLASS(PStruct))) + { + ScriptPosition.Message(MSG_ERROR, "Member variable requires a struct"); + delete this; + return nullptr; + } + } + else if (classx->ValueType->IsA(RUNTIME_CLASS(PStruct))) + { + // if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. + if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember) + { + auto parentfield = static_cast(classx)->membervar; + // PFields are garbage collected so this will be automatically taken care of later. + auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + static_cast(classx)->membervar = newfield; + classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = classx->Resolve(ctx); + classx = nullptr; + return x; + } + else + { + if (!(classx->RequestAddress(&AddressWritable))) + { + ScriptPosition.Message(MSG_ERROR, "unable to dereference left side of %s", membervar->SymbolName.GetChars()); + delete this; + return nullptr; + } + } } ValueType = membervar->Type; return this; } -ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) +ExpEmit FxStructMember::Emit(VMFunctionBuilder *build) { ExpEmit obj = classx->Emit(build); assert(obj.RegType == REGT_POINTER); @@ -4473,6 +4528,41 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) } +//========================================================================== +// +// +// +//========================================================================== + +FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition &pos) +: FxStructMember(x, mem, pos) +{ + ExprType = EFX_ClassMember; + //if (classx->IsDefaultObject()) Readonly=true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxClassMember::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(classx, ctx); + + PPointer *ptrtype = dyn_cast(classx->ValueType); + if (ptrtype == NULL || !ptrtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + { + ScriptPosition.Message(MSG_ERROR, "Member variable requires a class or object"); + delete this; + return NULL; + } + ValueType = membervar->Type; + return this; +} + //========================================================================== // // diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 9125d5d8c..771faa2c8 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -237,6 +237,7 @@ enum EFxType EFX_FRandom, EFX_Random2, EFX_ClassMember, + EFX_StructMember, EFX_LocalVariable, EFX_Self, EFX_ArrayElement, @@ -1037,20 +1038,35 @@ public: // //========================================================================== -class FxClassMember : public FxExpression +class FxStructMember : public FxExpression { public: FxExpression *classx; PField *membervar; bool AddressRequested; + bool AddressWritable; - FxClassMember(FxExpression*, PField*, const FScriptPosition&); - ~FxClassMember(); + FxStructMember(FxExpression*, PField*, const FScriptPosition&); + ~FxStructMember(); FxExpression *Resolve(FCompileContext&); bool RequestAddress(bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxClassMember +// +//========================================================================== + +class FxClassMember : public FxStructMember +{ +public: + + FxClassMember(FxExpression*, PField*, const FScriptPosition&); + FxExpression *Resolve(FCompileContext&); +}; + //========================================================================== // // FxLocalVariable diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index e11e249ce..03e88b149 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -650,17 +650,17 @@ void InitThingdef() symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid))); symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate))); symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel))); - symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.X))); // must remain read-only! - symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Y))); // must remain read-only! - symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Z))); // must remain read-only! - symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X))); - symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y))); - symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z))); - symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X))); - symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y))); - symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z))); - symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X))); - symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y))); + symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, __Pos.X))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, __Pos.Y))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, __Pos.Z))); // must remain read-only! + symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.X))); + symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.Y))); + symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.Z))); + symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.X))); + symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.Y))); + symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.Z))); + symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Scale.X))); + symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Scale.Y))); symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score))); symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy))); symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina))); @@ -677,6 +677,9 @@ void InitThingdef() symt.AddSymbol(new PField(NAME_VisibleEndAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndAngle))); symt.AddSymbol(new PField(NAME_VisibleEndPitch, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndPitch))); symt.AddSymbol(new PField("AttackSound", TypeSound, VARF_Native, myoffsetof(AActor, AttackSound))); + symt.AddSymbol(new PField("Pos", TypeVector3, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos))); + symt.AddSymbol(new PField("Vel", TypeVector3, VARF_Native, myoffsetof(AActor, Vel))); + symt.AddSymbol(new PField("Scale", TypeVector2, VARF_Native, myoffsetof(AActor, Scale))); symt.AddSymbol(new PField(NAME_Target, TypeActor, VARF_Native, myoffsetof(AActor, target))); symt.AddSymbol(new PField(NAME_Master, TypeActor, VARF_Native, myoffsetof(AActor, master))); symt.AddSymbol(new PField(NAME_Tracer, TypeActor, VARF_Native, myoffsetof(AActor, tracer)));