Eliminate objcImpl field offset vectors

We really don’t need ‘em; we can just adjust the direct field offsets.

The runtime entry point currently uses a weird little hack that we will refactor away shortly.
This commit is contained in:
Becca Royal-Gordon
2024-04-30 12:00:28 -07:00
parent 427386feea
commit d1f14e5814
7 changed files with 68 additions and 26 deletions

View File

@@ -788,8 +788,7 @@ Class
swift_updatePureObjCClassMetadata(Class self,
ClassLayoutFlags flags,
size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets);
const TypeLayout * const *fieldTypes);
#endif
/// Given class metadata, a class descriptor and a method descriptor, look up

View File

@@ -1437,17 +1437,15 @@ FUNCTION(UpdateClassMetadata2,
EFFECT(MetaData),
UNKNOWN_MEMEFFECTS)
// objc_class *swift_updatePureObjCClassMetadata(objc_class *self,
// objc_class *swift_updatePureObjCClassMetadata(
// objc_class *self,
// ClassLayoutFlags flags,
// size_t numFields,
// TypeLayout * const *fieldTypes,
// size_t *fieldOffsets);
// TypeLayout * const *fieldTypes);
FUNCTION(UpdatePureObjCClassMetadata,
swift_updatePureObjCClassMetadata, SwiftCC, AlwaysAvailable,
RETURNS(ObjCClassPtrTy),
ARGS(ObjCClassPtrTy, SizeTy, SizeTy,
Int8PtrPtrTy->getPointerTo(),
SizeTy->getPointerTo()),
ARGS(ObjCClassPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo()),
ATTRS(NoUnwind),
EFFECT(MetaData),
UNKNOWN_MEMEFFECTS)

View File

@@ -104,7 +104,6 @@ public:
asImpl().addSuperclass();
asImpl().addClassCacheData();
asImpl().addClassDataPointer();
addClassMembers(Target, Target);
return;
}
@@ -221,11 +220,9 @@ private:
rootClass))
return;
if (!isPureObjC()) {
// Add vtable entries.
asImpl().addVTableEntries(theClass);
}
}
/// Add fields associated with the given class and its bases.
void addEmbeddedClassMembers(ClassDecl *theClass) {

View File

@@ -2953,9 +2953,15 @@ emitInitializeFieldOffsetVector(SILType T, llvm::Value *metadata,
bool isVWTMutable,
MetadataDependencyCollector *collector) {
auto *target = T.getNominalOrBoundGenericNominal();
llvm::Value *fieldVector
= emitAddressOfFieldOffsetVector(*this, metadata, target)
llvm::Value *fieldVector = nullptr;
// @objc @implementation classes don't actually have a field vector; for them,
// we're just trying to update the direct field offsets.
if (!isa<ClassDecl>(target)
|| !cast<ClassDecl>(target)->getObjCImplementationDecl()) {
fieldVector = emitAddressOfFieldOffsetVector(*this, metadata, target)
.getAddress();
}
// Collect the stored properties of the type.
unsigned numFields = getNumFields(target);
@@ -3019,7 +3025,7 @@ emitInitializeFieldOffsetVector(SILType T, llvm::Value *metadata,
case ClassMetadataStrategy::FixedOrUpdate:
assert(IGM.Context.LangOpts.EnableObjCInterop);
if (!classDecl->getObjCImplementationDecl()) {
if (fieldVector) {
// Call swift_updateClassMetadata(). Note that the static metadata
// already references the superclass in this case, but we still want
// to ensure the superclass metadata is initialized first.
@@ -3028,10 +3034,13 @@ emitInitializeFieldOffsetVector(SILType T, llvm::Value *metadata,
{metadata, IGM.getSize(Size(uintptr_t(flags))), numFieldsV,
fields.getAddress(), fieldVector});
} else {
// If we don't have a field vector, we must be updating an
// @objc @implementation class layout. Call
// swift_updatePureObjCClassMetadata() instead.
Builder.CreateCall(
IGM.getUpdatePureObjCClassMetadataFunctionPointer(),
{metadata, IGM.getSize(Size(uintptr_t(flags))), numFieldsV,
fields.getAddress(), fieldVector});
fields.getAddress()});
}
break;
@@ -4438,12 +4447,14 @@ namespace {
: super(IGM, theClass, builder, fieldLayout, vtable) {}
void addFieldOffset(VarDecl *var) {
assert(!isPureObjC());
addFixedFieldOffset(IGM, B, var, [](DeclContext *dc) {
return dc->getDeclaredTypeInContext();
});
}
void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
assert(!isPureObjC());
llvm_unreachable("Fixed class metadata cannot have missing members");
}
@@ -4469,12 +4480,14 @@ namespace {
: super(IGM, theClass, builder, fieldLayout) {}
void addFieldOffset(VarDecl *var) {
assert(!isPureObjC());
// Field offsets are either copied from the superclass or calculated
// at runtime.
B.addInt(IGM.SizeTy, 0);
}
void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
assert(!isPureObjC());
for (unsigned i = 0,
e = placeholder->getNumberOfFieldOffsetVectorEntries();
i < e; ++i) {
@@ -4970,11 +4983,13 @@ namespace {
}
void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
assert(!isPureObjC());
llvm_unreachable(
"Prespecialized generic class metadata cannot have missing members");
}
void addFieldOffset(VarDecl *var) {
assert(!isPureObjC());
addFixedFieldOffset(IGM, B, var, [&](DeclContext *dc) {
return dc->mapTypeIntoContext(type);
});

View File

@@ -280,6 +280,10 @@ llvm::Value *irgen::emitArgumentPackShapeRef(IRGenFunction &IGF,
Address irgen::emitAddressOfFieldOffsetVector(IRGenFunction &IGF,
llvm::Value *metadata,
NominalTypeDecl *decl) {
assert(!isa<ClassDecl>(decl)
|| !cast<ClassDecl>(decl)->getObjCImplementationDecl()
&& "objcImpl classes don't have a field offset vector");
auto &layout = IGF.IGM.getMetadataLayout(decl);
auto offset = [&]() {
if (isa<ClassDecl>(decl)) {

View File

@@ -4070,12 +4070,36 @@ static void initObjCClass(ObjCClass *self,
}
}
static void populateInitialFieldOffsets(ObjCClass *self,
size_t numFields,
size_t *fieldOffsets) {
ClassROData *rodata = getROData(self);
ClassIvarList *ivars = rodata->IvarList;
if (!ivars) {
assert(numFields == 0);
return;
}
assert(ivars->Count == numFields);
assert(ivars->EntrySize == sizeof(ClassIvarEntry));
for (unsigned i = 0; i != numFields; ++i) {
ClassIvarEntry *ivar = &ivars->getIvars()[i];
if (ivar->Offset) {
fieldOffsets[i] = *ivar->Offset;
} else {
fieldOffsets[i] = 0;
}
}
}
Class
swift::swift_updatePureObjCClassMetadata(Class cls,
ClassLayoutFlags flags,
size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets) {
const TypeLayout * const *fieldTypes) {
auto self = (ObjCClass *)cls;
bool requiresUpdate = SWIFT_RUNTIME_WEAK_CHECK(_objc_realizeClassFromSwift);
@@ -4105,6 +4129,11 @@ swift::swift_updatePureObjCClassMetadata(Class cls,
// which point at field offset globals and not the field offset vector.
swift_getInitializedObjCClass((Class)self);
} else {
// Fake up a field offsets vector based on the ivars.
// FIXME: Temporary; we should just combine the other two functions' logic.
size_t *fieldOffsets = (size_t *)alloca(numFields * sizeof(size_t));
populateInitialFieldOffsets(self, numFields, fieldOffsets);
// Update the field offset vector using runtime type information; the layout
// of resilient types might be different than the statically-emitted layout.
initClassFieldOffsetVector(self, numFields, fieldTypes, fieldOffsets);

View File

@@ -28,7 +28,7 @@
// CHECK: [[_PROPERTIES_ImplClass:@[^, ]+]] = internal constant { i32, i32, [1 x { ptr, ptr }] } { i32 16, i32 1, [1 x { ptr, ptr }] [{ ptr, ptr } { ptr @.str.12.implProperty, ptr @".str.18.Ti,N,VimplProperty" }] }, section "__DATA, __objc_const", align 8
// FIXME: Should just be @_PROTOCOLS_ImplClass, but an IRGen bug causes the protocol list to be emitted twice.
// CHECK: [[_DATA_ImplClass:@[^, ]+]] = internal constant { i32, i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr } { i32 388, i32 8, i32 24, i32 0, ptr null, ptr @.str.9.ImplClass, ptr [[_INSTANCE_METHODS_ImplClass]], ptr @_PROTOCOLS_ImplClass.{{[0-9]+}}, ptr [[_IVARS_ImplClass]], ptr null, ptr [[_PROPERTIES_ImplClass]] }, section "__DATA, __objc_data", align 8
// CHECK: @"OBJC_CLASS_$_ImplClass" = global <{ i64, ptr, ptr, ptr, i64, i64, i64 }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_ImplClass" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, i64 ptrtoint (ptr [[_DATA_ImplClass]] to i64), i64 8, i64 16 }>, section "__DATA,__objc_data, regular", align 8
// CHECK: @"OBJC_CLASS_$_ImplClass" = global <{ i64, ptr, ptr, ptr, i64 }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_ImplClass" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, i64 ptrtoint (ptr [[_DATA_ImplClass]] to i64) }>, section "__DATA,__objc_data, regular", align 8
// Swift metadata
// NEGATIVE-NOT: OBJC_CLASS_$_ImplClass.{{[0-9]}}
@@ -92,7 +92,7 @@
// CHECK: @_IVARS_NoInitImplClass = internal constant { i32, i32, [4 x { ptr, ptr, ptr, i32, i32 }] } { i32 32, i32 4, [4 x { ptr, ptr, ptr, i32, i32 }] [{ ptr, ptr, ptr, i32, i32 } { ptr @"$sSo15NoInitImplClassC19objc_implementationE2s1SSvpWvd", ptr @.str.2.s1, ptr @.str.0., i32 3, i32 16 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo15NoInitImplClassC19objc_implementationE2s2SSvpWvd", ptr @.str.2.s2, ptr @.str.0., i32 3, i32 16 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo15NoInitImplClassC19objc_implementationE2s3SSvpWvd", ptr @.str.2.s3, ptr @.str.0., i32 3, i32 16 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo15NoInitImplClassC19objc_implementationE2s4SSvpWvd", ptr @.str.2.s4, ptr @.str.0., i32 3, i32 16 }] }, section "__DATA, __objc_const", align 8
// CHECK: @_PROPERTIES_NoInitImplClass = internal constant { i32, i32, [4 x { ptr, ptr }] } { i32 16, i32 4, [4 x { ptr, ptr }] [{ ptr, ptr } { ptr @.str.2.s1, ptr @".str.16.T@\22NSString\22,N,R" }, { ptr, ptr } { ptr @.str.2.s2, ptr @".str.16.T@\22NSString\22,N,C" }, { ptr, ptr } { ptr @.str.2.s3, ptr @".str.16.T@\22NSString\22,N,R" }, { ptr, ptr } { ptr @.str.2.s4, ptr @".str.16.T@\22NSString\22,N,C" }] }, section "__DATA, __objc_const", align 8
// CHECK: @_DATA_NoInitImplClass = internal constant { i32, i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr } { i32 388, i32 8, i32 72, i32 0, ptr null, ptr @.str.15.NoInitImplClass, ptr @_INSTANCE_METHODS_NoInitImplClass, ptr null, ptr @_IVARS_NoInitImplClass, ptr null, ptr @_PROPERTIES_NoInitImplClass }, section "__DATA, __objc_data", align 8
// CHECK: @"OBJC_CLASS_$_NoInitImplClass" = global <{ i64, ptr, ptr, ptr, i64, i64, i64, i64, i64 }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_NoInitImplClass" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, i64 ptrtoint (ptr @_DATA_NoInitImplClass to i64), i64 8, i64 24, i64 40, i64 56 }>, section "__DATA,__objc_data, regular", align 8
// CHECK: @"OBJC_CLASS_$_NoInitImplClass" = global <{ i64, ptr, ptr, ptr, i64 }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_NoInitImplClass" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, i64 ptrtoint (ptr @_DATA_NoInitImplClass to i64) }>, section "__DATA,__objc_data, regular", align 8
@_objcImplementation extension NoInitImplClass {
@objc let s1 = "s1v"
@objc var s2 = "s2v"
@@ -142,7 +142,7 @@ open class SwiftSubclass: ImplClass {
// Class
// CHECK: @_IVARS_ImplClassWithResilientStoredProperty = internal constant { i32, i32, [4 x { ptr, ptr, ptr, i32, i32 }] } { i32 32, i32 4, [4 x { ptr, ptr, ptr, i32, i32 }] [{ ptr, ptr, ptr, i32, i32 } { ptr @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE9beforeInts5Int32VvpWvd", ptr @.str.9.beforeInt, ptr @.str.0., i32 2, i32 4 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE6mirrors6MirrorVSgvpWvd", ptr @.str.6.mirror, ptr @.str.0., i32 0, i32 0 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE13afterIntFinals5Int32VvpWvd", ptr @.str.13.afterIntFinal, ptr @.str.0., i32 2, i32 4 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE8afterInts5Int32VvpWvd", ptr @.str.8.afterInt, ptr @.str.0., i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
// CHECK: @_DATA_ImplClassWithResilientStoredProperty = internal constant { i32, i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr } { i32 452, i32 8, i32 20, i32 0, ptr null, ptr @.str.36.ImplClassWithResilientStoredProperty, ptr @_INSTANCE_METHODS_ImplClassWithResilientStoredProperty, ptr null, ptr @_IVARS_ImplClassWithResilientStoredProperty, ptr null, ptr @_PROPERTIES_ImplClassWithResilientStoredProperty, ptr @"$sSo36ImplClassWithResilientStoredPropertyCMU" }, section "__DATA, __objc_data", align 8
// CHECK: @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty" = global <{ i64, ptr, ptr, ptr, i64, i64, i64, i64, i64 }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_ImplClassWithResilientStoredProperty" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, i64 ptrtoint (ptr @_DATA_ImplClassWithResilientStoredProperty to i64), i64 0, i64 0, i64 0, i64 0 }>, section "__DATA,__objc_data, regular", align 8
// CHECK: @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty" = global <{ i64, ptr, ptr, ptr, i64 }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_ImplClassWithResilientStoredProperty" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, i64 ptrtoint (ptr @_DATA_ImplClassWithResilientStoredProperty to i64) }>, section "__DATA,__objc_data, regular", align 8
@_objcImplementation extension ImplClassWithResilientStoredProperty {
@objc var beforeInt: Int32 = 0
@@ -323,7 +323,7 @@ public func fn(impl: ImplClass, swiftSub: SwiftSubclass) {
// CHECK: store ptr {{%[0-9]+}}, ptr {{%[0-9]+}}
// CHECK: store ptr getelementptr inbounds (ptr, ptr @"$sBi32_WV", i32 8), ptr {{%[0-9]+}}
// CHECK: store ptr getelementptr inbounds (ptr, ptr @"$sBi32_WV", i32 8), ptr {{%[0-9]+}}
// CHECK: {{%[0-9]+}} = call swiftcc ptr @swift_updatePureObjCClassMetadata(ptr @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty", i64 256, i64 4, ptr [[FIELDS_ARRAY]], ptr getelementptr inbounds (i64, ptr @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty", i64 5))
// CHECK: {{%[0-9]+}} = call swiftcc ptr @swift_updatePureObjCClassMetadata(ptr @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty", i64 256, i64 4, ptr [[FIELDS_ARRAY]])
//
// This function should not invoke the metadata accessor.
// CHECK-NOT: sSo36ImplClassWithResilientStoredPropertyCMa