Skip to content

Commit 641870a

Browse files
committed
[Runtime] Lazily copy ivar list in initObjCClass.
There's often nothing that needs to be fixed up in the ivar list. In that case, we can avoid copying it. This saves time and memory, and allows the class rodata to be in immutable memory. rdar://116189946
1 parent 8cfcc24 commit 641870a

File tree

1 file changed

+34
-27
lines changed

1 file changed

+34
-27
lines changed

stdlib/public/runtime/Metadata.cpp

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3441,38 +3441,45 @@ static void initObjCClass(ClassMetadata *self,
34413441
size_t *fieldOffsets) {
34423442
ClassROData *rodata = getROData(self);
34433443

3444-
// Always clone the ivar descriptors.
3445-
if (numFields) {
3446-
const ClassIvarList *dependentIvars = rodata->IvarList;
3447-
assert(dependentIvars->Count == numFields);
3448-
assert(dependentIvars->EntrySize == sizeof(ClassIvarEntry));
3449-
3450-
auto ivarListSize = sizeof(ClassIvarList) +
3451-
numFields * sizeof(ClassIvarEntry);
3452-
auto ivars = (ClassIvarList*) getResilientMetadataAllocator()
3453-
.Allocate(ivarListSize, alignof(ClassIvarList));
3454-
memcpy(ivars, dependentIvars, ivarListSize);
3455-
rodata->IvarList = ivars;
3444+
ClassIvarList *ivars = rodata->IvarList;
3445+
if (!ivars) {
3446+
assert(numFields == 0);
3447+
return;
3448+
}
34563449

3457-
for (unsigned i = 0; i != numFields; ++i) {
3458-
auto *eltLayout = fieldTypes[i];
3450+
assert(ivars->Count == numFields);
3451+
assert(ivars->EntrySize == sizeof(ClassIvarEntry));
34593452

3460-
ClassIvarEntry &ivar = ivars->getIvars()[i];
3453+
bool copiedIvarList = false;
34613454

3462-
// Fill in the field offset global, if this ivar has one.
3463-
if (ivar.Offset) {
3464-
if (*ivar.Offset != fieldOffsets[i])
3465-
*ivar.Offset = fieldOffsets[i];
3466-
}
3455+
for (unsigned i = 0; i != numFields; ++i) {
3456+
auto *eltLayout = fieldTypes[i];
34673457

3468-
// If the ivar's size doesn't match the field layout we
3469-
// computed, overwrite it and give it better type information.
3470-
if (ivar.Size != eltLayout->size) {
3471-
ivar.Size = eltLayout->size;
3472-
ivar.Type = nullptr;
3473-
ivar.Log2Alignment =
3474-
getLog2AlignmentFromMask(eltLayout->flags.getAlignmentMask());
3458+
ClassIvarEntry &ivar = ivars->getIvars()[i];
3459+
3460+
// Fill in the field offset global, if this ivar has one.
3461+
if (ivar.Offset) {
3462+
if (*ivar.Offset != fieldOffsets[i])
3463+
*ivar.Offset = fieldOffsets[i];
3464+
}
3465+
3466+
// If the ivar's size doesn't match the field layout we
3467+
// computed, overwrite it and give it better type information.
3468+
if (ivar.Size != eltLayout->size) {
3469+
// If we're going to modify the ivar list, we need to copy it first.
3470+
if (!copiedIvarList) {
3471+
auto ivarListSize = sizeof(ClassIvarList) +
3472+
numFields * sizeof(ClassIvarEntry);
3473+
ivars = (ClassIvarList*) getResilientMetadataAllocator()
3474+
.Allocate(ivarListSize, alignof(ClassIvarList));
3475+
memcpy(ivars, rodata->IvarList, ivarListSize);
3476+
rodata->IvarList = ivars;
3477+
copiedIvarList = true;
34753478
}
3479+
ivar.Size = eltLayout->size;
3480+
ivar.Type = nullptr;
3481+
ivar.Log2Alignment =
3482+
getLog2AlignmentFromMask(eltLayout->flags.getAlignmentMask());
34763483
}
34773484
}
34783485
}

0 commit comments

Comments
 (0)