Skip to content

Commit 41e7071

Browse files
authored
Merge pull request #15523 from rjmccall/archetype-isa-encoding
2 parents 9d72a2b + 2de86ea commit 41e7071

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

lib/IRGen/GenClass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2314,6 +2314,8 @@ bool irgen::doesClassMetadataRequireDynamicInitialization(IRGenModule &IGM,
23142314
}
23152315

23162316
bool irgen::hasKnownSwiftMetadata(IRGenModule &IGM, CanType type) {
2317+
// This needs to be kept up-to-date with getIsaEncodingForType.
2318+
23172319
if (ClassDecl *theClass = type.getClassOrBoundGenericClass()) {
23182320
return hasKnownSwiftMetadata(IGM, theClass);
23192321
}

lib/IRGen/GenHeap.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,13 +1969,32 @@ static ClassDecl *getRootClass(ClassDecl *theClass) {
19691969
/// What isa encoding mechanism does a type have?
19701970
IsaEncoding irgen::getIsaEncodingForType(IRGenModule &IGM,
19711971
CanType type) {
1972+
if (!IGM.ObjCInterop) return IsaEncoding::Pointer;
1973+
1974+
// This needs to be kept up-to-date with hasKnownSwiftMetadata.
1975+
19721976
if (auto theClass = type->getClassOrBoundGenericClass()) {
19731977
// We can access the isas of pure Swift classes directly.
19741978
if (getRootClass(theClass)->hasKnownSwiftImplementation())
19751979
return IsaEncoding::Pointer;
19761980
// For ObjC or mixed classes, we need to use object_getClass.
19771981
return IsaEncoding::ObjC;
19781982
}
1983+
1984+
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
1985+
// If we have a concrete superclass constraint, just recurse.
1986+
if (auto superclass = archetype->getSuperclass()) {
1987+
return getIsaEncodingForType(IGM, superclass->getCanonicalType());
1988+
}
1989+
1990+
// Otherwise, we must just have a class constraint. Use the
1991+
// conservative answer.
1992+
return IsaEncoding::ObjC;
1993+
}
1994+
1995+
// We should never be working with an unopened existential type here.
1996+
assert(!type->isAnyExistentialType());
1997+
19791998
// Non-class heap objects should be pure Swift, so we can access their isas
19801999
// directly.
19812000
return IsaEncoding::Pointer;

test/IRGen/objc_casts.sil

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
import Swift
88
import Foundation
99

10+
class SwiftClass {}
11+
sil_vtable SwiftClass {}
12+
13+
protocol ClassProto : class {}
14+
1015
// CHECK-LABEL: define hidden swiftcc %TSo8NSObjectC* @checkedClassBoundCast(%swift.type*, %TSo8NSObjectC*, %swift.type* %T) #0 {
1116
// CHECK: [[OPAQUE_OBJ:%.+]] = bitcast %TSo8NSObjectC* %1 to i8*
1217
// CHECK: [[OPAQUE_CLASS:%.+]] = bitcast %swift.type* %T to i8*
@@ -54,3 +59,27 @@ bb0(%metatype : $Optional<@thick T.Type>):
5459
%tuple = tuple ()
5560
return %tuple : $()
5661
}
62+
63+
// CHECK-LABEL: define hidden swiftcc { %objc_object*, i8** } @swift_class_bounded_to_cp
64+
// CHECK-SAME: ([[SWIFTCLASS:%T10objc_casts10SwiftClassC]]*, %swift.type* %T)
65+
// CHECK: [[T0:%.*]] = bitcast [[SWIFTCLASS]]* %0 to %swift.type**
66+
// CHECK-NEXT: [[TYPE:%.*]] = load %swift.type*, %swift.type** [[T0]],
67+
// CHECK-NEXT: [[T0:%.*]] = bitcast [[SWIFTCLASS]]* %0 to i8*
68+
// CHECK-NEXT: call { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* [[T0]], %swift.type* [[TYPE]], %swift.protocol* @"$S10objc_casts10ClassProtoMp")
69+
sil hidden @swift_class_bounded_to_cp : $@convention(thin) <T: SwiftClass> (@owned T) -> @owned ClassProto {
70+
entry(%a : $T):
71+
%0 = unconditional_checked_cast %a : $T to $ClassProto
72+
return %0 : $ClassProto
73+
}
74+
75+
// CHECK-LABEL: define hidden swiftcc { %objc_object*, i8** } @objc_class_bounded_to_cp
76+
// CHECK-SAME: ([[OBJCCLASS:%TSo8NSObjectC]]*, %swift.type* %T)
77+
// CHECK: [[T0:%.*]] = bitcast [[OBJCCLASS]]* %0 to %objc_object*
78+
// CHECK-NEXT: [[TYPE:%.*]] = call %swift.type* @swift_getObjectType(%objc_object* [[T0]])
79+
// CHECK-NEXT: [[T0:%.*]] = bitcast [[OBJCCLASS]]* %0 to i8*
80+
// CHECK-NEXT: call { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* [[T0]], %swift.type* [[TYPE]], %swift.protocol* @"$S10objc_casts10ClassProtoMp")
81+
sil hidden @objc_class_bounded_to_cp : $@convention(thin) <T: NSObject> (@owned T) -> @owned ClassProto {
82+
entry(%a : $T):
83+
%0 = unconditional_checked_cast %a : $T to $ClassProto
84+
return %0 : $ClassProto
85+
}

0 commit comments

Comments
 (0)