mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-23 20:43:15 +00:00
- implemented the backend for dynamic arrays. Still needs thorough testing but it should be complete.
- use a memory arena to store flat pointers so that the messed up cleanup can be avoided by deallocating this in bulk. - added a new SO opcode to the VM to execute a write barrier. This is necessary for all objects that are not linked into one global table, i.e. everything except thinkers and class types. - always use the cheaper LOS opcode for reading pointers to classes and defaults because these cannot be destroyed during normal operation. - removed the pointless validation from String.Mid. If the values are read as unsigned the internal validation of FString::Mid will automatically ensure proper results.
This commit is contained in:
parent
4ca69f10c7
commit
56024a1ebe
8 changed files with 376 additions and 147 deletions
|
@ -397,6 +397,23 @@ size_t DObject::PropagateMark()
|
|||
GC::Mark((DObject **)((BYTE *)this + *offsets));
|
||||
offsets++;
|
||||
}
|
||||
|
||||
offsets = info->ArrayPointers;
|
||||
if (offsets == NULL)
|
||||
{
|
||||
const_cast<PClass *>(info)->BuildArrayPointers();
|
||||
offsets = info->ArrayPointers;
|
||||
}
|
||||
while (*offsets != ~(size_t)0)
|
||||
{
|
||||
auto aray = (TArray<DObject*>*)((BYTE *)this + *offsets);
|
||||
for (auto &p : *aray)
|
||||
{
|
||||
GC::Mark(&p);
|
||||
}
|
||||
offsets++;
|
||||
}
|
||||
|
||||
return info->Size;
|
||||
}
|
||||
return 0;
|
||||
|
@ -427,6 +444,28 @@ size_t DObject::PointerSubstitution (DObject *old, DObject *notOld)
|
|||
}
|
||||
offsets++;
|
||||
}
|
||||
|
||||
offsets = info->ArrayPointers;
|
||||
if (offsets == NULL)
|
||||
{
|
||||
const_cast<PClass *>(info)->BuildArrayPointers();
|
||||
offsets = info->ArrayPointers;
|
||||
}
|
||||
while (*offsets != ~(size_t)0)
|
||||
{
|
||||
auto aray = (TArray<DObject*>*)((BYTE *)this + *offsets);
|
||||
for (auto &p : *aray)
|
||||
{
|
||||
if (p == old)
|
||||
{
|
||||
p = notOld;
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
offsets++;
|
||||
}
|
||||
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
|
420
src/dobjtype.cpp
420
src/dobjtype.cpp
|
@ -65,6 +65,7 @@ EXTERN_CVAR(Bool, strictdecorate);
|
|||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
FMemArena FlatpointerArena; // stores the flat pointers because freeing them individually is rather messy.
|
||||
FNamespaceManager Namespaces;
|
||||
|
||||
FTypeTable TypeTable;
|
||||
|
@ -99,7 +100,7 @@ PPointer *TypeVoidPtr;
|
|||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
// A harmless non-NULL FlatPointer for classes without pointers.
|
||||
// A harmless non-nullptr FlatPointer for classes without pointers.
|
||||
static const size_t TheEnd = ~(size_t)0;
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
@ -118,7 +119,7 @@ void DumpTypeTable()
|
|||
{
|
||||
int len = 0;
|
||||
Printf("%4zu:", i);
|
||||
for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext)
|
||||
for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext)
|
||||
{
|
||||
Printf(" -> %s", ty->DescriptiveName());
|
||||
len++;
|
||||
|
@ -161,7 +162,7 @@ IMPLEMENT_CLASS(PClassType, false, false)
|
|||
//==========================================================================
|
||||
|
||||
PClassType::PClassType()
|
||||
: TypeTableType(NULL)
|
||||
: TypeTableType(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -211,7 +212,7 @@ IMPLEMENT_POINTERS_END
|
|||
//==========================================================================
|
||||
|
||||
PType::PType(unsigned int size, unsigned int align)
|
||||
: Size(size), Align(align), HashNext(NULL)
|
||||
: Size(size), Align(align), HashNext(nullptr)
|
||||
{
|
||||
mDescriptiveName = "Type";
|
||||
loadOp = OP_NOP;
|
||||
|
@ -286,6 +287,10 @@ void PType::SetPointer(void *base, unsigned offset, TArray<size_t> *stroffs) con
|
|||
{
|
||||
}
|
||||
|
||||
void PType::SetPointerArray(void *base, unsigned offset, TArray<size_t> *stroffs) const
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: InitializeValue
|
||||
|
@ -831,7 +836,7 @@ PBool::PBool()
|
|||
MemberOnly = false;
|
||||
// Override the default max set by PInt's constructor
|
||||
PSymbolConstNumeric *maxsym = static_cast<PSymbolConstNumeric *>(Symbols.FindSymbol(NAME_Max, false));
|
||||
assert(maxsym != NULL && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
|
||||
assert(maxsym != nullptr && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
|
||||
maxsym->Value = 1;
|
||||
}
|
||||
|
||||
|
@ -1147,7 +1152,7 @@ bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const
|
|||
void PString::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special) const
|
||||
{
|
||||
if (base != nullptr) new((BYTE *)base + offset) FString;
|
||||
if (special != NULL)
|
||||
if (special != nullptr)
|
||||
{
|
||||
special->Push(std::make_pair(this, offset));
|
||||
}
|
||||
|
@ -1415,7 +1420,7 @@ IMPLEMENT_POINTERS_END
|
|||
//==========================================================================
|
||||
|
||||
PPointer::PPointer()
|
||||
: PBasicType(sizeof(void *), alignof(void *)), PointedType(NULL), IsConst(false)
|
||||
: PBasicType(sizeof(void *), alignof(void *)), PointedType(nullptr), IsConst(false)
|
||||
{
|
||||
mDescriptiveName = "NullPointer";
|
||||
SetOps();
|
||||
|
@ -1442,8 +1447,9 @@ PPointer::PPointer(PType *pointsat, bool isconst)
|
|||
|
||||
void PPointer::SetOps()
|
||||
{
|
||||
storeOp = OP_SP;
|
||||
loadOp = (PointedType && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) ? OP_LO : OP_LP;
|
||||
// Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them.
|
||||
storeOp = (loadOp == OP_LO && !static_cast<PClass*>(PointedType)->IsDescendantOf(RUNTIME_CLASS(DThinker))) ? OP_SO : OP_SP;
|
||||
moveOp = OP_MOVEA;
|
||||
RegType = REGT_POINTER;
|
||||
}
|
||||
|
@ -1476,7 +1482,7 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// PPointer :: SetDefaultValue
|
||||
// PPointer :: SetPointer
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
@ -1547,7 +1553,7 @@ PPointer *NewPointer(PType *type, bool isconst)
|
|||
{
|
||||
size_t bucket;
|
||||
PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket);
|
||||
if (ptype == NULL)
|
||||
if (ptype == nullptr)
|
||||
{
|
||||
ptype = new PPointer(type, isconst);
|
||||
TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket);
|
||||
|
@ -1606,18 +1612,6 @@ IMPLEMENT_POINTERS_START(PClassPointer)
|
|||
IMPLEMENT_POINTER(ClassRestriction)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClassPointer - Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PClassPointer::PClassPointer()
|
||||
: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(NULL)
|
||||
{
|
||||
mDescriptiveName = "ClassPointer";
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClassPointer - Parameterized Constructor
|
||||
|
@ -1629,6 +1623,10 @@ PClassPointer::PClassPointer(PClass *restrict)
|
|||
{
|
||||
if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars());
|
||||
else mDescriptiveName = "ClassPointer";
|
||||
// class pointers do not need write barriers because all classes are stored in the global type table and won't get collected.
|
||||
// This means we can use the cheapoer non-barriered opcodes here.
|
||||
loadOp = OP_LOS;
|
||||
storeOp = OP_SP;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1683,7 +1681,7 @@ PClassPointer *NewClassPointer(PClass *restrict)
|
|||
{
|
||||
size_t bucket;
|
||||
PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, &bucket);
|
||||
if (ptype == NULL)
|
||||
if (ptype == nullptr)
|
||||
{
|
||||
ptype = new PClassPointer(restrict);
|
||||
TypeTable.AddType(ptype, RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, bucket);
|
||||
|
@ -1739,7 +1737,7 @@ PEnum *NewEnum(FName name, PTypeBase *outer)
|
|||
size_t bucket;
|
||||
if (outer == nullptr) outer = Namespaces.GlobalNamespace;
|
||||
PType *etype = TypeTable.FindType(RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, &bucket);
|
||||
if (etype == NULL)
|
||||
if (etype == nullptr)
|
||||
{
|
||||
etype = new PEnum(name, outer);
|
||||
TypeTable.AddType(etype, RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, bucket);
|
||||
|
@ -1762,7 +1760,7 @@ IMPLEMENT_POINTERS_END
|
|||
//==========================================================================
|
||||
|
||||
PArray::PArray()
|
||||
: ElementType(NULL), ElementCount(0)
|
||||
: ElementType(nullptr), ElementCount(0)
|
||||
{
|
||||
mDescriptiveName = "Array";
|
||||
}
|
||||
|
@ -1902,7 +1900,7 @@ PArray *NewArray(PType *type, unsigned int count)
|
|||
{
|
||||
size_t bucket;
|
||||
PType *atype = TypeTable.FindType(RUNTIME_CLASS(PArray), (intptr_t)type, count, &bucket);
|
||||
if (atype == NULL)
|
||||
if (atype == nullptr)
|
||||
{
|
||||
atype = new PArray(type, count);
|
||||
TypeTable.AddType(atype, RUNTIME_CLASS(PArray), (intptr_t)type, count, bucket);
|
||||
|
@ -1976,7 +1974,7 @@ PResizableArray *NewResizableArray(PType *type)
|
|||
{
|
||||
size_t bucket;
|
||||
PType *atype = TypeTable.FindType(RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, &bucket);
|
||||
if (atype == NULL)
|
||||
if (atype == nullptr)
|
||||
{
|
||||
atype = new PResizableArray(type);
|
||||
TypeTable.AddType(atype, RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, bucket);
|
||||
|
@ -1999,7 +1997,7 @@ IMPLEMENT_POINTERS_END
|
|||
//==========================================================================
|
||||
|
||||
PDynArray::PDynArray()
|
||||
: ElementType(NULL)
|
||||
: ElementType(nullptr)
|
||||
{
|
||||
mDescriptiveName = "DynArray";
|
||||
Size = sizeof(FArray);
|
||||
|
@ -2046,6 +2044,152 @@ void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
|||
id2 = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PDynArray :: InitializeValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PDynArray::InitializeValue(void *addr, const void *deff) const
|
||||
{
|
||||
const FArray *def = (const FArray*)deff;
|
||||
FArray *aray = (FArray*)addr;
|
||||
|
||||
if (def == nullptr || def->Count == 0)
|
||||
{
|
||||
// Empty arrays do not need construction.
|
||||
*aray = { nullptr, 0, 0 };
|
||||
}
|
||||
else if (ElementType->GetRegType() != REGT_STRING)
|
||||
{
|
||||
// These are just integral values which can be done without any constructor hackery.
|
||||
size_t blocksize = ElementType->Size * def->Count;
|
||||
aray->Array = M_Malloc(blocksize);
|
||||
memcpy(aray->Array, def->Array, blocksize);
|
||||
aray->Most = aray->Count = def->Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-empty string arrays require explicit construction.
|
||||
new(addr) TArray<FString>(*(TArray<FString>*)def);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PDynArray :: DestroyValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PDynArray::DestroyValue(void *addr) const
|
||||
{
|
||||
FArray *aray = (FArray*)addr;
|
||||
|
||||
if (aray->Array != nullptr)
|
||||
{
|
||||
if (ElementType->GetRegType() != REGT_STRING)
|
||||
{
|
||||
M_Free(aray->Array);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Damn those cursed strings again. :(
|
||||
((TArray<FString>*)addr)->~TArray<FString>();
|
||||
}
|
||||
}
|
||||
aray->Count = aray->Most = 0;
|
||||
aray->Array = nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PDynArray :: SetDefaultValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special) const
|
||||
{
|
||||
memset((char*)base + offset, 0, sizeof(FArray)); // same as constructing an empty array.
|
||||
if (special != nullptr)
|
||||
{
|
||||
special->Push(std::make_pair(this, offset));
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PDynArray :: SetPointer
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PDynArray::SetPointerArray(void *base, unsigned offset, TArray<size_t> *special) const
|
||||
{
|
||||
if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
|
||||
{
|
||||
// Add to the list of pointer arrays for this class.
|
||||
special->Push(offset);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PDynArray :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PDynArray::WriteValue(FSerializer &ar, const char *key, const void *addr) const
|
||||
{
|
||||
FArray *aray = (FArray*)addr;
|
||||
if (aray->Count > 0)
|
||||
{
|
||||
if (ar.BeginArray(key))
|
||||
{
|
||||
const BYTE *addrb = (const BYTE *)aray->Array;
|
||||
for (unsigned i = 0; i < aray->Count; ++i)
|
||||
{
|
||||
ElementType->WriteValue(ar, nullptr, addrb);
|
||||
addrb += ElementType->Size;
|
||||
}
|
||||
ar.EndArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PDynArray :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PDynArray::ReadValue(FSerializer &ar, const char *key, void *addr) const
|
||||
{
|
||||
FArray *aray = (FArray*)addr;
|
||||
DestroyValue(addr); // note that even after calling this we still got a validly constructed empty array.
|
||||
|
||||
if (ar.BeginArray(key))
|
||||
{
|
||||
bool readsomething = false;
|
||||
unsigned count = ar.ArraySize();
|
||||
|
||||
size_t blocksize = ElementType->Size * count;
|
||||
aray->Array = M_Malloc(blocksize);
|
||||
memset(aray->Array, 0, blocksize);
|
||||
aray->Most = aray->Count = count;
|
||||
|
||||
BYTE *addrb = (BYTE *)aray->Array;
|
||||
for (unsigned i = 0; i<count; i++)
|
||||
{
|
||||
// Strings must be constructed first.
|
||||
if (ElementType->GetRegType() == REGT_STRING) new(addrb) FString;
|
||||
readsomething |= ElementType->ReadValue(ar, nullptr, addrb);
|
||||
addrb += ElementType->Size;
|
||||
}
|
||||
ar.EndArray();
|
||||
return readsomething;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// NewDynArray
|
||||
|
@ -2059,7 +2203,7 @@ PDynArray *NewDynArray(PType *type)
|
|||
{
|
||||
size_t bucket;
|
||||
PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket);
|
||||
if (atype == NULL)
|
||||
if (atype == nullptr)
|
||||
{
|
||||
FString backingname;
|
||||
|
||||
|
@ -2109,7 +2253,7 @@ IMPLEMENT_POINTERS_END
|
|||
//==========================================================================
|
||||
|
||||
PMap::PMap()
|
||||
: KeyType(NULL), ValueType(NULL)
|
||||
: KeyType(nullptr), ValueType(nullptr)
|
||||
{
|
||||
mDescriptiveName = "Map";
|
||||
Size = sizeof(FMap);
|
||||
|
@ -2169,7 +2313,7 @@ PMap *NewMap(PType *keytype, PType *valuetype)
|
|||
{
|
||||
size_t bucket;
|
||||
PType *maptype = TypeTable.FindType(RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, &bucket);
|
||||
if (maptype == NULL)
|
||||
if (maptype == nullptr)
|
||||
{
|
||||
maptype = new PMap(keytype, valuetype);
|
||||
TypeTable.AddType(maptype, RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, bucket);
|
||||
|
@ -2308,7 +2452,7 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const
|
|||
foundsomething = true;
|
||||
|
||||
const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true);
|
||||
if (sym == NULL)
|
||||
if (sym == nullptr)
|
||||
{
|
||||
DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n",
|
||||
label, TypeName.GetChars());
|
||||
|
@ -2332,7 +2476,7 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const
|
|||
// PStruct :: AddField
|
||||
//
|
||||
// Appends a new field to the end of a struct. Returns either the new field
|
||||
// or NULL if a symbol by that name already exists.
|
||||
// or nullptr if a symbol by that name already exists.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
@ -2350,10 +2494,10 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags)
|
|||
// its fields.
|
||||
Align = MAX(Align, type->Align);
|
||||
|
||||
if (Symbols.AddSymbol(field) == NULL)
|
||||
if (Symbols.AddSymbol(field) == nullptr)
|
||||
{ // name is already in use
|
||||
delete field;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
Fields.Push(field);
|
||||
|
||||
|
@ -2365,7 +2509,7 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags)
|
|||
// PStruct :: AddField
|
||||
//
|
||||
// Appends a new native field to the struct. Returns either the new field
|
||||
// or NULL if a symbol by that name already exists.
|
||||
// or nullptr if a symbol by that name already exists.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
@ -2408,7 +2552,7 @@ PStruct *NewStruct(FName name, PTypeBase *outer)
|
|||
size_t bucket;
|
||||
if (outer == nullptr) outer = Namespaces.GlobalNamespace;
|
||||
PType *stype = TypeTable.FindType(RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, &bucket);
|
||||
if (stype == NULL)
|
||||
if (stype == nullptr)
|
||||
{
|
||||
stype = new PStruct(name, outer);
|
||||
TypeTable.AddType(stype, RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, bucket);
|
||||
|
@ -2447,7 +2591,7 @@ PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer)
|
|||
size_t bucket;
|
||||
if (outer == nullptr) outer = Namespaces.GlobalNamespace;
|
||||
PType *stype = TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, &bucket);
|
||||
if (stype == NULL)
|
||||
if (stype == nullptr)
|
||||
{
|
||||
stype = new PNativeStruct(name, outer);
|
||||
TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket);
|
||||
|
@ -2466,7 +2610,7 @@ IMPLEMENT_CLASS(PField, false, false)
|
|||
//==========================================================================
|
||||
|
||||
PField::PField()
|
||||
: PSymbol(NAME_None), Offset(0), Type(NULL), Flags(0)
|
||||
: PSymbol(NAME_None), Offset(0), Type(nullptr), Flags(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -2599,7 +2743,7 @@ PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *>
|
|||
{
|
||||
size_t bucket;
|
||||
PType *proto = TypeTable.FindType(RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, &bucket);
|
||||
if (proto == NULL)
|
||||
if (proto == nullptr)
|
||||
{
|
||||
proto = new PPrototype(rettypes, argtypes);
|
||||
TypeTable.AddType(proto, RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, bucket);
|
||||
|
@ -2689,7 +2833,7 @@ IMPLEMENT_POINTERS_END
|
|||
|
||||
static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void *addr)
|
||||
{
|
||||
if (type != NULL)
|
||||
if (type != nullptr)
|
||||
{
|
||||
RecurseWriteFields(type->ParentClass, ar, addr);
|
||||
// Don't write this part if it has no non-transient variables
|
||||
|
@ -2773,7 +2917,7 @@ bool PClass::ReadAllFields(FSerializer &ar, void *addr) const
|
|||
{
|
||||
// Only read it if the type is related to this one.
|
||||
const PClass *parent;
|
||||
for (parent = this; parent != NULL; parent = parent->ParentClass)
|
||||
for (parent = this; parent != nullptr; parent = parent->ParentClass)
|
||||
{
|
||||
if (parent == type)
|
||||
{
|
||||
|
@ -2835,7 +2979,7 @@ void PClass::StaticInit ()
|
|||
|
||||
FAutoSegIterator probe(CRegHead, CRegTail);
|
||||
|
||||
while (*++probe != NULL)
|
||||
while (*++probe != nullptr)
|
||||
{
|
||||
((ClassReg *)*probe)->RegisterClass ();
|
||||
}
|
||||
|
@ -2859,16 +3003,12 @@ void PClass::StaticInit ()
|
|||
//
|
||||
// PClass :: StaticShutdown STATIC
|
||||
//
|
||||
// Frees FlatPointers belonging to all classes. Only really needed to avoid
|
||||
// memory leak warnings at exit.
|
||||
// Frees all static class data.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::StaticShutdown ()
|
||||
{
|
||||
TArray<size_t *> uniqueFPs(64);
|
||||
unsigned int i, j;
|
||||
|
||||
// delete all variables containing pointers to script functions.
|
||||
for (auto p : FunctionPtrList)
|
||||
{
|
||||
|
@ -2876,7 +3016,8 @@ void PClass::StaticShutdown ()
|
|||
}
|
||||
FunctionPtrList.Clear();
|
||||
|
||||
// Make a full garbage collection here so that all destroyed but uncollected higher level objects that still exist can be properly taken down.
|
||||
// Make a full garbage collection here so that all destroyed but uncollected higher level objects
|
||||
// that still exist are properly taken down before the low level data is deleted.
|
||||
GC::FullGC();
|
||||
|
||||
// From this point onward no scripts may be called anymore because the data needed by the VM is getting deleted now.
|
||||
|
@ -2886,33 +3027,7 @@ void PClass::StaticShutdown ()
|
|||
// Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts.
|
||||
TypeTable.Clear();
|
||||
Namespaces.ReleaseSymbols();
|
||||
|
||||
for (i = 0; i < PClass::AllClasses.Size(); ++i)
|
||||
{
|
||||
PClass *type = PClass::AllClasses[i];
|
||||
PClass::AllClasses[i] = NULL;
|
||||
if (type->FlatPointers != &TheEnd && type->FlatPointers != type->Pointers)
|
||||
{
|
||||
// FlatPointers are shared by many classes, so we must check for
|
||||
// duplicates and only delete those that are unique.
|
||||
for (j = 0; j < uniqueFPs.Size(); ++j)
|
||||
{
|
||||
if (type->FlatPointers == uniqueFPs[j])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == uniqueFPs.Size())
|
||||
{
|
||||
uniqueFPs.Push(const_cast<size_t *>(type->FlatPointers));
|
||||
}
|
||||
}
|
||||
type->Destroy();
|
||||
}
|
||||
for (i = 0; i < uniqueFPs.Size(); ++i)
|
||||
{
|
||||
delete[] uniqueFPs[i];
|
||||
}
|
||||
FlatpointerArena.FreeAllBlocks();
|
||||
bShutdown = true;
|
||||
|
||||
AllClasses.Clear();
|
||||
|
@ -2946,7 +3061,7 @@ void PClass::StaticBootstrap()
|
|||
PClassClass *cls = new PClassClass;
|
||||
PClass::RegistrationInfo.SetupClass(cls);
|
||||
|
||||
// The PClassClass constructor initialized these to NULL, because the
|
||||
// The PClassClass constructor initialized these to nullptr, because the
|
||||
// PClass metadata had not been created yet. Now it has, so we know what
|
||||
// they should be and can insert them into the type table successfully.
|
||||
clscls->TypeTableType = cls;
|
||||
|
@ -2971,6 +3086,7 @@ PClass::PClass()
|
|||
ParentClass = nullptr;
|
||||
Pointers = nullptr;
|
||||
FlatPointers = nullptr;
|
||||
ArrayPointers = nullptr;
|
||||
HashNext = nullptr;
|
||||
Defaults = nullptr;
|
||||
bRuntimeClass = false;
|
||||
|
@ -2990,10 +3106,10 @@ PClass::PClass()
|
|||
|
||||
PClass::~PClass()
|
||||
{
|
||||
if (Defaults != NULL)
|
||||
if (Defaults != nullptr)
|
||||
{
|
||||
M_Free(Defaults);
|
||||
Defaults = NULL;
|
||||
Defaults = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3020,7 +3136,7 @@ PClass *ClassReg::RegisterClass()
|
|||
};
|
||||
|
||||
// Skip classes that have already been registered
|
||||
if (MyClass != NULL)
|
||||
if (MyClass != nullptr)
|
||||
{
|
||||
return MyClass;
|
||||
}
|
||||
|
@ -3059,7 +3175,7 @@ PClass *ClassReg::RegisterClass()
|
|||
|
||||
void ClassReg::SetupClass(PClass *cls)
|
||||
{
|
||||
assert(MyClass == NULL);
|
||||
assert(MyClass == nullptr);
|
||||
MyClass = cls;
|
||||
cls->TypeName = FName(Name+1);
|
||||
cls->Size = SizeOf;
|
||||
|
@ -3082,7 +3198,7 @@ void PClass::InsertIntoHash ()
|
|||
PType *found;
|
||||
|
||||
found = TypeTable.FindType(RUNTIME_CLASS(PClass), 0, TypeName, &bucket);
|
||||
if (found != NULL)
|
||||
if (found != nullptr)
|
||||
{ // This type has already been inserted
|
||||
I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars());
|
||||
}
|
||||
|
@ -3102,14 +3218,14 @@ void PClass::InsertIntoHash ()
|
|||
|
||||
const PClass *PClass::FindParentClass(FName name) const
|
||||
{
|
||||
for (const PClass *type = this; type != NULL; type = type->ParentClass)
|
||||
for (const PClass *type = this; type != nullptr; type = type->ParentClass)
|
||||
{
|
||||
if (type->TypeName == name)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3124,9 +3240,9 @@ PClass *PClass::FindClass (FName zaname)
|
|||
{
|
||||
if (zaname == NAME_None)
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<PClass *>(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, NULL));
|
||||
return static_cast<PClass *>(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, nullptr));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3140,10 +3256,10 @@ PClass *PClass::FindClass (FName zaname)
|
|||
DObject *PClass::CreateNew() const
|
||||
{
|
||||
BYTE *mem = (BYTE *)M_Malloc (Size);
|
||||
assert (mem != NULL);
|
||||
assert (mem != nullptr);
|
||||
|
||||
// Set this object's defaults before constructing it.
|
||||
if (Defaults != NULL)
|
||||
if (Defaults != nullptr)
|
||||
memcpy (mem, Defaults, Size);
|
||||
else
|
||||
memset (mem, 0, Size);
|
||||
|
@ -3170,7 +3286,7 @@ void PClass::InitializeSpecials(void *addr, void *defaults) const
|
|||
{
|
||||
return;
|
||||
}
|
||||
assert(ParentClass != NULL);
|
||||
assert(ParentClass != nullptr);
|
||||
ParentClass->InitializeSpecials(addr, defaults);
|
||||
for (auto tao : SpecialInits)
|
||||
{
|
||||
|
@ -3195,7 +3311,7 @@ void PClass::DestroySpecials(void *addr) const
|
|||
{
|
||||
return;
|
||||
}
|
||||
assert(ParentClass != NULL);
|
||||
assert(ParentClass != nullptr);
|
||||
ParentClass->DestroySpecials(addr);
|
||||
for (auto tao : SpecialInits)
|
||||
{
|
||||
|
@ -3231,7 +3347,7 @@ void PClass::InitializeDefaults()
|
|||
{
|
||||
if (IsKindOf(RUNTIME_CLASS(PClassActor)))
|
||||
{
|
||||
assert(Defaults == NULL);
|
||||
assert(Defaults == nullptr);
|
||||
Defaults = (BYTE *)M_Malloc(Size);
|
||||
|
||||
// run the constructor on the defaults to set the vtbl pointer which is needed to run class-aware functions on them.
|
||||
|
@ -3248,7 +3364,7 @@ void PClass::InitializeDefaults()
|
|||
|
||||
|
||||
// Copy the defaults from the parent but leave the DObject part alone because it contains important data.
|
||||
if (ParentClass->Defaults != NULL)
|
||||
if (ParentClass->Defaults != nullptr)
|
||||
{
|
||||
memcpy(Defaults + sizeof(DObject), ParentClass->Defaults + sizeof(DObject), ParentClass->Size - sizeof(DObject));
|
||||
if (Size > ParentClass->Size)
|
||||
|
@ -3265,7 +3381,7 @@ void PClass::InitializeDefaults()
|
|||
if (bRuntimeClass)
|
||||
{
|
||||
// Copy parent values from the parent defaults.
|
||||
assert(ParentClass != NULL);
|
||||
assert(ParentClass != nullptr);
|
||||
ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults);
|
||||
|
||||
for (const PField *field : Fields)
|
||||
|
@ -3404,14 +3520,14 @@ PClass *PClass::FindClassTentative(FName name)
|
|||
{
|
||||
if (name == NAME_None)
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
size_t bucket;
|
||||
|
||||
PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass),
|
||||
/*FIXME:Outer*/0, name, &bucket);
|
||||
|
||||
if (found != NULL)
|
||||
if (found != nullptr)
|
||||
{
|
||||
return static_cast<PClass *>(found);
|
||||
}
|
||||
|
@ -3484,14 +3600,14 @@ int PClass::FindVirtualIndex(FName name, PPrototype *proto)
|
|||
|
||||
void PClass::BuildFlatPointers ()
|
||||
{
|
||||
if (FlatPointers != NULL)
|
||||
if (FlatPointers != nullptr)
|
||||
{ // Already built: Do nothing.
|
||||
return;
|
||||
}
|
||||
else if (ParentClass == NULL)
|
||||
else if (ParentClass == nullptr)
|
||||
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
|
||||
if (Pointers == NULL)
|
||||
{ // No pointers: Make FlatPointers a harmless non-NULL.
|
||||
if (Pointers == nullptr)
|
||||
{ // No pointers: Make FlatPointers a harmless non-nullptr.
|
||||
FlatPointers = &TheEnd;
|
||||
}
|
||||
else
|
||||
|
@ -3536,7 +3652,7 @@ void PClass::BuildFlatPointers ()
|
|||
{ }
|
||||
|
||||
// Concatenate them into a new array
|
||||
size_t *flat = new size_t[numPointers + numSuperPointers + ScriptPointers.Size() + 1];
|
||||
size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1));
|
||||
if (numSuperPointers > 0)
|
||||
{
|
||||
memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers);
|
||||
|
@ -3555,6 +3671,68 @@ void PClass::BuildFlatPointers ()
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClass :: BuildArrayPointers
|
||||
//
|
||||
// same as above, but creates a list to dynamic object arrays
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::BuildArrayPointers()
|
||||
{
|
||||
if (ArrayPointers != nullptr)
|
||||
{ // Already built: Do nothing.
|
||||
return;
|
||||
}
|
||||
else if (ParentClass == nullptr)
|
||||
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
|
||||
ArrayPointers = &TheEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
ParentClass->BuildArrayPointers();
|
||||
|
||||
TArray<size_t> ScriptPointers;
|
||||
|
||||
// Collect all arrays to pointers in scripted fields.
|
||||
for (auto field : Fields)
|
||||
{
|
||||
if (!(field->Flags & VARF_Native))
|
||||
{
|
||||
field->Type->SetPointerArray(Defaults, unsigned(field->Offset), &ScriptPointers);
|
||||
}
|
||||
}
|
||||
|
||||
if (ScriptPointers.Size() == 0)
|
||||
{ // No new pointers: Just use the same ArrayPointers as the parent.
|
||||
ArrayPointers = ParentClass->ArrayPointers;
|
||||
}
|
||||
else
|
||||
{ // New pointers: Create a new FlatPointers array and add them.
|
||||
int numSuperPointers;
|
||||
|
||||
// Count pointers defined by superclasses.
|
||||
for (numSuperPointers = 0; ParentClass->ArrayPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++)
|
||||
{
|
||||
}
|
||||
|
||||
// Concatenate them into a new array
|
||||
size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1));
|
||||
if (numSuperPointers > 0)
|
||||
{
|
||||
memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers);
|
||||
}
|
||||
if (ScriptPointers.Size() > 0)
|
||||
{
|
||||
memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size());
|
||||
}
|
||||
flat[numSuperPointers + ScriptPointers.Size()] = ~(size_t)0;
|
||||
ArrayPointers = flat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClass :: NativeClass
|
||||
|
@ -3604,18 +3782,18 @@ void PClass::FindFunction(VMFunction **pptr, FName clsname, FName funcname)
|
|||
PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum)
|
||||
{
|
||||
size_t bucket = Hash(metatype, parm1, parm2) % HASH_SIZE;
|
||||
if (bucketnum != NULL)
|
||||
if (bucketnum != nullptr)
|
||||
{
|
||||
*bucketnum = bucket;
|
||||
}
|
||||
for (PType *type = TypeHash[bucket]; type != NULL; type = type->HashNext)
|
||||
for (PType *type = TypeHash[bucket]; type != nullptr; type = type->HashNext)
|
||||
{
|
||||
if (type->GetClass()->TypeTableType == metatype && type->IsMatch(parm1, parm2))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3630,13 +3808,13 @@ PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, si
|
|||
|
||||
void FTypeTable::ReplaceType(PType *newtype, PType *oldtype, size_t bucket)
|
||||
{
|
||||
for (PType **type_p = &TypeHash[bucket]; *type_p != NULL; type_p = &(*type_p)->HashNext)
|
||||
for (PType **type_p = &TypeHash[bucket]; *type_p != nullptr; type_p = &(*type_p)->HashNext)
|
||||
{
|
||||
PType *type = *type_p;
|
||||
if (type == oldtype)
|
||||
{
|
||||
newtype->HashNext = type->HashNext;
|
||||
type->HashNext = NULL;
|
||||
type->HashNext = nullptr;
|
||||
*type_p = newtype;
|
||||
break;
|
||||
}
|
||||
|
@ -3654,7 +3832,7 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t
|
|||
#ifdef _DEBUG
|
||||
size_t bucketcheck;
|
||||
assert(metatype == type->GetClass()->TypeTableType && "Metatype does not match passed object");
|
||||
assert(FindType(metatype, parm1, parm2, &bucketcheck) == NULL && "Type must not be inserted more than once");
|
||||
assert(FindType(metatype, parm1, parm2, &bucketcheck) == nullptr && "Type must not be inserted more than once");
|
||||
assert(bucketcheck == bucket && "Passed bucket was wrong");
|
||||
#endif
|
||||
type->HashNext = TypeHash[bucket];
|
||||
|
@ -3677,7 +3855,7 @@ void FTypeTable::AddType(PType *type)
|
|||
metatype = type->GetClass()->TypeTableType;
|
||||
type->GetTypeIDs(parm1, parm2);
|
||||
bucket = Hash(metatype, parm1, parm2) % HASH_SIZE;
|
||||
assert(FindType(metatype, parm1, parm2, NULL) == NULL && "Type must not be inserted more than once");
|
||||
assert(FindType(metatype, parm1, parm2, nullptr) == nullptr && "Type must not be inserted more than once");
|
||||
|
||||
type->HashNext = TypeHash[bucket];
|
||||
TypeHash[bucket] = type;
|
||||
|
@ -3732,7 +3910,7 @@ void FTypeTable::Mark()
|
|||
{
|
||||
for (int i = HASH_SIZE - 1; i >= 0; --i)
|
||||
{
|
||||
if (TypeHash[i] != NULL)
|
||||
if (TypeHash[i] != nullptr)
|
||||
{
|
||||
GC::Mark(TypeHash[i]);
|
||||
}
|
||||
|
@ -3790,7 +3968,7 @@ PSymbol::~PSymbol()
|
|||
}
|
||||
|
||||
PSymbolTable::PSymbolTable()
|
||||
: ParentSymbolTable(NULL)
|
||||
: ParentSymbolTable(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -3833,24 +4011,24 @@ void PSymbolTable::SetParentTable (PSymbolTable *parent)
|
|||
PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const
|
||||
{
|
||||
PSymbol * const *value = Symbols.CheckKey(symname);
|
||||
if (value == NULL && searchparents && ParentSymbolTable != NULL)
|
||||
if (value == nullptr && searchparents && ParentSymbolTable != nullptr)
|
||||
{
|
||||
return ParentSymbolTable->FindSymbol(symname, searchparents);
|
||||
}
|
||||
return value != NULL ? *value : NULL;
|
||||
return value != nullptr ? *value : nullptr;
|
||||
}
|
||||
|
||||
PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable)
|
||||
{
|
||||
PSymbol * const *value = Symbols.CheckKey(symname);
|
||||
if (value == NULL)
|
||||
if (value == nullptr)
|
||||
{
|
||||
if (ParentSymbolTable != NULL)
|
||||
if (ParentSymbolTable != nullptr)
|
||||
{
|
||||
return ParentSymbolTable->FindSymbolInTable(symname, symtable);
|
||||
}
|
||||
symtable = NULL;
|
||||
return NULL;
|
||||
symtable = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
symtable = this;
|
||||
return *value;
|
||||
|
@ -3859,9 +4037,9 @@ PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable)
|
|||
PSymbol *PSymbolTable::AddSymbol (PSymbol *sym)
|
||||
{
|
||||
// Symbols that already exist are not inserted.
|
||||
if (Symbols.CheckKey(sym->SymbolName) != NULL)
|
||||
if (Symbols.CheckKey(sym->SymbolName) != nullptr)
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
Symbols.Insert(sym->SymbolName, sym);
|
||||
return sym;
|
||||
|
@ -3878,16 +4056,16 @@ PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym)
|
|||
{
|
||||
// If a symbol with a matching name exists, take its place and return it.
|
||||
PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName);
|
||||
if (symslot != NULL)
|
||||
if (symslot != nullptr)
|
||||
{
|
||||
PSymbol *oldsym = *symslot;
|
||||
*symslot = newsym;
|
||||
return oldsym;
|
||||
}
|
||||
// Else, just insert normally and return NULL since there was no
|
||||
// Else, just insert normally and return nullptr since there was no
|
||||
// symbol to replace.
|
||||
Symbols.Insert(newsym->SymbolName, newsym);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(PNamespace, false, true)
|
||||
|
@ -3969,7 +4147,7 @@ void RemoveUnusedSymbols()
|
|||
// We do not need any non-field and non-function symbols in structs and classes anymore.
|
||||
for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i)
|
||||
{
|
||||
for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext)
|
||||
for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext)
|
||||
{
|
||||
if (ty->IsKindOf(RUNTIME_CLASS(PStruct)))
|
||||
{
|
||||
|
|
|
@ -247,6 +247,7 @@ public:
|
|||
// object is destroyed.
|
||||
virtual void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL) const;
|
||||
virtual void SetPointer(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) const;
|
||||
virtual void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) const;
|
||||
|
||||
// Initialize the value, if needed (e.g. strings)
|
||||
virtual void InitializeValue(void *addr, const void *def) const;
|
||||
|
@ -534,7 +535,7 @@ class PClassPointer : public PPointer
|
|||
DECLARE_CLASS(PClassPointer, PPointer);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
PClassPointer(class PClass *restrict);
|
||||
PClassPointer(class PClass *restrict = nullptr);
|
||||
|
||||
class PClass *ClassRestriction;
|
||||
|
||||
|
@ -542,8 +543,6 @@ public:
|
|||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
protected:
|
||||
PClassPointer();
|
||||
};
|
||||
|
||||
// Struct/class fields ------------------------------------------------------
|
||||
|
@ -657,6 +656,14 @@ public:
|
|||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
|
||||
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
|
||||
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
|
||||
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override;
|
||||
void InitializeValue(void *addr, const void *def) const override;
|
||||
void DestroyValue(void *addr) const override;
|
||||
void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) const override;
|
||||
|
||||
protected:
|
||||
PDynArray();
|
||||
};
|
||||
|
@ -801,6 +808,7 @@ public:
|
|||
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;
|
||||
bool bRuntimeClass; // class was defined at run-time, not compile-time
|
||||
bool bExported; // This type has been declared in a script
|
||||
|
@ -818,6 +826,7 @@ public:
|
|||
PField *AddField(FName name, PType *type, DWORD flags=0) override;
|
||||
void InitializeActorInfo();
|
||||
void BuildFlatPointers();
|
||||
void BuildArrayPointers();
|
||||
void DestroySpecials(void *addr) const;
|
||||
const PClass *NativeClass() const;
|
||||
|
||||
|
|
|
@ -542,7 +542,7 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
tag = ATAG_STATE;
|
||||
}
|
||||
else if (value.Type->GetLoadOp() == OP_LO)
|
||||
else if (value.Type->GetLoadOp() != OP_LP)
|
||||
{
|
||||
tag = ATAG_OBJECT;
|
||||
}
|
||||
|
@ -6356,7 +6356,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build)
|
|||
ob.Free(build);
|
||||
ExpEmit meta(build, REGT_POINTER);
|
||||
build->Emit(OP_META, meta.RegNum, ob.RegNum);
|
||||
build->Emit(OP_LO, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
|
||||
build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
|
||||
return meta;
|
||||
|
||||
}
|
||||
|
@ -8874,7 +8874,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build)
|
|||
op.Free(build);
|
||||
}
|
||||
ExpEmit to(build, REGT_POINTER);
|
||||
build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass)));
|
||||
build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass)));
|
||||
return to;
|
||||
}
|
||||
|
||||
|
@ -8946,7 +8946,7 @@ ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build)
|
|||
build->Emit(OP_LKP, to.RegNum, op.RegNum);
|
||||
op = to;
|
||||
}
|
||||
build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
|
||||
build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
|
||||
return to;
|
||||
}
|
||||
|
||||
|
@ -10683,8 +10683,7 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
|
|||
|
||||
case REGT_POINTER:
|
||||
{
|
||||
bool isobject = ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)));
|
||||
build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), isobject ? ATAG_OBJECT : ATAG_GENERIC));
|
||||
build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), ValueType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC));
|
||||
break;
|
||||
}
|
||||
case REGT_STRING:
|
||||
|
@ -10824,7 +10823,7 @@ ExpEmit FxStaticArray::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
TArray<void*> cvalues;
|
||||
for (auto v : values) cvalues.Push(static_cast<FxConstant *>(v)->GetValue().GetPointer());
|
||||
StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() == OP_LO ? ATAG_OBJECT : ATAG_GENERIC);
|
||||
StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1141,19 +1141,8 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat)
|
|||
DEFINE_ACTION_FUNCTION(FStringStruct, Mid)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_INT(ipos);
|
||||
PARAM_INT(ilen);
|
||||
// validate. we don't want to crash if someone passes negative values.
|
||||
// with size_t it's handled naturally I think, as it's unsigned, but not in ZScript.
|
||||
if (ipos < 0) ipos = 0;
|
||||
if (ilen < 0) ilen = 0;
|
||||
// convert to size_t to prevent overflows here
|
||||
size_t slen = self->Len();
|
||||
size_t pos = (size_t)ipos;
|
||||
size_t len = (size_t)ilen;
|
||||
if (pos > slen) pos = slen - 1;
|
||||
if (pos + len > slen)
|
||||
len = slen - pos;
|
||||
PARAM_UINT(pos);
|
||||
PARAM_UINT(len);
|
||||
FString s = self->Mid(pos, len);
|
||||
ACTION_RETURN_STRING(s);
|
||||
}
|
||||
|
@ -1161,7 +1150,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Mid)
|
|||
DEFINE_ACTION_FUNCTION(FStringStruct, Len)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
ACTION_RETURN_INT(self->Len());
|
||||
ACTION_RETURN_INT((int)self->Len());
|
||||
}
|
||||
|
||||
// CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int.
|
||||
|
@ -1169,7 +1158,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharAt)
|
|||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_INT(pos);
|
||||
int slen = self->Len();
|
||||
int slen = (int)self->Len();
|
||||
if (pos < 0 || pos >= slen)
|
||||
ACTION_RETURN_STRING("");
|
||||
ACTION_RETURN_STRING(FString((*self)[pos]));
|
||||
|
@ -1179,7 +1168,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt)
|
|||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_INT(pos);
|
||||
int slen = self->Len();
|
||||
int slen = (int)self->Len();
|
||||
if (pos < 0 || pos >= slen)
|
||||
ACTION_RETURN_INT(0);
|
||||
ACTION_RETURN_INT((*self)[pos]);
|
||||
|
|
|
@ -997,6 +997,7 @@ void NullParam(const char *varname);
|
|||
|
||||
// For required parameters.
|
||||
#define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i;
|
||||
#define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); unsigned x = param[p].i;
|
||||
#define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); bool x = !!param[p].i;
|
||||
#define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FName x = ENamedName(param[p].i);
|
||||
#define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i;
|
||||
|
@ -1040,6 +1041,7 @@ void NullParam(const char *varname);
|
|||
#define PARAM_PROLOGUE int paramnum = -1;
|
||||
|
||||
#define PARAM_INT(x) ++paramnum; PARAM_INT_AT(paramnum,x)
|
||||
#define PARAM_UINT(x) ++paramnum; PARAM_UINT_AT(paramnum,x)
|
||||
#define PARAM_BOOL(x) ++paramnum; PARAM_BOOL_AT(paramnum,x)
|
||||
#define PARAM_NAME(x) ++paramnum; PARAM_NAME_AT(paramnum,x)
|
||||
#define PARAM_SOUND(x) ++paramnum; PARAM_SOUND_AT(paramnum,x)
|
||||
|
|
|
@ -347,6 +347,17 @@ begin:
|
|||
GETADDR(PA,RC,X_WRITE_NIL);
|
||||
*(void **)ptr = reg.a[B];
|
||||
NEXTOP;
|
||||
OP(SO):
|
||||
ASSERTA(a); ASSERTA(B); ASSERTKD(C);
|
||||
GETADDR(PA,KC,X_WRITE_NIL);
|
||||
*(void **)ptr = reg.a[B];
|
||||
GC::WriteBarrier((DObject*)*(void **)ptr);
|
||||
NEXTOP;
|
||||
OP(SO_R):
|
||||
ASSERTA(a); ASSERTA(B); ASSERTD(C);
|
||||
GETADDR(PA,RC,X_WRITE_NIL);
|
||||
GC::WriteBarrier((DObject*)*(void **)ptr);
|
||||
NEXTOP;
|
||||
OP(SV2):
|
||||
ASSERTA(a); ASSERTF(B+1); ASSERTKD(C);
|
||||
GETADDR(PA,KC,X_WRITE_NIL);
|
||||
|
|
|
@ -70,6 +70,8 @@ xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string
|
|||
xx(SS_R, ss, RPRSRI, NOP, 0, 0),
|
||||
xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer
|
||||
xx(SP_R, sp, RPRPRI, NOP, 0, 0),
|
||||
xx(SO, sp, RPRPKI, SO_R, 4, REGT_INT), // store object pointer with write barrier (only needed for non thinkers and non types
|
||||
xx(SO_R, sp, RPRPRI, NOP, 0, 0),
|
||||
xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2
|
||||
xx(SV2_R, sv2, RPRVRI, NOP, 0, 0),
|
||||
xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3
|
||||
|
|
Loading…
Reference in a new issue