[Runtime] Reference ObjC class objects indirectly in conformance records.

Within conformance records, reference Objective-C class objects
indirectly so the runtime can update those references appropriately.
We don't need to do this for classes with Swift metadata.

Make all OBJC_CLASS_REF symbols object-local using "\01l", which
prevents the linker from producing incorrect relative addresses.

Fixes the ABI-affecting part of rdar://problem/36310179.
This commit is contained in:
Doug Gregor
2018-03-19 15:56:04 -07:00
parent 44e230b91a
commit cd617dce4a
7 changed files with 22 additions and 10 deletions

View File

@@ -766,6 +766,9 @@ public:
bool isForeignTypeMetadataCandidate() const { bool isForeignTypeMetadataCandidate() const {
return getKind() == Kind::ForeignTypeMetadataCandidate; return getKind() == Kind::ForeignTypeMetadataCandidate;
} }
bool isObjCClassRef() const {
return getKind() == Kind::ObjCClassRef;
}
/// Determine whether this entity will be weak-imported. /// Determine whether this entity will be weak-imported.
bool isWeakImported(ModuleDecl *module) const { bool isWeakImported(ModuleDecl *module) const {

View File

@@ -2445,6 +2445,15 @@ IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity,
Alignment alignment, Alignment alignment,
llvm::Type *defaultType, llvm::Type *defaultType,
ConstantReference::Directness forceIndirectness) { ConstantReference::Directness forceIndirectness) {
// ObjC class references can always be directly referenced, even in
// the weird cases where we don't see a definition.
if (entity.isObjCClassRef()) {
auto value = getAddrOfObjCClassRef(
const_cast<ClassDecl *>(cast<ClassDecl>(entity.getDecl())));
return { cast<llvm::Constant>(value.getAddress()),
ConstantReference::Direct };
}
// Ensure the variable is at least forward-declared. // Ensure the variable is at least forward-declared.
if (entity.isForeignTypeMetadataCandidate()) { if (entity.isForeignTypeMetadataCandidate()) {
auto foreignCandidate auto foreignCandidate
@@ -2522,7 +2531,7 @@ IRGenModule::getTypeEntityReference(NominalTypeDecl *decl) {
kind = TypeMetadataRecordKind::IndirectObjCClass; kind = TypeMetadataRecordKind::IndirectObjCClass;
defaultTy = TypeMetadataPtrTy; defaultTy = TypeMetadataPtrTy;
entity = LinkEntity::forObjCClass(clas); entity = LinkEntity::forObjCClassRef(clas);
} else { } else {
// A reference to a concrete type. // A reference to a concrete type.
// TODO: consider using a symbolic reference (i.e. a symbol string // TODO: consider using a symbolic reference (i.e. a symbol string
@@ -2537,8 +2546,8 @@ IRGenModule::getTypeEntityReference(NominalTypeDecl *decl) {
// Adjust the flags now that we know whether the reference to this // Adjust the flags now that we know whether the reference to this
// entity will be indirect. // entity will be indirect.
if (ref.isIndirect() && if (ref.isIndirect()) {
kind == TypeMetadataRecordKind::DirectNominalTypeDescriptor) { assert(kind == TypeMetadataRecordKind::DirectNominalTypeDescriptor);
kind = TypeMetadataRecordKind::IndirectNominalTypeDescriptor; kind = TypeMetadataRecordKind::IndirectNominalTypeDescriptor;
} }

View File

@@ -191,7 +191,7 @@ std::string LinkEntity::mangleAsString() const {
case Kind::ObjCClassRef: { case Kind::ObjCClassRef: {
llvm::SmallString<64> tempBuffer; llvm::SmallString<64> tempBuffer;
StringRef name = cast<ClassDecl>(getDecl())->getObjCRuntimeName(tempBuffer); StringRef name = cast<ClassDecl>(getDecl())->getObjCRuntimeName(tempBuffer);
std::string Result("OBJC_CLASS_REF_$_"); std::string Result("\01l_OBJC_CLASS_REF_$_");
Result.append(name.data(), name.size()); Result.append(name.data(), name.size());
return Result; return Result;
} }

View File

@@ -3,7 +3,7 @@
// CHECK-NOT: _TMnCSo // CHECK-NOT: _TMnCSo
// CHECK: @"$SSo6ThingyCyxG32objc_bridged_generic_conformance1PADMc" = hidden constant %swift.protocol_conformance_descriptor {{.*}} @"got.OBJC_CLASS_$_Thingy" // CHECK: @"$SSo6ThingyCyxG32objc_bridged_generic_conformance1PADMc" = hidden constant %swift.protocol_conformance_descriptor {{.*}} @"\01l_OBJC_CLASS_REF_$_Thingy"
// CHECK-NOT: _TMnCSo // CHECK-NOT: _TMnCSo

View File

@@ -28,7 +28,7 @@ bb0(%unused : $@thick T.Type, %obj : $NSObject):
// CHECK: [[T0:%.*]] = call %objc_object* @swift_dynamicCastMetatypeToObjectUnconditional(%swift.type* %0) // CHECK: [[T0:%.*]] = call %objc_object* @swift_dynamicCastMetatypeToObjectUnconditional(%swift.type* %0)
// TODO: is this really necessary? also, this really shouldn't use a direct reference // TODO: is this really necessary? also, this really shouldn't use a direct reference
// CHECK-NEXT: [[T1:%.*]] = bitcast %objc_object* [[T0]] to i8* // CHECK-NEXT: [[T1:%.*]] = bitcast %objc_object* [[T0]] to i8*
// CHECK-NEXT: [[T2a:%.*]] = load %objc_class*, %objc_class** @"OBJC_CLASS_REF_$_Foo" // CHECK-NEXT: [[T2a:%.*]] = load %objc_class*, %objc_class** @"\01l_OBJC_CLASS_REF_$_Foo"
// CHECK-NEXT: [[T2:%.*]] = call %objc_class* @swift_getInitializedObjCClass(%objc_class* [[T2a]]) // CHECK-NEXT: [[T2:%.*]] = call %objc_class* @swift_getInitializedObjCClass(%objc_class* [[T2a]])
// CHECK-NEXT: [[T3:%.*]] = bitcast %objc_class* [[T2]] to i8* // CHECK-NEXT: [[T3:%.*]] = bitcast %objc_class* [[T2]] to i8*
// CHECK-NEXT: call i8* @swift_dynamicCastObjCClassUnconditional(i8* [[T1]], i8* [[T3]]) // CHECK-NEXT: call i8* @swift_dynamicCastObjCClassUnconditional(i8* [[T1]], i8* [[T3]])
@@ -44,7 +44,7 @@ bb0(%metatype : $@thick T.Type):
// CHECK: [[T0:%.*]] = call %objc_object* @swift_dynamicCastMetatypeToObjectUnconditional(%swift.type* [[ARG]]) // CHECK: [[T0:%.*]] = call %objc_object* @swift_dynamicCastMetatypeToObjectUnconditional(%swift.type* [[ARG]])
// TODO: is this really necessary? also, this really shouldn't use a direct reference // TODO: is this really necessary? also, this really shouldn't use a direct reference
// CHECK-NEXT: [[T1:%.*]] = bitcast %objc_object* [[T0]] to i8* // CHECK-NEXT: [[T1:%.*]] = bitcast %objc_object* [[T0]] to i8*
// CHECK-NEXT: [[T2a:%.*]] = load %objc_class*, %objc_class** @"OBJC_CLASS_REF_$_Foo" // CHECK-NEXT: [[T2a:%.*]] = load %objc_class*, %objc_class** @"\01l_OBJC_CLASS_REF_$_Foo"
// CHECK-NEXT: [[T2:%.*]] = call %objc_class* @swift_getInitializedObjCClass(%objc_class* [[T2a]]) // CHECK-NEXT: [[T2:%.*]] = call %objc_class* @swift_getInitializedObjCClass(%objc_class* [[T2a]])
// CHECK-NEXT: [[T3:%.*]] = bitcast %objc_class* [[T2]] to i8* // CHECK-NEXT: [[T3:%.*]] = bitcast %objc_class* [[T2]] to i8*
// CHECK-NEXT: call i8* @swift_dynamicCastObjCClassUnconditional(i8* [[T1]], i8* [[T3]]) // CHECK-NEXT: call i8* @swift_dynamicCastObjCClassUnconditional(i8* [[T1]], i8* [[T3]])

View File

@@ -39,7 +39,7 @@ entry:
%b = metatype $@thick GenericClass<NSObject>.Type %b = metatype $@thick GenericClass<NSObject>.Type
apply %z<GenericClass<NSObject>>(%b) : $@convention(thin) <T> (@thick T.Type) -> () apply %z<GenericClass<NSObject>>(%b) : $@convention(thin) <T> (@thick T.Type) -> ()
// CHECK: [[T0:%.*]] = load %objc_class*, %objc_class** @"OBJC_CLASS_REF_$_GenericClass", // CHECK: [[T0:%.*]] = load %objc_class*, %objc_class** @"\01l_OBJC_CLASS_REF_$_GenericClass",
// CHECK: [[OBJC_CLASS:%.*]] = call %objc_class* @swift_getInitializedObjCClass(%objc_class* [[T0]]) // CHECK: [[OBJC_CLASS:%.*]] = call %objc_class* @swift_getInitializedObjCClass(%objc_class* [[T0]])
// CHECK: call swiftcc void @objc_class_sink(%objc_class* [[OBJC_CLASS]], %swift.type* [[METADATA]]) // CHECK: call swiftcc void @objc_class_sink(%objc_class* [[OBJC_CLASS]], %swift.type* [[METADATA]])
%c = metatype $@objc_metatype GenericClass<NSString>.Type %c = metatype $@objc_metatype GenericClass<NSString>.Type
@@ -79,7 +79,7 @@ entry(%0: $Subclass, %1: $NSDictionary):
} }
// CHECK-LABEL: define linkonce_odr hidden swiftcc %swift.metadata_response @"$SSo12GenericClassCMa"( // CHECK-LABEL: define linkonce_odr hidden swiftcc %swift.metadata_response @"$SSo12GenericClassCMa"(
// CHECK: [[T0:%.*]] = load %objc_class*, %objc_class** @"OBJC_CLASS_REF_$_GenericClass", // CHECK: [[T0:%.*]] = load %objc_class*, %objc_class** @"\01l_OBJC_CLASS_REF_$_GenericClass",
// CHECK: call %objc_class* @swift_getInitializedObjCClass(%objc_class* [[T0]]) // CHECK: call %objc_class* @swift_getInitializedObjCClass(%objc_class* [[T0]])
// CHECK-LABEL: define linkonce_odr hidden swiftcc %swift.metadata_response @"$SSaySo12GenericClassC_SitGMa" // CHECK-LABEL: define linkonce_odr hidden swiftcc %swift.metadata_response @"$SSaySo12GenericClassC_SitGMa"

View File

@@ -30,7 +30,7 @@ extension NSRect: Runcible {
// -- protocol descriptor // -- protocol descriptor
// CHECK-SAME: [[RUNCIBLE]] // CHECK-SAME: [[RUNCIBLE]]
// -- class object reference // -- class object reference
// CHECK-SAME: @"got.OBJC_CLASS_$_Gizmo" // CHECK-SAME: @"\01l_OBJC_CLASS_REF_$_Gizmo"
// -- witness table // -- witness table
// CHECK-SAME: @"$SSo5GizmoC33protocol_conformance_records_objc8RuncibleACWP" // CHECK-SAME: @"$SSo5GizmoC33protocol_conformance_records_objc8RuncibleACWP"
// -- flags // -- flags