Skip to content

Commit 8edf870

Browse files
authored
Merge pull request #68834 from mikeash/lazy-copy-ivar-list
[Runtime] Lazily copy ivar list in initObjCClass.
2 parents 1c4c8e8 + 641870a commit 8edf870

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)