Skip to content

Commit 14f0ce6

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 7e30002 commit 14f0ce6

File tree

1 file changed

+67
-124
lines changed

1 file changed

+67
-124
lines changed

stdlib/public/runtime/Metadata.cpp

Lines changed: 67 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "MetadataCache.h"
2626
#include "BytecodeLayouts.h"
2727
#include "swift/ABI/TypeIdentity.h"
28+
#include "swift/Basic/Defer.h"
2829
#include "swift/Basic/MathUtils.h"
2930
#include "swift/Basic/Lazy.h"
3031
#include "swift/Basic/Range.h"
@@ -3974,76 +3975,90 @@ swift::swift_updateClassMetadata2(ClassMetadata *self,
39743975
/*allowDependency*/ true);
39753976
}
39763977

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

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

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
3989+
auto rodata = getROData(self);
39913990

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

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());
4001+
// Realize the class. This causes the runtime to slide the field offsets
4002+
// stored in the field offset globals.
4003+
//
4004+
// Note that the field offset vector is *not* updated; however in
4005+
// Objective-C interop mode, we don't actually use the field offset vector
4006+
// of non-generic classes.
4007+
//
4008+
// In particular, class mirrors always use the Objective-C ivar descriptors,
4009+
// which point at field offset globals and not the field offset vector.
4010+
swift_getInitializedObjCClass((Class)self);
4011+
return cls;
40044012
}
40054013

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);
4014+
SWIFT_DEFER {
4015+
// Realize the class. This causes the runtime to slide the field offsets
4016+
// stored in the field offset globals.
4017+
SWIFT_RUNTIME_WEAK_USE(_objc_realizeClassFromSwift(cls, cls));
4018+
};
40264019

4020+
// Update the field offset globals using runtime type information; the layout
4021+
// of resilient types might be different than the statically-emitted layout.
40274022
ClassIvarList *ivars = rodata->IvarList;
40284023
if (!ivars) {
40294024
assert(numFields == 0);
4030-
return;
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+
// Start layout from our static notion of where the superclass starts.
4034+
// Objective-C expects us to have generated a correct ivar layout, which it
4035+
// will simply slide if it needs to.
4036+
assert(self->Superclass && "Swift cannot implement a root class");
4037+
size_t size = rodata->InstanceStart;
4038+
size_t alignMask = 0xF; // malloc alignment guarantee
40404039

4040+
// Okay, now do layout.
4041+
for (unsigned i = 0; i != numFields; ++i) {
40414042
ClassIvarEntry *ivar = &ivars->getIvars()[i];
40424043

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

40494064
// If the ivar's size doesn't match the field layout we
@@ -4068,82 +4083,10 @@ static void initObjCClass(ObjCClass *self,
40684083
getLog2AlignmentFromMask(eltLayout->flags.getAlignmentMask());
40694084
}
40704085
}
4071-
}
4072-
4073-
static void populateInitialFieldOffsets(ObjCClass *self,
4074-
size_t numFields,
4075-
size_t *fieldOffsets) {
4076-
ClassROData *rodata = getROData(self);
4077-
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-
auto ROData = getROData(self);
4110-
4111-
// If we're running on a older Objective-C runtime, just realize
4112-
// the class.
4113-
if (!requiresUpdate) {
4114-
// If we don't have a backward deployment layout, we cannot proceed here.
4115-
if (ROData->InstanceSize == 0) {
4116-
fatalError(0, "class %s does not have a fragile layout; "
4117-
"the deployment target was newer than this OS\n",
4118-
ROData->Name);
4119-
}
4120-
4121-
// Realize the class. This causes the runtime to slide the field offsets
4122-
// stored in the field offset globals.
4123-
//
4124-
// Note that the field offset vector is *not* updated; however in
4125-
// Objective-C interop mode, we don't actually use the field offset vector
4126-
// of non-generic classes.
4127-
//
4128-
// In particular, class mirrors always use the Objective-C ivar descriptors,
4129-
// which point at field offset globals and not the field offset vector.
4130-
swift_getInitializedObjCClass((Class)self);
4131-
} else {
4132-
// Fake up a field offsets vector based on the ivars.
4133-
// FIXME: Temporary; we should just combine the other two functions' logic.
4134-
size_t *fieldOffsets = (size_t *)alloca(numFields * sizeof(size_t));
4135-
populateInitialFieldOffsets(self, numFields, fieldOffsets);
4136-
4137-
// Update the field offset vector using runtime type information; the layout
4138-
// of resilient types might be different than the statically-emitted layout.
4139-
initClassFieldOffsetVector(self, numFields, fieldTypes, fieldOffsets);
41404086

4141-
// Copy field offset vector entries to the field offset globals.
4142-
initObjCClass(self, numFields, fieldTypes, fieldOffsets);
4143-
4144-
// See remark above about how this slides field offset globals.
4145-
SWIFT_RUNTIME_WEAK_USE(_objc_realizeClassFromSwift(cls, cls));
4146-
}
4087+
// Save the size into the Objective-C metadata.
4088+
if (rodata->InstanceSize != size)
4089+
rodata->InstanceSize = size;
41474090

41484091
return cls;
41494092
}

0 commit comments

Comments
 (0)