Skip to content

Commit f8aef0a

Browse files
authored
Merge pull request #12732 from jckarter/objc-class-metadata-unwrapping
[WIP] Runtime: Put ObjC class wrapper unwrapping behind a runtime call.
2 parents b4899f1 + 95d2510 commit f8aef0a

File tree

13 files changed

+66
-76
lines changed

13 files changed

+66
-76
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2750,13 +2750,18 @@ swift_getBlockTypeMetadata3(const void *arg0,
27502750
SWIFT_RUNTIME_EXPORT
27512751
void
27522752
swift_instantiateObjCClass(const ClassMetadata *theClass);
2753-
#endif
27542753

27552754
/// \brief Fetch a uniqued type metadata for an ObjC class.
27562755
SWIFT_RUNTIME_EXPORT
27572756
const Metadata *
27582757
swift_getObjCClassMetadata(const ClassMetadata *theClass);
27592758

2759+
/// \brief Get the ObjC class object from class type metadata.
2760+
SWIFT_RUNTIME_EXPORT
2761+
const ClassMetadata *
2762+
swift_getObjCClassFromMetadata(const Metadata *theClass);
2763+
#endif
2764+
27602765
/// \brief Fetch a unique type metadata object for a foreign type.
27612766
SWIFT_RUNTIME_EXPORT
27622767
const ForeignTypeMetadata *

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,12 @@ FUNCTION(GetObjCClassMetadata, swift_getObjCClassMetadata, DefaultCC,
841841
ARGS(ObjCClassPtrTy),
842842
ATTRS(NoUnwind, ReadNone))
843843

844+
// Metadata *swift_getObjCClassFromMetadata(objc_class *theClass);
845+
FUNCTION(GetObjCClassFromMetadata, swift_getObjCClassFromMetadata, DefaultCC,
846+
RETURNS(ObjCClassPtrTy),
847+
ARGS(TypeMetadataPtrTy),
848+
ATTRS(NoUnwind, ReadNone))
849+
844850
// Metadata *swift_getTupleTypeMetadata(size_t numElements,
845851
// Metadata * const *elts,
846852
// const char *labels,

lib/IRGen/GenMeta.cpp

Lines changed: 11 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ static llvm::Constant *getMangledTypeName(IRGenModule &IGM, CanType type,
108108

109109
llvm::Value *irgen::emitObjCMetadataRefForMetadata(IRGenFunction &IGF,
110110
llvm::Value *classPtr) {
111+
assert(IGF.IGM.Context.LangOpts.EnableObjCInterop);
111112
classPtr = IGF.Builder.CreateBitCast(classPtr, IGF.IGM.ObjCClassPtrTy);
112113

113114
// Fetch the metadata for that class.
@@ -4204,46 +4205,16 @@ llvm::Value *irgen::emitClassHeapMetadataRefForMetatype(IRGenFunction &IGF,
42044205
if (hasKnownSwiftMetadata(IGF.IGM, type))
42054206
return metatype;
42064207

4207-
// Otherwise, we inline a little operation here.
4208-
4209-
// Load the metatype kind.
4210-
auto metatypeKindAddr =
4211-
Address(IGF.Builder.CreateStructGEP(/*Ty=*/nullptr, metatype, 0),
4212-
IGF.IGM.getPointerAlignment());
4213-
auto metatypeKind =
4214-
IGF.Builder.CreateLoad(metatypeKindAddr, metatype->getName() + ".kind");
4215-
4216-
// Compare it with the class wrapper kind.
4217-
auto classWrapperKind =
4218-
llvm::ConstantInt::get(IGF.IGM.MetadataKindTy,
4219-
unsigned(MetadataKind::ObjCClassWrapper));
4220-
auto isObjCClassWrapper =
4221-
IGF.Builder.CreateICmpEQ(metatypeKind, classWrapperKind,
4222-
"isObjCClassWrapper");
4223-
4224-
// Branch based on that.
4225-
llvm::BasicBlock *contBB = IGF.createBasicBlock("metadataForClass.cont");
4226-
llvm::BasicBlock *wrapBB = IGF.createBasicBlock("isWrapper");
4227-
IGF.Builder.CreateCondBr(isObjCClassWrapper, wrapBB, contBB);
4228-
llvm::BasicBlock *origBB = IGF.Builder.GetInsertBlock();
4229-
4230-
// If it's a wrapper, load from the 'Class' field, which is at index 1.
4231-
// TODO: if we guaranteed that this load couldn't crash, we could use
4232-
// a select here instead, which might be profitable.
4233-
IGF.Builder.emitBlock(wrapBB);
4234-
auto classFromWrapper =
4235-
emitInvariantLoadFromMetadataAtIndex(IGF, metatype, 1,
4236-
IGF.IGM.TypeMetadataPtrTy);
4237-
IGF.Builder.CreateBr(contBB);
4238-
4239-
// Continuation block.
4240-
IGF.Builder.emitBlock(contBB);
4241-
auto phi = IGF.Builder.CreatePHI(IGF.IGM.TypeMetadataPtrTy, 2,
4242-
metatype->getName() + ".class");
4243-
phi->addIncoming(metatype, origBB);
4244-
phi->addIncoming(classFromWrapper, wrapBB);
4245-
4246-
return phi;
4208+
// Otherwise, we may have to unwrap an ObjC class wrapper.
4209+
assert(IGF.IGM.Context.LangOpts.EnableObjCInterop);
4210+
metatype = IGF.Builder.CreateBitCast(metatype, IGF.IGM.TypeMetadataPtrTy);
4211+
4212+
// Fetch the metadata for that class.
4213+
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetObjCClassFromMetadataFn(),
4214+
metatype);
4215+
call->setDoesNotThrow();
4216+
call->setDoesNotAccessMemory();
4217+
return call;
42474218
}
42484219

42494220
/// Load the correct virtual function for the given class method.

stdlib/public/runtime/Casting.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3196,7 +3196,7 @@ SWIFT_CC(swift)
31963196
const Metadata *swift::_swift_class_getSuperclass(const Metadata *theClass) {
31973197
if (const ClassMetadata *classType = theClass->getClassObject())
31983198
if (classHasSuperclass(classType))
3199-
return swift_getObjCClassMetadata(classType->SuperClass);
3199+
return getMetadataForClass(classType->SuperClass);
32003200
return nullptr;
32013201
}
32023202

stdlib/public/runtime/Metadata.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,6 @@ namespace {
281281
/// The uniquing structure for ObjC class-wrapper metadata.
282282
static SimpleGlobalCache<ObjCClassCacheEntry> ObjCClassWrappers;
283283

284-
#endif
285-
286284
const Metadata *
287285
swift::swift_getObjCClassMetadata(const ClassMetadata *theClass) {
288286
// Make calls resilient against receiving a null Objective-C class. This can
@@ -295,14 +293,24 @@ swift::swift_getObjCClassMetadata(const ClassMetadata *theClass) {
295293
return theClass;
296294
}
297295

298-
#if SWIFT_OBJC_INTEROP
299296
return &ObjCClassWrappers.getOrInsert(theClass).first->Data;
300-
#else
301-
fatalError(/* flags = */ 0,
302-
"swift_getObjCClassMetadata: no Objective-C interop");
303-
#endif
304297
}
305298

299+
const ClassMetadata *
300+
swift::swift_getObjCClassFromMetadata(const Metadata *theMetadata) {
301+
// Unwrap ObjC class wrappers.
302+
if (auto wrapper = dyn_cast<ObjCClassWrapperMetadata>(theMetadata)) {
303+
return wrapper->Class;
304+
}
305+
306+
// Otherwise, the input should already be a Swift class object.
307+
auto theClass = cast<ClassMetadata>(theMetadata);
308+
assert(theClass->isTypeMetadata() && !theClass->isArtificialSubclass());
309+
return theClass;
310+
}
311+
312+
#endif
313+
306314
/***************************************************************************/
307315
/*** Functions *************************************************************/
308316
/***************************************************************************/

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@ const Metadata *TypeMetadataRecord::getCanonicalTypeMetadata() const {
137137
}
138138
case TypeMetadataRecordKind::UniqueDirectClass:
139139
if (auto *ClassMetadata =
140-
static_cast<const ::ClassMetadata *>(getDirectType()))
141-
return swift_getObjCClassMetadata(ClassMetadata);
140+
static_cast<const ::ClassMetadata *>(getDirectType())) {
141+
return getMetadataForClass(ClassMetadata);
142+
}
142143
else
143144
return nullptr;
144145
default:

stdlib/public/runtime/Private.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,14 @@ namespace swift {
190190
void (*function)(void *));
191191
#endif
192192

193+
static inline const Metadata *getMetadataForClass(const ClassMetadata *c) {
194+
#if SWIFT_OBJC_INTEROP
195+
return swift_getObjCClassMetadata(c);
196+
#else
197+
return c;
198+
#endif
199+
}
200+
193201
} // end namespace swift
194202

195203
#endif /* SWIFT_RUNTIME_PRIVATE_H */

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,14 @@ const Metadata *ProtocolConformanceRecord::getCanonicalTypeMetadata() const {
108108
// metadata. The class additionally may be weak-linked, so we have to check
109109
// for null.
110110
if (auto *ClassMetadata = *getIndirectClass())
111-
return swift_getObjCClassMetadata(ClassMetadata);
111+
return getMetadataForClass(ClassMetadata);
112112
return nullptr;
113113

114114
case TypeMetadataRecordKind::UniqueDirectClass:
115115
// The class may be ObjC, in which case we need to instantiate its Swift
116116
// metadata.
117117
if (auto *ClassMetadata = getDirectClass())
118-
return swift_getObjCClassMetadata(ClassMetadata);
118+
return getMetadataForClass(ClassMetadata);
119119
return nullptr;
120120

121121
case TypeMetadataRecordKind::UniqueNominalTypeDescriptor:
@@ -394,7 +394,7 @@ searchInConformanceCache(const Metadata *type,
394394
// If the type is a class, try its superclass.
395395
if (const ClassMetadata *classType = type->getClassObject()) {
396396
if (classHasSuperclass(classType)) {
397-
type = swift_getObjCClassMetadata(classType->SuperClass);
397+
type = getMetadataForClass(classType->SuperClass);
398398
goto recur;
399399
}
400400
}
@@ -433,7 +433,7 @@ bool isRelatedType(const Metadata *type, const void *candidate,
433433
// If the type is a class, try its superclass.
434434
if (const ClassMetadata *classType = type->getClassObject()) {
435435
if (classHasSuperclass(classType)) {
436-
type = swift_getObjCClassMetadata(classType->SuperClass);
436+
type = getMetadataForClass(classType->SuperClass);
437437
continue;
438438
}
439439
}

stdlib/public/runtime/Reflection.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ void swift_MagicMirrorData_summary(const Metadata *T, String *result) {
295295
const Metadata *type) {
296296
void *object = *reinterpret_cast<void * const *>(value);
297297
auto isa = _swift_getClass(object);
298-
return swift_getObjCClassMetadata(isa);
298+
return getMetadataForClass(isa);
299299
}
300300

301301
static std::tuple<const Metadata *, const OpaqueValue *>

stdlib/public/runtime/SwiftObject.mm

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,7 @@ static Class _swift_getObjCClassOfAllocated(const void *object) {
105105
const Metadata *swift::swift_getObjectType(HeapObject *object) {
106106
auto classAsMetadata = _swift_getClass(object);
107107

108-
#if !SWIFT_OBJC_INTEROP
109-
assert(classAsMetadata &&
110-
classAsMetadata->isTypeMetadata() &&
111-
!classAsMetadata->isArtificialSubclass());
112-
return classAsMetadata;
113-
#else
108+
#if SWIFT_OBJC_INTEROP
114109
// Walk up the superclass chain skipping over artifical Swift classes.
115110
// If we find a non-Swift class use the result of [object class] instead.
116111

@@ -129,6 +124,11 @@ static Class _swift_getObjCClassOfAllocated(const void *object) {
129124
}
130125
classAsMetadata = reinterpret_cast<const ClassMetadata *>(objcClass);
131126
return swift_getObjCClassMetadata(classAsMetadata);
127+
#else
128+
assert(classAsMetadata &&
129+
classAsMetadata->isTypeMetadata() &&
130+
!classAsMetadata->isArtificialSubclass());
131+
return classAsMetadata;
132132
#endif
133133
}
134134

test/ClangImporter/objc_ir.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func propertyAccess(b b: B) {
7373
b.counter = b.counter + 1
7474

7575
// CHECK: call %swift.type* @_T0So1BCMa()
76-
// CHECK: bitcast %swift.type* {{%.+}} to %objc_class*
76+
// CHECK: call %objc_class* @swift_getObjCClassFromMetadata
7777
// CHECK: load i8*, i8** @"\01L_selector(sharedCounter)"
7878
// CHECK: load i8*, i8** @"\01L_selector(setSharedCounter:)"
7979
B.sharedCounter = B.sharedCounter + 1

test/IRGen/abitypes.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,8 @@ class Foo {
214214

215215
// x86_64-macosx: define hidden i8* @_T08abitypes3FooC9copyClass{{[_0-9a-zA-Z]*}}FTo(i8*, i8*, i8*) unnamed_addr {{.*}} {
216216
// x86_64-macosx: [[VALUE:%[0-9]+]] = call swiftcc [[TYPE:%.*]]* @_T08abitypes3FooC9copyClass{{[_0-9a-zA-Z]*}}F
217-
// x86_64-macosx: [[T0:%.*]] = phi [[TYPE]]* [ [[VALUE]],
218-
// x86_64-macosx: [[T1:%.*]] = bitcast [[TYPE]]* [[T0]] to [[OBJC:%objc_class]]*
219-
// x86_64-macosx: [[RESULT:%[0-9]+]] = bitcast [[OBJC]]* [[T1]] to i8*
217+
// x86_64-macosx: [[T0:%.*]] = call [[OBJC:%objc_class]]* @swift_getObjCClassFromMetadata([[TYPE]]* [[VALUE]])
218+
// x86_64-macosx: [[RESULT:%[0-9]+]] = bitcast [[OBJC]]* [[T0]] to i8*
220219
// x86_64-macosx: ret i8* [[RESULT]]
221220
dynamic func copyClass(_ a: AnyClass) -> AnyClass {
222221
return a

test/IRGen/metatype.sil

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ bb0(%0 : $@thick X.Type):
3131
// CHECK-LABEL: define{{( protected)?}} swiftcc %objc_class* @foreign_thick_to_objc(%swift.type*)
3232
sil @foreign_thick_to_objc : $@convention(thin) (@thick Gizmo.Type) -> @objc_metatype Gizmo.Type {
3333
bb0(%0 : $@thick Gizmo.Type):
34-
// CHECK: [[KIND_GEP:%[0-9A-Za-z_.]+]] = getelementptr inbounds %swift.type, %swift.type* %0, i32 0, i32 0
35-
// CHECK-NEXT: [[KIND:%[0-9A-Za-z_.]+]] = load i64, i64* [[KIND_GEP]], align 8
36-
// CHECK-NEXT: [[IS_WRAPPER:%[0-9A-Za-z_.]+]] = icmp eq i64 [[KIND]], 14
37-
// CHECK-NEXT: br i1
34+
// CHECK: call %objc_class* @swift_getObjCClassFromMetadata
3835
%1 = thick_to_objc_metatype %0 : $@thick Gizmo.Type to $@objc_metatype Gizmo.Type
3936
// CHECK: ret %objc_class*
4037
return %1 : $@objc_metatype Gizmo.Type
@@ -61,12 +58,7 @@ bb0(%0 : $@objc_metatype Gizmo.Type):
6158
protocol CP: class {}
6259

6360
// CHECK-LABEL: define{{( protected)?}} swiftcc %objc_class* @archetype_objc_metatype(%swift.type* %T, i8** %T.CP)
64-
// CHECK: [[IS_OBJC_WRAPPER:%.*]] = icmp eq i64 {{%.*}}, 14
65-
// CHECK: br i1 [[IS_OBJC_WRAPPER]], label %isWrapper, label %metadataForClass.cont
66-
// CHECK: isWrapper:
67-
// CHECK: [[WRAPPED_CLASS:%.*]] = load %swift.type*, %swift.type**
68-
// CHECK: metadataForClass.cont:
69-
// CHECK: phi %swift.type* [ %T, %entry ], [ [[WRAPPED_CLASS]], %isWrapper ]
61+
// CHECK: call %objc_class* @swift_getObjCClassFromMetadata
7062
sil @archetype_objc_metatype : $@convention(thin) <T: CP> () -> @objc_metatype T.Type {
7163
entry:
7264
%m = metatype $@objc_metatype T.Type

0 commit comments

Comments
 (0)