Skip to content

Commit 3c7b556

Browse files
committed
[IRGen+Runtime] Fix tag bit mask handling for objc, unknown objects and blocks
rdar://138487964 On platforms that don't have reserved bits in objc (including unknown) pointers, we use the spare bits for Swift enums, so they have to be masked out. Blocks don't have reserved bits on any platform.
1 parent bba4f65 commit 3c7b556

File tree

5 files changed

+169
-17
lines changed

5 files changed

+169
-17
lines changed

lib/IRGen/TypeLayout.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212
#include "TypeLayout.h"
13+
#include "ClassTypeInfo.h"
1314
#include "ConstantBuilder.h"
1415
#include "EnumPayload.h"
1516
#include "FixedTypeInfo.h"
@@ -1293,14 +1294,17 @@ bool ScalarTypeLayoutEntry::refCountString(IRGenModule &IGM,
12931294
case ScalarKind::BlockReference:
12941295
B.addRefCount(LayoutStringBuilder::RefCountingKind::Block, size);
12951296
break;
1296-
case ScalarKind::ObjCReference:
1297-
if (typeInfo.hasFixedSpareBits()) {
1297+
case ScalarKind::ObjCReference: {
1298+
auto *classTI = dyn_cast<ClassTypeInfo>(&typeInfo);
1299+
assert(classTI);
1300+
if (!classTI->getClass()->hasClangNode()) {
12981301
B.addRefCount(LayoutStringBuilder::RefCountingKind::NativeSwiftObjC,
12991302
size);
13001303
} else {
13011304
B.addRefCount(LayoutStringBuilder::RefCountingKind::ObjC, size);
13021305
}
13031306
break;
1307+
}
13041308
case ScalarKind::ThickFunc:
13051309
B.addSkip(IGM.getPointerSize().getValue());
13061310
B.addRefCount(LayoutStringBuilder::RefCountingKind::NativeStrong,

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,16 @@ static uint64_t readTagBytes(const uint8_t *addr, uint8_t byteCount) {
9797
}
9898
}
9999

100+
// This check is used to determine whether or not ObjC references can
101+
// be tagged pointers. If they can't, they have the same spare bits
102+
// as swift references, and we have to mask them out before passing the
103+
// reference to ref counting operations.
104+
static constexpr bool platformSupportsTaggedPointers() {
105+
// Platforms that don't reserve bits for ObjC, don't support tagged
106+
// pointers.
107+
return _swift_abi_ObjCReservedBitsMask != 0;
108+
}
109+
100110
#if defined(__APPLE__) && defined(__arm64__)
101111

102112
#define CONTINUE_WITH_COPY(METADATA, READER, ADDR_OFFSET, DEST, SRC) \
@@ -281,9 +291,12 @@ static void weakDestroy(const Metadata *metadata, LayoutStringReader1 &reader,
281291
static void unknownDestroy(const Metadata *metadata,
282292
LayoutStringReader1 &reader, uintptr_t &addrOffset,
283293
uint8_t *addr) {
284-
void *object = *(void**)(addr + addrOffset);
294+
uintptr_t object = *(uintptr_t *)(addr + addrOffset);
285295
addrOffset += sizeof(void*);
286-
swift_unknownObjectRelease(object);
296+
if (!platformSupportsTaggedPointers()) {
297+
object &= ~_swift_abi_SwiftSpareBitsMask;
298+
}
299+
swift_unknownObjectRelease((void *)object);
287300
}
288301

289302
static void unknownUnownedDestroy(const Metadata *metadata,
@@ -769,9 +782,10 @@ multiPayloadEnumGeneric(const Metadata *metadata, LayoutStringReader1 &reader,
769782
static void blockDestroy(const Metadata *metadata, LayoutStringReader1 &reader,
770783
uintptr_t &addrOffset, uint8_t *addr) {
771784
#if SWIFT_OBJC_INTEROP
772-
void* object = (void *)(addr + addrOffset);
785+
uintptr_t object = *(uintptr_t *)(addr + addrOffset);
786+
object &= ~_swift_abi_SwiftSpareBitsMask;
773787
addrOffset += sizeof(void*);
774-
_Block_release(object);
788+
_Block_release((void *)object);
775789
#else
776790
swift_unreachable("Blocks are not available on this platform");
777791
#endif
@@ -783,6 +797,11 @@ static void objcStrongDestroy(const Metadata *metadata,
783797
#if SWIFT_OBJC_INTEROP
784798
uintptr_t object = *(uintptr_t *)(addr + addrOffset);
785799
addrOffset += sizeof(objc_object*);
800+
801+
if (!platformSupportsTaggedPointers()) {
802+
object &= ~_swift_abi_SwiftSpareBitsMask;
803+
}
804+
786805
objc_release((objc_object *)object);
787806
#else
788807
swift_unreachable("ObjC interop is not available on this platform");
@@ -959,10 +978,13 @@ static void weakCopyInit(const Metadata *metadata, LayoutStringReader1 &reader,
959978
static void unknownRetain(const Metadata *metadata, LayoutStringReader1 &reader,
960979
uintptr_t &addrOffset, uint8_t *dest, uint8_t *src) {
961980
uintptr_t _addrOffset = addrOffset;
962-
void *object = *(void **)(src + _addrOffset);
981+
uintptr_t object = *(uintptr_t *)(src + _addrOffset);
963982
memcpy(dest + _addrOffset, &object, sizeof(void*));
964983
addrOffset = _addrOffset + sizeof(void *);
965-
swift_unknownObjectRetain(object);
984+
if (!platformSupportsTaggedPointers()) {
985+
object &= ~_swift_abi_SwiftSpareBitsMask;
986+
}
987+
swift_unknownObjectRetain((void *)object);
966988
}
967989

968990
static void unknownUnownedCopyInit(const Metadata *metadata,
@@ -1000,9 +1022,11 @@ static void blockCopy(const Metadata *metadata, LayoutStringReader1 &reader,
10001022
uintptr_t &addrOffset, uint8_t *dest, uint8_t *src) {
10011023
#if SWIFT_OBJC_INTEROP
10021024
uintptr_t _addrOffset = addrOffset;
1003-
auto *copy = _Block_copy(*(void**)(src + _addrOffset));
1004-
memcpy(dest + _addrOffset, &copy, sizeof(void*));
1025+
uintptr_t object = *(uintptr_t *)(src + _addrOffset);
1026+
memcpy(dest + _addrOffset, &object, sizeof(void *));
10051027
addrOffset = _addrOffset + sizeof(void*);
1028+
object &= ~_swift_abi_SwiftSpareBitsMask;
1029+
_Block_copy((void *)object);
10061030
#else
10071031
swift_unreachable("Blocks are not available on this platform");
10081032
#endif
@@ -1016,6 +1040,11 @@ static void objcStrongRetain(const Metadata *metadata,
10161040
uintptr_t object = *(uintptr_t *)(src + _addrOffset);
10171041
memcpy(dest + _addrOffset, &object, sizeof(objc_object *));
10181042
addrOffset = _addrOffset + sizeof(objc_object *);
1043+
1044+
if (!platformSupportsTaggedPointers()) {
1045+
object &= ~_swift_abi_SwiftSpareBitsMask;
1046+
}
1047+
10191048
objc_retain((objc_object *)object);
10201049
#else
10211050
swift_unreachable("ObjC interop is not available on this platform");
@@ -1368,12 +1397,16 @@ static void unknownAssignWithCopy(const Metadata *metadata,
13681397
uintptr_t &addrOffset, uint8_t *dest,
13691398
uint8_t *src) {
13701399
uintptr_t _addrOffset = addrOffset;
1371-
void *destObject = *(void **)(dest + _addrOffset);
1372-
void *srcObject = *(void **)(src + _addrOffset);
1400+
uintptr_t destObject = *(uintptr_t *)(dest + _addrOffset);
1401+
uintptr_t srcObject = *(uintptr_t *)(src + _addrOffset);
13731402
memcpy(dest + _addrOffset, &srcObject, sizeof(void *));
13741403
addrOffset = _addrOffset + sizeof(void *);
1375-
swift_unknownObjectRelease(destObject);
1376-
swift_unknownObjectRetain(srcObject);
1404+
if (!platformSupportsTaggedPointers()) {
1405+
destObject &= ~_swift_abi_SwiftSpareBitsMask;
1406+
srcObject &= ~_swift_abi_SwiftSpareBitsMask;
1407+
}
1408+
swift_unknownObjectRelease((void *)destObject);
1409+
swift_unknownObjectRetain((void *)srcObject);
13771410
}
13781411

13791412
static void bridgeAssignWithCopy(const Metadata *metadata,
@@ -1431,10 +1464,14 @@ static void blockAssignWithCopy(const Metadata *metadata,
14311464
uint8_t *src) {
14321465
#if SWIFT_OBJC_INTEROP
14331466
uintptr_t _addrOffset = addrOffset;
1434-
_Block_release(*(void **)(dest + _addrOffset));
1435-
auto *copy = _Block_copy(*(void **)(src + _addrOffset));
1436-
memcpy(dest + _addrOffset, &copy, sizeof(void*));
1467+
uintptr_t destObject = *(uintptr_t *)(dest + _addrOffset);
1468+
uintptr_t srcObject = *(uintptr_t *)(src + _addrOffset);
1469+
memcpy(dest + _addrOffset, &srcObject, sizeof(void *));
14371470
addrOffset = _addrOffset + sizeof(void*);
1471+
destObject &= ~_swift_abi_SwiftSpareBitsMask;
1472+
srcObject &= ~_swift_abi_SwiftSpareBitsMask;
1473+
_Block_release((void *)destObject);
1474+
_Block_copy((void *)srcObject);
14381475
#else
14391476
swift_unreachable("Blocks are not available on this platform");
14401477
#endif
@@ -1452,6 +1489,11 @@ static void objcStrongAssignWithCopy(const Metadata *metadata,
14521489
memcpy(dest + _addrOffset, &srcObject, sizeof(objc_object*));
14531490
addrOffset = _addrOffset + sizeof(objc_object*);
14541491

1492+
if (!platformSupportsTaggedPointers()) {
1493+
destObject &= ~_swift_abi_SwiftSpareBitsMask;
1494+
srcObject &= ~_swift_abi_SwiftSpareBitsMask;
1495+
}
1496+
14551497
objc_release((objc_object *)destObject);
14561498
objc_retain((objc_object *)srcObject);
14571499
#else

test/Interpreter/Inputs/layout_string_witnesses_types.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,12 @@ public enum ErrorWrapper {
667667
case y(Error)
668668
}
669669

670+
public enum MultiPayloadAnyObject {
671+
case x(AnyObject)
672+
case y(AnyObject)
673+
case z(AnyObject)
674+
}
675+
670676
@inline(never)
671677
public func consume<T>(_ x: T.Type) {
672678
withExtendedLifetime(x) {}

test/Interpreter/layout_string_witnesses_objc.swift

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,60 @@ func testMultiPayloadNativeSwiftObjC() {
133133
}
134134

135135
testMultiPayloadNativeSwiftObjC()
136+
137+
public enum MultiPayloadBlock {
138+
#if _pointerBitWidth(_32)
139+
public typealias PaddingPayload = (Int16, Int8, Bool)
140+
#else
141+
public typealias PaddingPayload = (Int32, Int16, Int8, Bool)
142+
#endif
143+
144+
case x(PaddingPayload)
145+
case y(@convention(block) () -> Void)
146+
}
147+
148+
func testMultiPayloadBlock() {
149+
let ptr = UnsafeMutablePointer<MultiPayloadBlock>.allocate(capacity: 1)
150+
151+
// initWithCopy
152+
do {
153+
let instance = SimpleClass(x: 0)
154+
let x = MultiPayloadBlock.y({ print(instance) })
155+
testInit(ptr, to: x)
156+
}
157+
158+
// assignWithTake
159+
do {
160+
let instance = SimpleClass(x: 1)
161+
let y = MultiPayloadBlock.y({ print(instance) })
162+
163+
// CHECK-NEXT: Before deinit
164+
print("Before deinit")
165+
166+
// CHECK-NEXT: SimpleClass deinitialized!
167+
testAssign(ptr, from: y)
168+
}
169+
170+
// assignWithCopy
171+
do {
172+
let instance = SimpleClass(x: 2)
173+
var z = MultiPayloadBlock.y({ print(instance) })
174+
175+
// CHECK-NEXT: Before deinit
176+
print("Before deinit")
177+
178+
// CHECK-NEXT: SimpleClass deinitialized!
179+
testAssignCopy(ptr, from: &z)
180+
}
181+
182+
// CHECK-NEXT: Before deinit
183+
print("Before deinit")
184+
185+
// destroy
186+
// CHECK-NEXT: SimpleClass deinitialized!
187+
testDestroy(ptr)
188+
189+
ptr.deallocate()
190+
}
191+
192+
testMultiPayloadBlock()

test/Interpreter/layout_string_witnesses_static.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,49 @@ func testMultiPayloadOneExtraTagValue() {
13631363

13641364
testMultiPayloadOneExtraTagValue()
13651365

1366+
func testMultiPayloadAnyObject() {
1367+
let ptr = UnsafeMutablePointer<MultiPayloadAnyObject>.allocate(capacity: 1)
1368+
1369+
// initWithCopy
1370+
do {
1371+
let x = MultiPayloadAnyObject.y(SimpleClass(x: 0))
1372+
testInit(ptr, to: x)
1373+
}
1374+
1375+
// assignWithTake
1376+
do {
1377+
let y = MultiPayloadAnyObject.z(SimpleClass(x: 1))
1378+
1379+
// CHECK-NEXT: Before deinit
1380+
print("Before deinit")
1381+
1382+
// CHECK-NEXT: SimpleClass deinitialized!
1383+
testAssign(ptr, from: y)
1384+
}
1385+
1386+
// assignWithCopy
1387+
do {
1388+
var z = MultiPayloadAnyObject.z(SimpleClass(x: 2))
1389+
1390+
// CHECK-NEXT: Before deinit
1391+
print("Before deinit")
1392+
1393+
// CHECK-NEXT: SimpleClass deinitialized!
1394+
testAssignCopy(ptr, from: &z)
1395+
}
1396+
1397+
// CHECK-NEXT: Before deinit
1398+
print("Before deinit")
1399+
1400+
// destroy
1401+
// CHECK-NEXT: SimpleClass deinitialized!
1402+
testDestroy(ptr)
1403+
1404+
ptr.deallocate()
1405+
}
1406+
1407+
testMultiPayloadAnyObject()
1408+
13661409
#if os(macOS)
13671410
func testObjc() {
13681411
let ptr = UnsafeMutablePointer<ObjcWrapper>.allocate(capacity: 1)

0 commit comments

Comments
 (0)