Skip to content

Commit 4e7ce5a

Browse files
committed
[IRGen+Runtime] Differentiate between pure Swift and regular ObjC references in CVW
rdar://139106139 Regular ObjC references do not have unused bits or extra inhabitants for storing enum tags, because they may be tagged pointers. However, ObjC classes that are implemented in Swift do, so we must differentiate between the two.
1 parent af036fe commit 4e7ce5a

File tree

4 files changed

+112
-29
lines changed

4 files changed

+112
-29
lines changed

lib/IRGen/TypeLayout.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class LayoutStringBuilder {
7070
Bridge = 0x08,
7171
Block = 0x09,
7272
ObjC = 0x0a,
73-
Custom = 0x0b,
73+
NativeSwiftObjC = 0x0b,
7474

7575
// reserved
7676
// Metatype = 0x0c,
@@ -1294,7 +1294,12 @@ bool ScalarTypeLayoutEntry::refCountString(IRGenModule &IGM,
12941294
B.addRefCount(LayoutStringBuilder::RefCountingKind::Block, size);
12951295
break;
12961296
case ScalarKind::ObjCReference:
1297-
B.addRefCount(LayoutStringBuilder::RefCountingKind::ObjC, size);
1297+
if (typeInfo.hasFixedSpareBits()) {
1298+
B.addRefCount(LayoutStringBuilder::RefCountingKind::NativeSwiftObjC,
1299+
size);
1300+
} else {
1301+
B.addRefCount(LayoutStringBuilder::RefCountingKind::ObjC, size);
1302+
}
12981303
break;
12991304
case ScalarKind::ThickFunc:
13001305
B.addSkip(IGM.getPointerSize().getValue());

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,15 @@ static uint64_t readTagBytes(const uint8_t *addr, uint8_t byteCount) {
127127
uint64_t TAG = 0; \
128128
uintptr_t OFFSET = 0; \
129129
\
130-
_Pragma("clang diagnostic push") \
131-
_Pragma("clang diagnostic ignored \"-Wgnu-label-as-value\"") \
132-
const void *dispatchTable[] = { \
133-
&&done, &&Error, &&NativeStrong, &&NativeUnowned, \
134-
&&NativeWeak, &&Unknown, &&UnknownUnowned, &&UnknownWeak, \
135-
&&Bridge, &&Block, &&ObjC, &&Custom, \
136-
&&Metatype, &&Generic, &&Existential, &&Resilient, \
137-
&&Default, &&Default, &&Default, &&Default, \
138-
&&Default, &&Default, &&Default, \
130+
_Pragma("clang diagnostic push") _Pragma( \
131+
"clang diagnostic ignored \"-Wgnu-label-as-value\"") \
132+
const void *dispatchTable[] = { \
133+
&&done, &&Error, &&NativeStrong, &&NativeUnowned, \
134+
&&NativeWeak, &&Unknown, &&UnknownUnowned, &&UnknownWeak, \
135+
&&Bridge, &&Block, &&ObjC, &&NativeSwiftObjC, \
136+
&&Metatype, &&Generic, &&Existential, &&Resilient, \
137+
&&Default, &&Default, &&Default, &&Default, \
138+
&&Default, &&Default, &&Default, \
139139
}; \
140140
\
141141
[[clang::nomerge]] { \
@@ -194,8 +194,9 @@ static uint64_t readTagBytes(const uint8_t *addr, uint8_t byteCount) {
194194
CONTINUE(METADATA, READER, ADDR_OFFSET, __VA_ARGS__); \
195195
} \
196196
[[clang::nomerge]] { \
197-
Custom: \
198-
swift_unreachable(""); \
197+
NativeSwiftObjC: \
198+
FN_TABLE[11](METADATA, READER, ADDR_OFFSET, __VA_ARGS__); \
199+
CONTINUE(METADATA, READER, ADDR_OFFSET, __VA_ARGS__); \
199200
} \
200201
[[clang::nomerge]] { \
201202
Metatype: \
@@ -782,9 +783,18 @@ static void objcStrongDestroy(const Metadata *metadata,
782783
#if SWIFT_OBJC_INTEROP
783784
uintptr_t object = *(uintptr_t *)(addr + addrOffset);
784785
addrOffset += sizeof(objc_object*);
785-
if (object & _swift_abi_ObjCReservedBitsMask)
786-
return;
786+
objc_release((objc_object *)object);
787+
#else
788+
swift_unreachable("ObjC interop is not available on this platform");
789+
#endif
790+
}
787791

792+
static void nativeSwiftObjcStrongDestroy(const Metadata *metadata,
793+
LayoutStringReader1 &reader,
794+
uintptr_t &addrOffset, uint8_t *addr) {
795+
#if SWIFT_OBJC_INTEROP
796+
uintptr_t object = *(uintptr_t *)(addr + addrOffset);
797+
addrOffset += sizeof(objc_object *);
788798
object &= ~_swift_abi_SwiftSpareBitsMask;
789799
objc_release((objc_object *)object);
790800
#else
@@ -838,7 +848,7 @@ constexpr DestrFn destroyTable[] = {
838848
&bridgeDestroy,
839849
&blockDestroy,
840850
&objcStrongDestroy,
841-
nullptr, // Custom
851+
&nativeSwiftObjcStrongDestroy,
842852
&metatypeDestroy,
843853
nullptr, // Generic
844854
&existentialDestroy,
@@ -1006,8 +1016,21 @@ static void objcStrongRetain(const Metadata *metadata,
10061016
uintptr_t object = *(uintptr_t *)(src + _addrOffset);
10071017
memcpy(dest + _addrOffset, &object, sizeof(objc_object *));
10081018
addrOffset = _addrOffset + sizeof(objc_object *);
1009-
if (object & _swift_abi_ObjCReservedBitsMask)
1010-
return;
1019+
objc_retain((objc_object *)object);
1020+
#else
1021+
swift_unreachable("ObjC interop is not available on this platform");
1022+
#endif
1023+
}
1024+
1025+
static void nativeSwiftObjcStrongRetain(const Metadata *metadata,
1026+
LayoutStringReader1 &reader,
1027+
uintptr_t &addrOffset, uint8_t *dest,
1028+
uint8_t *src) {
1029+
#if SWIFT_OBJC_INTEROP
1030+
uintptr_t _addrOffset = addrOffset;
1031+
uintptr_t object = *(uintptr_t *)(src + _addrOffset);
1032+
memcpy(dest + _addrOffset, &object, sizeof(objc_object *));
1033+
addrOffset = _addrOffset + sizeof(objc_object *);
10111034
object &= ~_swift_abi_SwiftSpareBitsMask;
10121035
objc_retain((objc_object *)object);
10131036
#else
@@ -1069,7 +1092,7 @@ constexpr InitFn initWithCopyTable[] = {
10691092
&bridgeRetain,
10701093
&blockCopy,
10711094
&objcStrongRetain,
1072-
nullptr, // Custom
1095+
&nativeSwiftObjcStrongRetain,
10731096
&metatypeInitWithCopy,
10741097
nullptr, // Generic
10751098
&existentialInitWithCopy,
@@ -1429,15 +1452,29 @@ static void objcStrongAssignWithCopy(const Metadata *metadata,
14291452
memcpy(dest + _addrOffset, &srcObject, sizeof(objc_object*));
14301453
addrOffset = _addrOffset + sizeof(objc_object*);
14311454

1432-
if (!(destObject & _swift_abi_ObjCReservedBitsMask)) {
1433-
destObject &= ~_swift_abi_SwiftSpareBitsMask;
1434-
objc_release((objc_object *)destObject);
1435-
}
1455+
objc_release((objc_object *)destObject);
1456+
objc_retain((objc_object *)srcObject);
1457+
#else
1458+
swift_unreachable("ObjC interop is not available on this platform");
1459+
#endif
1460+
}
14361461

1437-
if (!(srcObject & _swift_abi_ObjCReservedBitsMask)) {
1438-
srcObject &= ~_swift_abi_SwiftSpareBitsMask;
1439-
objc_retain((objc_object *)srcObject);
1440-
}
1462+
static void nativeSwiftObjcStrongAssignWithCopy(const Metadata *metadata,
1463+
LayoutStringReader1 &reader,
1464+
uintptr_t &addrOffset,
1465+
uint8_t *dest, uint8_t *src) {
1466+
#if SWIFT_OBJC_INTEROP
1467+
uintptr_t _addrOffset = addrOffset;
1468+
uintptr_t destObject = *(uintptr_t *)(dest + _addrOffset);
1469+
uintptr_t srcObject = *(uintptr_t *)(src + _addrOffset);
1470+
memcpy(dest + _addrOffset, &srcObject, sizeof(objc_object *));
1471+
addrOffset = _addrOffset + sizeof(objc_object *);
1472+
1473+
destObject &= ~_swift_abi_SwiftSpareBitsMask;
1474+
objc_release((objc_object *)destObject);
1475+
1476+
srcObject &= ~_swift_abi_SwiftSpareBitsMask;
1477+
objc_retain((objc_object *)srcObject);
14411478
#else
14421479
swift_unreachable("ObjC interop is not available on this platform");
14431480
#endif
@@ -1873,7 +1910,7 @@ constexpr InitFn assignWithCopyTable[] = {
18731910
&bridgeAssignWithCopy,
18741911
&blockAssignWithCopy,
18751912
&objcStrongAssignWithCopy,
1876-
nullptr, // Custom
1913+
&nativeSwiftObjcStrongAssignWithCopy,
18771914
&metatypeAssignWithCopy,
18781915
nullptr, // Generic
18791916
&existentialAssignWithCopy,

stdlib/public/runtime/BytecodeLayouts.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ enum class RefCountingKind : uint8_t {
3636
Bridge = 0x08,
3737
Block = 0x09,
3838
ObjC = 0x0a,
39-
Custom = 0x0b,
39+
NativeSwiftObjC = 0x0b,
4040

4141
Metatype = 0x0c,
4242
Generic = 0x0d,

test/Interpreter/layout_string_witnesses_objc.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,44 @@ func testMultiPayloadObjCExistentialWrapper() {
9292
}
9393

9494
testMultiPayloadObjCExistentialWrapper()
95+
96+
@objc
97+
class SwiftObjC: NSObject {
98+
deinit {
99+
print("SwiftObjC deinitialized!")
100+
}
101+
}
102+
103+
enum MultiPayloadNativeSwiftObjC {
104+
case x(SwiftObjC)
105+
case y(SwiftObjC)
106+
case z(SwiftObjC)
107+
}
108+
109+
func testMultiPayloadNativeSwiftObjC() {
110+
let ptr = allocateInternalGenericPtr(of: MultiPayloadNativeSwiftObjC.self)
111+
112+
do {
113+
let x = MultiPayloadNativeSwiftObjC.y(SwiftObjC())
114+
testGenericInit(ptr, to: x)
115+
}
116+
117+
do {
118+
let y = MultiPayloadNativeSwiftObjC.z(SwiftObjC())
119+
// CHECK: Before deinit
120+
print("Before deinit")
121+
122+
// CHECK-NEXT: SwiftObjC deinitialized!
123+
testGenericAssign(ptr, from: y)
124+
}
125+
126+
// CHECK-NEXT: Before deinit
127+
print("Before deinit")
128+
129+
// CHECK-NEXT: SwiftObjC deinitialized!
130+
testGenericDestroy(ptr, of: MultiPayloadNativeSwiftObjC.self)
131+
132+
ptr.deallocate()
133+
}
134+
135+
testMultiPayloadNativeSwiftObjC()

0 commit comments

Comments
 (0)