Extracted AggregateDeclaration.finalizeSize into a visitor in dsymbolsem (#21139)

This commit is contained in:
Matthew Qiu 2025-04-04 21:08:06 -04:00 committed by GitHub
parent b5b84fb102
commit d48bdb8f78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 242 additions and 240 deletions

View file

@ -187,8 +187,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return fields.length - isNested() - (vthis2 !is null);
}
abstract void finalizeSize();
override final uinteger_t size(Loc loc)
{
//printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);

View file

@ -120,7 +120,6 @@ public:
Sizeok sizeok; // set when structsize contains valid data
virtual Scope *newScope(Scope *sc);
virtual void finalizeSize() = 0;
uinteger_t size(Loc loc) override final;
Type *getType() override final;
bool isDeprecated() const override final; // is aggregate deprecated?
@ -172,7 +171,6 @@ public:
static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
StructDeclaration *syntaxCopy(Dsymbol *s) override;
const char *kind() const override;
void finalizeSize() override final;
bool isPOD();
bool zeroInit() const; // !=0 if initialize with 0 fill
bool zeroInit(bool v);
@ -287,7 +285,6 @@ public:
virtual bool isBaseOf(ClassDeclaration *cd, int *poffset);
bool isBaseInfoComplete();
void finalizeSize() override;
bool hasMonitor();
bool isCOMclass() const;
virtual bool isCOMinterface() const;

View file

@ -23,7 +23,6 @@ import dmd.gluelayer;
import dmd.declaration;
import dmd.dscope;
import dmd.dsymbol;
import dmd.dsymbolsem : setFieldOffset;
import dmd.errors;
import dmd.func;
import dmd.id;
@ -495,116 +494,6 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
return null;
}
final override void finalizeSize()
{
assert(sizeok != Sizeok.done);
// Set the offsets of the fields and determine the size of the class
if (baseClass)
{
assert(baseClass.sizeok == Sizeok.done);
alignsize = baseClass.alignsize;
if (classKind == ClassKind.cpp)
structsize = target.cpp.derivedClassOffset(baseClass);
else
structsize = baseClass.structsize;
}
else if (classKind == ClassKind.objc)
structsize = 0; // no hidden member for an Objective-C class
else if (isInterfaceDeclaration())
{
if (interfaces.length == 0)
{
alignsize = target.ptrsize;
structsize = target.ptrsize; // allow room for __vptr
}
}
else
{
alignsize = target.ptrsize;
structsize = target.ptrsize; // allow room for __vptr
if (hasMonitor())
structsize += target.ptrsize; // allow room for __monitor
}
//printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
size_t bi = 0; // index into vtblInterfaces[]
/****
* Runs through the inheritance graph to set the BaseClass.offset fields.
* Recursive in order to account for the size of the interface classes, if they are
* more than just interfaces.
* Params:
* cd = interface to look at
* baseOffset = offset of where cd will be placed
* Returns:
* subset of instantiated size used by cd for interfaces
*/
uint membersPlace(ClassDeclaration cd, uint baseOffset)
{
//printf(" membersPlace(%s, %d)\n", cd.toChars(), baseOffset);
uint offset = baseOffset;
foreach (BaseClass* b; cd.interfaces)
{
if (b.sym.sizeok != Sizeok.done)
b.sym.finalizeSize();
assert(b.sym.sizeok == Sizeok.done);
if (!b.sym.alignsize)
b.sym.alignsize = target.ptrsize;
offset = alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, offset);
assert(bi < vtblInterfaces.length);
BaseClass* bv = (*vtblInterfaces)[bi];
if (b.sym.interfaces.length == 0)
{
//printf("\tvtblInterfaces[%d] b=%p b.sym = %s, offset = %d\n", bi, bv, bv.sym.toChars(), offset);
bv.offset = offset;
++bi;
// All the base interfaces down the left side share the same offset
for (BaseClass* b2 = bv; b2.baseInterfaces.length; )
{
b2 = &b2.baseInterfaces[0];
b2.offset = offset;
//printf("\tvtblInterfaces[%d] b=%p sym = %s, offset = %d\n", bi, b2, b2.sym.toChars(), b2.offset);
}
}
membersPlace(b.sym, offset);
//printf(" %s size = %d\n", b.sym.toChars(), b.sym.structsize);
offset += b.sym.structsize;
if (alignsize < b.sym.alignsize)
alignsize = b.sym.alignsize;
}
return offset - baseOffset;
}
structsize += membersPlace(this, structsize);
if (isInterfaceDeclaration())
{
sizeok = Sizeok.done;
return;
}
// FIXME: Currently setFieldOffset functions need to increase fields
// to calculate each variable offsets. It can be improved later.
fields.setDim(0);
FieldState fieldState;
fieldState.offset = structsize;
foreach (s; *members)
{
s.setFieldOffset(this, &fieldState, false);
}
sizeok = Sizeok.done;
// Calculate fields[i].overlapped
checkOverlappedFields();
}
/**************
* Returns: true if there's a __monitor field
*/

View file

@ -151,127 +151,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration
return "struct";
}
override final void finalizeSize()
{
//printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
assert(sizeok != Sizeok.done);
if (sizeok == Sizeok.inProcess)
{
return;
}
sizeok = Sizeok.inProcess;
//printf("+StructDeclaration::finalizeSize() %s, fields.length = %d, sizeok = %d\n", toChars(), fields.length, sizeok);
fields.setDim(0); // workaround
// Set the offsets of the fields and determine the size of the struct
FieldState fieldState;
bool isunion = isUnionDeclaration() !is null;
for (size_t i = 0; i < members.length; i++)
{
Dsymbol s = (*members)[i];
s.setFieldOffset(this, &fieldState, isunion);
if (type.ty == Terror)
{
errorSupplemental(s.loc, "error on member `%s`", s.toPrettyChars);
errors = true;
return;
}
}
if (structsize == 0)
{
hasNoFields = true;
alignsize = 1;
// A fine mess of what size a zero sized struct should be
final switch (classKind)
{
case ClassKind.d:
case ClassKind.cpp:
structsize = 1;
break;
case ClassKind.c:
case ClassKind.objc:
if (target.c.bitFieldStyle == TargetC.BitFieldStyle.MS)
{
/* Undocumented MS behavior for:
* struct S { int :0; };
*/
structsize = 4;
}
else
structsize = 0;
break;
}
}
// Round struct size up to next alignsize boundary.
// This will ensure that arrays of structs will get their internals
// aligned properly.
if (alignment.isDefault() || alignment.isPack())
structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
else
structsize = (structsize + alignment.get() - 1) & ~(alignment.get() - 1);
sizeok = Sizeok.done;
//printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), cast(int)fields.length, cast(int)structsize);
if (errors)
return;
// Calculate fields[i].overlapped
if (checkOverlappedFields())
{
errors = true;
return;
}
// Determine if struct is all zeros or not
zeroInit = true;
auto lastOffset = -1;
foreach (vd; fields)
{
// First skip zero sized fields
if (vd.type.size(vd.loc) == 0)
continue;
// only consider first sized member of an (anonymous) union
if (vd.overlapped && vd.offset == lastOffset)
continue;
lastOffset = vd.offset;
if (vd._init)
{
if (vd._init.isVoidInitializer())
/* Treat as 0 for the purposes of putting the initializer
* in the BSS segment, or doing a mass set to 0
*/
continue;
// Examine init to see if it is all 0s.
auto exp = vd.getConstInitializer();
if (!exp || !_isZeroInit(exp))
{
zeroInit = false;
break;
}
}
else if (!vd.type.isZeroInit(loc))
{
zeroInit = false;
break;
}
}
argTypes = target.toArgTypes(type);
}
/// Compute cached type properties for `TypeStruct`
extern(D) final void determineTypeProperties()
{

View file

@ -8308,3 +8308,245 @@ extern(C++) bool isAbstract(ClassDeclaration cd)
return no();
}
void finalizeSize(AggregateDeclaration ad)
{
scope v = new FinalizeSizeVisitor();
ad.accept(v);
}
private extern(C++) class FinalizeSizeVisitor : Visitor
{
alias visit = Visitor.visit;
override void visit(ClassDeclaration outerCd)
{
assert(outerCd.sizeok != Sizeok.done);
// Set the offsets of the fields and determine the size of the class
if (outerCd.baseClass)
{
assert(outerCd.baseClass.sizeok == Sizeok.done);
outerCd.alignsize = outerCd.baseClass.alignsize;
if (outerCd.classKind == ClassKind.cpp)
outerCd.structsize = target.cpp.derivedClassOffset(outerCd.baseClass);
else
outerCd.structsize = outerCd.baseClass.structsize;
}
else if (outerCd.classKind == ClassKind.objc)
outerCd.structsize = 0; // no hidden member for an Objective-C class
else if (outerCd.isInterfaceDeclaration())
{
if (outerCd.interfaces.length == 0)
{
outerCd.alignsize = target.ptrsize;
outerCd.structsize = target.ptrsize; // allow room for __vptr
}
}
else
{
outerCd.alignsize = target.ptrsize;
outerCd.structsize = target.ptrsize; // allow room for __vptr
if (outerCd.hasMonitor())
outerCd.structsize += target.ptrsize; // allow room for __monitor
}
//printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
size_t bi = 0; // index into vtblInterfaces[]
/****
* Runs through the inheritance graph to set the BaseClass.offset fields.
* Recursive in order to account for the size of the interface classes, if they are
* more than just interfaces.
* Params:
* cd = interface to look at
* baseOffset = offset of where cd will be placed
* Returns:
* subset of instantiated size used by cd for interfaces
*/
uint membersPlace(ClassDeclaration cd, uint baseOffset)
{
//printf(" membersPlace(%s, %d)\n", cd.toChars(), baseOffset);
uint offset = baseOffset;
foreach (BaseClass* b; cd.interfaces)
{
if (b.sym.sizeok != Sizeok.done)
b.sym.finalizeSize();
assert(b.sym.sizeok == Sizeok.done);
if (!b.sym.alignsize)
b.sym.alignsize = target.ptrsize;
offset = alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, offset);
assert(bi < outerCd.vtblInterfaces.length);
BaseClass* bv = (*(outerCd.vtblInterfaces))[bi];
if (b.sym.interfaces.length == 0)
{
//printf("\tvtblInterfaces[%d] b=%p b.sym = %s, offset = %d\n", bi, bv, bv.sym.toChars(), offset);
bv.offset = offset;
++bi;
// All the base interfaces down the left side share the same offset
for (BaseClass* b2 = bv; b2.baseInterfaces.length; )
{
b2 = &b2.baseInterfaces[0];
b2.offset = offset;
//printf("\tvtblInterfaces[%d] b=%p sym = %s, offset = %d\n", bi, b2, b2.sym.toChars(), b2.offset);
}
}
membersPlace(b.sym, offset);
//printf(" %s size = %d\n", b.sym.toChars(), b.sym.structsize);
offset += b.sym.structsize;
if (outerCd.alignsize < b.sym.alignsize)
outerCd.alignsize = b.sym.alignsize;
}
return offset - baseOffset;
}
outerCd.structsize += membersPlace(outerCd, outerCd.structsize);
if (outerCd.isInterfaceDeclaration())
{
outerCd.sizeok = Sizeok.done;
return;
}
// FIXME: Currently setFieldOffset functions need to increase fields
// to calculate each variable offsets. It can be improved later.
outerCd.fields.setDim(0);
FieldState fieldState;
fieldState.offset = outerCd.structsize;
foreach (s; *(outerCd.members))
{
s.setFieldOffset(outerCd, &fieldState, false);
}
outerCd.sizeok = Sizeok.done;
// Calculate fields[i].overlapped
outerCd.checkOverlappedFields();
}
override void visit(StructDeclaration sd)
{
//printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
assert(sd.sizeok != Sizeok.done);
if (sd.sizeok == Sizeok.inProcess)
{
return;
}
sd.sizeok = Sizeok.inProcess;
//printf("+StructDeclaration::finalizeSize() %s, fields.length = %d, sizeok = %d\n", toChars(), fields.length, sizeok);
sd.fields.setDim(0); // workaround
// Set the offsets of the fields and determine the size of the struct
FieldState fieldState;
bool isunion = sd.isUnionDeclaration() !is null;
for (size_t i = 0; i < sd.members.length; i++)
{
Dsymbol s = (*sd.members)[i];
s.setFieldOffset(sd, &fieldState, isunion);
if (sd.type.ty == Terror)
{
errorSupplemental(s.loc, "error on member `%s`", s.toPrettyChars);
sd.errors = true;
return;
}
}
if (sd.structsize == 0)
{
sd.hasNoFields = true;
sd.alignsize = 1;
// A fine mess of what size a zero sized struct should be
final switch (sd.classKind)
{
case ClassKind.d:
case ClassKind.cpp:
sd.structsize = 1;
break;
case ClassKind.c:
case ClassKind.objc:
if (target.c.bitFieldStyle == TargetC.BitFieldStyle.MS)
{
/* Undocumented MS behavior for:
* struct S { int :0; };
*/
sd.structsize = 4;
}
else
sd.structsize = 0;
break;
}
}
// Round struct size up to next alignsize boundary.
// This will ensure that arrays of structs will get their internals
// aligned properly.
if (sd.alignment.isDefault() || sd.alignment.isPack())
sd.structsize = (sd.structsize + sd.alignsize - 1) & ~(sd.alignsize - 1);
else
sd.structsize = (sd.structsize + sd.alignment.get() - 1) & ~(sd.alignment.get() - 1);
sd.sizeok = Sizeok.done;
//printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), cast(int)fields.length, cast(int)structsize);
if (sd.errors)
return;
// Calculate fields[i].overlapped
if (sd.checkOverlappedFields())
{
sd.errors = true;
return;
}
// Determine if struct is all zeros or not
sd.zeroInit = true;
auto lastOffset = -1;
foreach (vd; sd.fields)
{
// First skip zero sized fields
if (vd.type.size(vd.loc) == 0)
continue;
// only consider first sized member of an (anonymous) union
if (vd.overlapped && vd.offset == lastOffset)
continue;
lastOffset = vd.offset;
if (vd._init)
{
if (vd._init.isVoidInitializer())
/* Treat as 0 for the purposes of putting the initializer
* in the BSS segment, or doing a mass set to 0
*/
continue;
// Examine init to see if it is all 0s.
auto exp = vd.getConstInitializer();
if (!exp || !_isZeroInit(exp))
{
sd.zeroInit = false;
break;
}
}
else if (!vd.type.isZeroInit(sd.loc))
{
sd.zeroInit = false;
break;
}
}
sd.argTypes = target.toArgTypes(sd.type);
}
}

View file

@ -6354,7 +6354,6 @@ public:
bool disableNew;
Sizeok sizeok;
virtual Scope* newScope(Scope* sc);
virtual void finalizeSize() = 0;
uinteger_t size(Loc loc) final override;
Type* getType() final override;
bool isDeprecated() const final override;
@ -6701,7 +6700,6 @@ public:
virtual bool isBaseOf(ClassDeclaration* cd, int32_t* poffset);
bool isBaseInfoComplete() const;
void finalizeSize() final override;
bool hasMonitor();
bool isCOMclass() const;
virtual bool isCOMinterface() const;
@ -7435,7 +7433,6 @@ public:
static StructDeclaration* create(Loc loc, Identifier* id, bool inObject);
StructDeclaration* syntaxCopy(Dsymbol* s) override;
const char* kind() const override;
void finalizeSize() final override;
bool isPOD();
bool hasCopyConstruction();
void accept(Visitor* v) override;