Skip to content

Commit 4ea0c9b

Browse files
authored
Merge pull request #77431 from drexin/wip-138487964
[IRGen+Runtime] Fix tag bit mask handling for objc, unknown objects a…
2 parents 321f9aa + 3c7b556 commit 4ea0c9b

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)