Skip to content

Commit ad76246

Browse files
committed
[5.10][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 (cherry picked from commit 641870a)
1 parent 354b677 commit ad76246

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
@@ -3439,38 +3439,45 @@ static void initObjCClass(ClassMetadata *self,
34393439
size_t *fieldOffsets) {
34403440
ClassROData *rodata = getROData(self);
34413441

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

3455-
for (unsigned i = 0; i != numFields; ++i) {
3456-
auto *eltLayout = fieldTypes[i];
3448+
assert(ivars->Count == numFields);
3449+
assert(ivars->EntrySize == sizeof(ClassIvarEntry));
34573450

3458-
ClassIvarEntry &ivar = ivars->getIvars()[i];
3451+
bool copiedIvarList = false;
34593452

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-
}
3453+
for (unsigned i = 0; i != numFields; ++i) {
3454+
auto *eltLayout = fieldTypes[i];
34653455

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

0 commit comments

Comments
 (0)