mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 06:53:58 +00:00
- implemented the basics of a working metadata system.
This will store class meta properties in a separate memory block so that it won't have to muck around with PClass - which made the implementation from the scripting branch relatively useless because extending the data wasn't particularly easy and also not well implemented. This can now be handled just like the defaults.
This commit is contained in:
parent
d5d383ee93
commit
f343d36ea9
9 changed files with 128 additions and 41 deletions
105
src/dobjtype.cpp
105
src/dobjtype.cpp
|
@ -2910,6 +2910,11 @@ PClass::~PClass()
|
|||
M_Free(Defaults);
|
||||
Defaults = nullptr;
|
||||
}
|
||||
if (Meta != nullptr)
|
||||
{
|
||||
M_Free(Meta);
|
||||
Meta = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3047,7 +3052,7 @@ PClass *PClass::FindClass (FName zaname)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
DObject *PClass::CreateNew() const
|
||||
DObject *PClass::CreateNew()
|
||||
{
|
||||
BYTE *mem = (BYTE *)M_Malloc (Size);
|
||||
assert (mem != nullptr);
|
||||
|
@ -3064,7 +3069,7 @@ DObject *PClass::CreateNew() const
|
|||
}
|
||||
ConstructNative (mem);
|
||||
((DObject *)mem)->SetClass (const_cast<PClass *>(this));
|
||||
InitializeSpecials(mem, Defaults);
|
||||
InitializeSpecials(mem, Defaults, &PClass::SpecialInits);
|
||||
return (DObject *)mem;
|
||||
}
|
||||
|
||||
|
@ -3076,7 +3081,7 @@ DObject *PClass::CreateNew() const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::InitializeSpecials(void *addr, void *defaults) const
|
||||
void PClass::InitializeSpecials(void *addr, void *defaults, TArray<FTypeAndOffset> PClass::*Inits)
|
||||
{
|
||||
// Once we reach a native class, we can stop going up the family tree,
|
||||
// since native classes handle initialization natively.
|
||||
|
@ -3085,8 +3090,8 @@ void PClass::InitializeSpecials(void *addr, void *defaults) const
|
|||
return;
|
||||
}
|
||||
assert(ParentClass != nullptr);
|
||||
ParentClass->InitializeSpecials(addr, defaults);
|
||||
for (auto tao : SpecialInits)
|
||||
ParentClass->InitializeSpecials(addr, defaults, Inits);
|
||||
for (auto tao : (this->*Inits))
|
||||
{
|
||||
tao.first->InitializeValue((char*)addr + tao.second, defaults == nullptr? nullptr : ((char*)defaults) + tao.second);
|
||||
}
|
||||
|
@ -3101,7 +3106,7 @@ void PClass::InitializeSpecials(void *addr, void *defaults) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::DestroySpecials(void *addr) const
|
||||
void PClass::DestroySpecials(void *addr)
|
||||
{
|
||||
// Once we reach a native class, we can stop going up the family tree,
|
||||
// since native classes handle deinitialization natively.
|
||||
|
@ -3160,7 +3165,6 @@ void PClass::InitializeDefaults()
|
|||
optr->ObjNext = nullptr;
|
||||
optr->SetClass(this);
|
||||
|
||||
|
||||
// Copy the defaults from the parent but leave the DObject part alone because it contains important data.
|
||||
if (ParentClass->Defaults != nullptr)
|
||||
{
|
||||
|
@ -3174,19 +3178,31 @@ void PClass::InitializeDefaults()
|
|||
{
|
||||
memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject));
|
||||
}
|
||||
|
||||
if (MetaSize != 0)
|
||||
{
|
||||
Meta = (BYTE*)M_Malloc(MetaSize);
|
||||
memset(Meta, 0, MetaSize);
|
||||
if (ParentClass->MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (bRuntimeClass)
|
||||
{
|
||||
// Copy parent values from the parent defaults.
|
||||
assert(ParentClass != nullptr);
|
||||
if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults);
|
||||
if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits);
|
||||
if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits);
|
||||
for (const PField *field : Fields)
|
||||
{
|
||||
if (!(field->Flags & VARF_Native))
|
||||
if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta))
|
||||
{
|
||||
field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits);
|
||||
}
|
||||
if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta))
|
||||
{
|
||||
field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3264,6 +3280,39 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
|
|||
return type;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStruct :: AddField
|
||||
//
|
||||
// Appends a new metadata field to the end of a struct. Returns either the new field
|
||||
// or nullptr if a symbol by that name already exists.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PField *PClass::AddMetaField(FName name, PType *type, DWORD flags)
|
||||
{
|
||||
PField *field = new PField(name, type, flags);
|
||||
|
||||
// The new field is added to the end of this struct, alignment permitting.
|
||||
field->Offset = (MetaSize + (type->Align - 1)) & ~(type->Align - 1);
|
||||
|
||||
// Enlarge this struct to enclose the new field.
|
||||
MetaSize = unsigned(field->Offset + type->Size);
|
||||
|
||||
// This struct's alignment is the same as the largest alignment of any of
|
||||
// its fields.
|
||||
Align = MAX(Align, type->Align);
|
||||
|
||||
if (Symbols.AddSymbol(field) == nullptr)
|
||||
{ // name is already in use
|
||||
field->Destroy();
|
||||
return nullptr;
|
||||
}
|
||||
Fields.Push(field);
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClass :: AddField
|
||||
|
@ -3272,18 +3321,36 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
|
|||
|
||||
PField *PClass::AddField(FName name, PType *type, DWORD flags)
|
||||
{
|
||||
unsigned oldsize = Size;
|
||||
PField *field = Super::AddField(name, type, flags);
|
||||
|
||||
// Only initialize the defaults if they have already been created.
|
||||
// For ZScript this is not the case, it will first define all fields before
|
||||
// setting up any defaults for any class.
|
||||
if (field != nullptr && !(flags & VARF_Native) && Defaults != nullptr)
|
||||
if (!(flags & VARF_Meta))
|
||||
{
|
||||
Defaults = (BYTE *)M_Realloc(Defaults, Size);
|
||||
memset(Defaults + oldsize, 0, Size - oldsize);
|
||||
unsigned oldsize = Size;
|
||||
PField *field = Super::AddField(name, type, flags);
|
||||
|
||||
// Only initialize the defaults if they have already been created.
|
||||
// For ZScript this is not the case, it will first define all fields before
|
||||
// setting up any defaults for any class.
|
||||
if (field != nullptr && !(flags & VARF_Native) && Defaults != nullptr)
|
||||
{
|
||||
Defaults = (BYTE *)M_Realloc(Defaults, Size);
|
||||
memset(Defaults + oldsize, 0, Size - oldsize);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned oldsize = MetaSize;
|
||||
PField *field = AddMetaField(name, type, flags);
|
||||
|
||||
// Only initialize the defaults if they have already been created.
|
||||
// For ZScript this is not the case, it will first define all fields before
|
||||
// setting up any defaults for any class.
|
||||
if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr)
|
||||
{
|
||||
Meta = (BYTE *)M_Realloc(Meta, MetaSize);
|
||||
memset(Meta + oldsize, 0, MetaSize - oldsize);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -557,12 +557,13 @@ enum
|
|||
class PClass : public PNativeStruct
|
||||
{
|
||||
DECLARE_CLASS(PClass, PNativeStruct);
|
||||
protected:
|
||||
// We unravel _WITH_META here just as we did for PType.
|
||||
TArray<FTypeAndOffset> SpecialInits;
|
||||
protected:
|
||||
TArray<FTypeAndOffset> MetaInits;
|
||||
void Derive(PClass *newclass, FName name);
|
||||
void InitializeSpecials(void *addr, void *defaults) const;
|
||||
void InitializeSpecials(void *addr, void *defaults, TArray<FTypeAndOffset> PClass::*Inits);
|
||||
void SetSuper();
|
||||
PField *AddMetaField(FName name, PType *type, DWORD flags);
|
||||
public:
|
||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||
void WriteAllFields(FSerializer &ar, const void *addr) const;
|
||||
|
@ -577,11 +578,14 @@ public:
|
|||
static void StaticBootstrap();
|
||||
|
||||
// Per-class information -------------------------------------
|
||||
TArray<FTypeAndOffset> SpecialInits;
|
||||
PClass *ParentClass; // the class this class derives from
|
||||
const size_t *Pointers; // object pointers defined by this class *only*
|
||||
const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default
|
||||
const size_t *ArrayPointers; // dynamic arrays containing object pointers.
|
||||
BYTE *Defaults;
|
||||
BYTE *Meta; // Per-class static script data
|
||||
unsigned MetaSize;
|
||||
bool bRuntimeClass; // class was defined at run-time, not compile-time
|
||||
bool bExported; // This type has been declared in a script
|
||||
bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility
|
||||
|
@ -593,13 +597,13 @@ public:
|
|||
PClass();
|
||||
~PClass();
|
||||
void InsertIntoHash();
|
||||
DObject *CreateNew() const;
|
||||
DObject *CreateNew();
|
||||
PClass *CreateDerivedClass(FName name, unsigned int size);
|
||||
PField *AddField(FName name, PType *type, DWORD flags=0) override;
|
||||
void InitializeActorInfo();
|
||||
void BuildFlatPointers();
|
||||
void BuildArrayPointers();
|
||||
void DestroySpecials(void *addr) const;
|
||||
void DestroySpecials(void *addr);
|
||||
const PClass *NativeClass() const;
|
||||
|
||||
// Returns true if this type is an ancestor of (or same as) the passed type.
|
||||
|
|
|
@ -58,15 +58,15 @@ enum EScrollDir
|
|||
};
|
||||
|
||||
// actions that don't create objects
|
||||
#define WIPER_ID ((const PClass*)intptr_t(-1))
|
||||
#define TITLE_ID ((const PClass*)intptr_t(-2))
|
||||
#define WIPER_ID ((PClass*)intptr_t(-1))
|
||||
#define TITLE_ID ((PClass*)intptr_t(-2))
|
||||
|
||||
//==========================================================================
|
||||
|
||||
struct FIntermissionAction
|
||||
{
|
||||
int mSize;
|
||||
const PClass *mClass;
|
||||
PClass *mClass;
|
||||
FString mMusic;
|
||||
int mMusicOrder;
|
||||
int mCdTrack;
|
||||
|
|
|
@ -472,7 +472,7 @@ void M_SetMenu(FName menu, int param)
|
|||
}
|
||||
else
|
||||
{
|
||||
const PClass *menuclass = PClass::FindClass(menu);
|
||||
PClass *menuclass = PClass::FindClass(menu);
|
||||
if (menuclass != nullptr)
|
||||
{
|
||||
if (menuclass->IsDescendantOf("GenericMenu"))
|
||||
|
|
|
@ -6371,7 +6371,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build)
|
|||
ExpEmit ob = obj->Emit(build);
|
||||
ob.Free(build);
|
||||
ExpEmit meta(build, REGT_POINTER);
|
||||
build->Emit(OP_META, meta.RegNum, ob.RegNum);
|
||||
build->Emit(OP_CLSS, meta.RegNum, ob.RegNum);
|
||||
build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
|
||||
return meta;
|
||||
|
||||
|
@ -6805,7 +6805,7 @@ ExpEmit FxStructMember::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
obj.Free(build);
|
||||
ExpEmit meta(build, REGT_POINTER);
|
||||
build->Emit(OP_META, meta.RegNum, obj.RegNum);
|
||||
build->Emit(membervar->Flags & VARF_Native? OP_CLSS : OP_META, meta.RegNum, obj.RegNum);
|
||||
obj = meta;
|
||||
}
|
||||
|
||||
|
@ -8832,7 +8832,7 @@ ExpEmit FxGetClass::Emit(VMFunctionBuilder *build)
|
|||
ExpEmit op = Self->Emit(build);
|
||||
op.Free(build);
|
||||
ExpEmit to(build, REGT_POINTER);
|
||||
build->Emit(OP_META, to.RegNum, op.RegNum);
|
||||
build->Emit(OP_CLSS, to.RegNum, op.RegNum);
|
||||
return to;
|
||||
}
|
||||
|
||||
|
@ -8873,7 +8873,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build)
|
|||
if (Self->IsObject())
|
||||
{
|
||||
ExpEmit to(build, REGT_POINTER);
|
||||
build->Emit(OP_META, to.RegNum, op.RegNum);
|
||||
build->Emit(OP_CLSS, to.RegNum, op.RegNum);
|
||||
op = to;
|
||||
op.Free(build);
|
||||
}
|
||||
|
|
|
@ -827,7 +827,14 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul
|
|||
if (i > 0) sc.MustGetStringName(",");
|
||||
if (f->Flags & VARF_Meta)
|
||||
{
|
||||
addr = ((char*)bag.Info) + f->Offset;
|
||||
if (f->Flags & VARF_Native)
|
||||
{
|
||||
addr = ((char*)bag.Info) + f->Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = ((char*)bag.Info->Meta) + f->Offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -109,12 +109,18 @@ begin:
|
|||
reg.atag[a] = ATAG_GENERIC; // using ATAG_FRAMEPOINTER will cause endless asserts.
|
||||
NEXTOP;
|
||||
|
||||
OP(META):
|
||||
OP(CLSS):
|
||||
ASSERTA(a); ASSERTO(B);
|
||||
reg.a[a] = ((DObject*)reg.a[B])->GetClass(); // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer...
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
|
||||
OP(META):
|
||||
ASSERTA(a); ASSERTO(B);
|
||||
reg.a[a] = ((DObject*)reg.a[B])->GetClass()->Meta; // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer...
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
|
||||
OP(LB):
|
||||
ASSERTD(a); ASSERTA(B); ASSERTKD(C);
|
||||
GETADDR(PB,KC,X_READ_NIL);
|
||||
|
|
|
@ -23,7 +23,8 @@ xx(LKF_R, lk, RFRII8, NOP, 0, 0), // load float constant indexed
|
|||
xx(LKS_R, lk, RSRII8, NOP, 0, 0), // load string constant indexed
|
||||
xx(LKP_R, lk, RPRII8, NOP, 0, 0), // load pointer constant indexed
|
||||
xx(LFP, lf, LFP, NOP, 0, 0), // load frame pointer
|
||||
xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta class address
|
||||
xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta data address
|
||||
xx(CLSS, clss, RPRP, NOP, 0, 0), // load a class's descriptor address
|
||||
|
||||
// Load from memory. rA = *(rB + rkC)
|
||||
xx(LB, lb, RIRPKI, LB_R, 4, REGT_INT), // load byte
|
||||
|
|
|
@ -1070,11 +1070,6 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
|||
if (field->Flags & ZCC_Meta)
|
||||
{
|
||||
varflags |= VARF_Meta | VARF_Static | VARF_ReadOnly; // metadata implies readonly
|
||||
if (!(field->Flags & ZCC_Native))
|
||||
{
|
||||
// Non-native meta data is not implemented yet and requires some groundwork in the class copy code.
|
||||
Error(field, "Metadata member %s must be native", FName(field->Names->Name).GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
if (field->Type->ArraySize != nullptr)
|
||||
|
@ -1692,7 +1687,14 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop
|
|||
|
||||
if (f->Flags & VARF_Meta)
|
||||
{
|
||||
addr = ((char*)bag.Info) + f->Offset;
|
||||
if (f->Flags & VARF_Native)
|
||||
{
|
||||
addr = ((char*)bag.Info) + f->Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = ((char*)bag.Info->Meta) + f->Offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue