Skip to content

Commit 6b1580f

Browse files
committed
[NFC] Refactor swift_updatePureObjCClassMetadata()
Merge the three-stage operation originally designed for field vectors into a single unified loop that acts directly on the ivar offsets instead of using a faux field offset vector.
1 parent d43e49e commit 6b1580f

File tree

1 file changed

+74
-127
lines changed

1 file changed

+74
-127
lines changed

stdlib/public/runtime/Metadata.cpp

Lines changed: 74 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -3974,76 +3974,95 @@ swift::swift_updateClassMetadata2(ClassMetadata *self,
39743974
/*allowDependency*/ true);
39753975
}
39763976

3977-
static void initClassFieldOffsetVector(ObjCClass *self,
3978-
size_t numFields,
3979-
const TypeLayout * const *fieldTypes,
3980-
size_t *fieldOffsets) {
3981-
size_t size, alignMask;
3977+
Class
3978+
swift::swift_updatePureObjCClassMetadata(Class cls,
3979+
ClassLayoutFlags flags,
3980+
size_t numFields,
3981+
const TypeLayout * const *fieldTypes) {
3982+
auto self = (ObjCClass *)cls;
3983+
bool requiresUpdate = SWIFT_RUNTIME_WEAK_CHECK(_objc_realizeClassFromSwift);
39823984

3983-
ClassROData *rodata = getROData(self);
3985+
// Realize the superclass first.
3986+
(void)swift_getInitializedObjCClass((Class)self->Isa);
39843987

3985-
// Start layout from our static notion of where the superclass starts.
3986-
// Objective-C expects us to have generated a correct ivar layout, which it
3987-
// will simply slide if it needs to.
3988-
assert(self->Superclass && "Swift cannot implement a root class");
3989-
size = rodata->InstanceStart;
3990-
alignMask = 0xF; // malloc alignment guarantee
3988+
// The Swift bit has been set so that we use Swift class initialization paths,
3989+
// but from here on in, we want to treat this as a pure ObjC class. Clear it.
3990+
auto rodata = getROData(self);
3991+
self->RODataAndFlags = (uintptr_t)rodata;
39913992

3992-
// Okay, now do layout.
3993-
for (unsigned i = 0; i != numFields; ++i) {
3994-
auto *eltLayout = fieldTypes[i];
3993+
// If we're running on a older Objective-C runtime, just realize
3994+
// the class.
3995+
if (!requiresUpdate) {
3996+
// If we don't have a backward deployment layout, we cannot proceed here.
3997+
if (rodata->InstanceSize == 0) {
3998+
fatalError(0, "class %s does not have a fragile layout; "
3999+
"the deployment target was newer than this OS\n",
4000+
rodata->Name);
4001+
}
39954002

3996-
// Skip empty fields.
3997-
if (fieldOffsets[i] == 0 && eltLayout->size == 0)
3998-
continue;
3999-
auto offset = roundUpToAlignMask(size,
4000-
eltLayout->flags.getAlignmentMask());
4001-
fieldOffsets[i] = offset;
4002-
size = offset + eltLayout->size;
4003-
alignMask = std::max(alignMask, eltLayout->flags.getAlignmentMask());
4003+
// Realize the class. This causes the runtime to slide the field offsets
4004+
// stored in the field offset globals.
4005+
//
4006+
// Note that the field offset vector is *not* updated; however in
4007+
// Objective-C interop mode, we don't actually use the field offset vector
4008+
// of non-generic classes.
4009+
//
4010+
// In particular, class mirrors always use the Objective-C ivar descriptors,
4011+
// which point at field offset globals and not the field offset vector.
4012+
swift_getInitializedObjCClass((Class)self);
4013+
return cls;
40044014
}
40054015

4006-
// Save the size into the Objective-C metadata.
4007-
if (rodata->InstanceSize != size)
4008-
rodata->InstanceSize = size;
4009-
}
4010-
4011-
/// Non-generic classes only. Initialize the Objective-C ivar descriptors and
4012-
/// field offset globals. Does *not* register the class with the Objective-C
4013-
/// runtime; that must be done by the caller.
4014-
///
4015-
/// This function copies the ivar descriptors and updates each ivar global with
4016-
/// the corresponding offset in \p fieldOffsets, before asking the Objective-C
4017-
/// runtime to realize the class. The Objective-C runtime will then slide the
4018-
/// offsets stored in those globals.
4019-
///
4020-
/// Note that \p fieldOffsets remains unchanged in this case.
4021-
static void initObjCClass(ObjCClass *self,
4022-
size_t numFields,
4023-
const TypeLayout * const *fieldTypes,
4024-
size_t *fieldOffsets) {
4025-
ClassROData *rodata = getROData(self);
4026-
4016+
// Update the field offset globals using runtime type information; the layout
4017+
// of resilient types might be different than the statically-emitted layout.
40274018
ClassIvarList *ivars = rodata->IvarList;
40284019
if (!ivars) {
40294020
assert(numFields == 0);
4030-
return;
4021+
4022+
// See remark above about how this slides field offset globals.
4023+
SWIFT_RUNTIME_WEAK_USE(_objc_realizeClassFromSwift(cls, cls));
4024+
4025+
return cls;
40314026
}
40324027

40334028
assert(ivars->Count == numFields);
40344029
assert(ivars->EntrySize == sizeof(ClassIvarEntry));
40354030

40364031
bool copiedIvarList = false;
40374032

4038-
for (unsigned i = 0; i != numFields; ++i) {
4039-
auto *eltLayout = fieldTypes[i];
4033+
// Update the field offset globals using runtime type information; the layout
4034+
// of resilient types might be different than the statically-emitted layout.
4035+
size_t size, alignMask;
40404036

4037+
// Start layout from our static notion of where the superclass starts.
4038+
// Objective-C expects us to have generated a correct ivar layout, which it
4039+
// will simply slide if it needs to.
4040+
assert(self->Superclass && "Swift cannot implement a root class");
4041+
size = rodata->InstanceStart;
4042+
alignMask = 0xF; // malloc alignment guarantee
4043+
4044+
// Okay, now do layout.
4045+
for (unsigned i = 0; i != numFields; ++i) {
40414046
ClassIvarEntry *ivar = &ivars->getIvars()[i];
40424047

4043-
// Fill in the field offset global, if this ivar has one.
4048+
size_t offset = 0;
40444049
if (ivar->Offset) {
4045-
if (*ivar->Offset != fieldOffsets[i])
4046-
*ivar->Offset = fieldOffsets[i];
4050+
offset = *ivar->Offset;
4051+
}
4052+
4053+
auto *eltLayout = fieldTypes[i];
4054+
4055+
// Skip empty fields.
4056+
if (offset != 0 || eltLayout->size != 0) {
4057+
offset = roundUpToAlignMask(size, eltLayout->flags.getAlignmentMask());
4058+
size = offset + eltLayout->size;
4059+
alignMask = std::max(alignMask, eltLayout->flags.getAlignmentMask());
4060+
4061+
// Fill in the field offset global, if this ivar has one.
4062+
if (ivar->Offset) {
4063+
if (*ivar->Offset != offset)
4064+
*ivar->Offset = offset;
4065+
}
40474066
}
40484067

40494068
// If the ivar's size doesn't match the field layout we
@@ -4068,85 +4087,13 @@ static void initObjCClass(ObjCClass *self,
40684087
getLog2AlignmentFromMask(eltLayout->flags.getAlignmentMask());
40694088
}
40704089
}
4071-
}
4072-
4073-
static void populateInitialFieldOffsets(ObjCClass *self,
4074-
size_t numFields,
4075-
size_t *fieldOffsets) {
4076-
ClassROData *rodata = getROData(self);
40774090

4078-
ClassIvarList *ivars = rodata->IvarList;
4079-
if (!ivars) {
4080-
assert(numFields == 0);
4081-
return;
4082-
}
4083-
4084-
assert(ivars->Count == numFields);
4085-
assert(ivars->EntrySize == sizeof(ClassIvarEntry));
4086-
4087-
for (unsigned i = 0; i != numFields; ++i) {
4088-
ClassIvarEntry *ivar = &ivars->getIvars()[i];
4089-
4090-
if (ivar->Offset) {
4091-
fieldOffsets[i] = *ivar->Offset;
4092-
} else {
4093-
fieldOffsets[i] = 0;
4094-
}
4095-
}
4096-
}
4097-
4098-
Class
4099-
swift::swift_updatePureObjCClassMetadata(Class cls,
4100-
ClassLayoutFlags flags,
4101-
size_t numFields,
4102-
const TypeLayout * const *fieldTypes) {
4103-
auto self = (ObjCClass *)cls;
4104-
bool requiresUpdate = SWIFT_RUNTIME_WEAK_CHECK(_objc_realizeClassFromSwift);
4105-
4106-
// Realize the superclass first.
4107-
(void)swift_getInitializedObjCClass((Class)self->Isa);
4108-
4109-
// The Swift bit has been set so that we use Swift class initialization paths,
4110-
// but from here on in, we want to treat this as a pure ObjC class. Clear it.
4111-
auto ROData = getROData(self);
4112-
self->RODataAndFlags = (uintptr_t)ROData;
4113-
4114-
// If we're running on a older Objective-C runtime, just realize
4115-
// the class.
4116-
if (!requiresUpdate) {
4117-
// If we don't have a backward deployment layout, we cannot proceed here.
4118-
if (ROData->InstanceSize == 0) {
4119-
fatalError(0, "class %s does not have a fragile layout; "
4120-
"the deployment target was newer than this OS\n",
4121-
ROData->Name);
4122-
}
4123-
4124-
// Realize the class. This causes the runtime to slide the field offsets
4125-
// stored in the field offset globals.
4126-
//
4127-
// Note that the field offset vector is *not* updated; however in
4128-
// Objective-C interop mode, we don't actually use the field offset vector
4129-
// of non-generic classes.
4130-
//
4131-
// In particular, class mirrors always use the Objective-C ivar descriptors,
4132-
// which point at field offset globals and not the field offset vector.
4133-
swift_getInitializedObjCClass((Class)self);
4134-
} else {
4135-
// Fake up a field offsets vector based on the ivars.
4136-
// FIXME: Temporary; we should just combine the other two functions' logic.
4137-
size_t *fieldOffsets = (size_t *)alloca(numFields * sizeof(size_t));
4138-
populateInitialFieldOffsets(self, numFields, fieldOffsets);
4139-
4140-
// Update the field offset vector using runtime type information; the layout
4141-
// of resilient types might be different than the statically-emitted layout.
4142-
initClassFieldOffsetVector(self, numFields, fieldTypes, fieldOffsets);
4143-
4144-
// Copy field offset vector entries to the field offset globals.
4145-
initObjCClass(self, numFields, fieldTypes, fieldOffsets);
4091+
// Save the size into the Objective-C metadata.
4092+
if (rodata->InstanceSize != size)
4093+
rodata->InstanceSize = size;
41464094

4147-
// See remark above about how this slides field offset globals.
4148-
SWIFT_RUNTIME_WEAK_USE(_objc_realizeClassFromSwift(cls, cls));
4149-
}
4095+
// See remark above about how this slides field offset globals.
4096+
SWIFT_RUNTIME_WEAK_USE(_objc_realizeClassFromSwift(cls, cls));
41504097

41514098
return cls;
41524099
}

0 commit comments

Comments
 (0)