Skip to content

Commit 24367fa

Browse files
committed
Runtime: Have native refcounting entry points ignore negative pointer values on x86-64 and arm64.
The high half of the address space is used by the kernel in these architectures, and it would be useful for us to be able to pack small values into places the ABI otherwise requires a refcountable pointer, such as closures and maybe refcounted existentials.
1 parent a562c0e commit 24367fa

File tree

3 files changed

+45
-21
lines changed

3 files changed

+45
-21
lines changed

lib/IRGen/SwiftTargetInfo.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ static void configureARM64(IRGenModule &IGM, const llvm::Triple &triple,
5454

5555
// arm64 requires ISA-masking.
5656
target.ObjCUseISAMask = true;
57+
58+
// arm64 tops out at 56 effective bits of address space and reserves the high
59+
// half for the kernel.
60+
target.SwiftRetainIgnoresNegativeValues = true;
5761
}
5862

5963
/// Configures target-specific information for x86-64 platforms.
@@ -75,6 +79,10 @@ static void configureX86_64(IRGenModule &IGM, const llvm::Triple &triple,
7579

7680
// x86-64 requires ISA-masking.
7781
target.ObjCUseISAMask = true;
82+
83+
// x86-64 only has 48 effective bits of address space and reserves the high
84+
// half for the kernel.
85+
target.SwiftRetainIgnoresNegativeValues = true;
7886
}
7987

8088
/// Configures target-specific information for 32-bit x86 platforms.

lib/IRGen/SwiftTargetInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ class SwiftTargetInfo {
9595
/// The value stored in a Builtin.once predicate to indicate that an
9696
/// initialization has already happened, if known.
9797
Optional<int64_t> OnceDonePredicateValue = None;
98+
99+
/// True if `swift_retain` and `swift_release` are no-ops when passed
100+
/// "negative" pointer values.
101+
bool SwiftRetainIgnoresNegativeValues = false;
98102
};
99103

100104
}

stdlib/public/runtime/HeapObject.cpp

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@
4343

4444
using namespace swift;
4545

46+
/// Returns true if the pointer passed to a native retain or release is valid.
47+
/// If false, the operation should immediately return.
48+
static inline bool isValidPointerForNativeRetain(const void *p) {
49+
#if defined(__x86_64__) || defined(__arm64__)
50+
// On these platforms, the upper half of address space is reserved for the
51+
// kernel, so we can assume that pointer values in this range are invalid.
52+
return (intptr_t)p > 0;
53+
#else
54+
return p != nullptr;
55+
#endif
56+
}
57+
4658
HeapObject *swift::swift_allocObject(HeapMetadata const *metadata,
4759
size_t requiredSize,
4860
size_t requiredAlignmentMask)
@@ -185,7 +197,7 @@ OpaqueValue *swift::swift_projectBox(HeapObject *o) {
185197
// for boxes of empty type. The address of an empty value is always undefined,
186198
// so we can just return nil back in this case.
187199
if (!o)
188-
return reinterpret_cast<OpaqueValue*>(o);
200+
return nullptr;
189201
auto metadata = static_cast<const GenericBoxHeapMetadata *>(o->metadata);
190202
return metadata->project(o);
191203
}
@@ -206,7 +218,7 @@ void swift::swift_nonatomic_retain(HeapObject *object) {
206218
SWIFT_RT_ENTRY_IMPL_VISIBILITY
207219
extern "C"
208220
void SWIFT_RT_ENTRY_IMPL(swift_nonatomic_retain)(HeapObject *object) {
209-
if (object)
221+
if (isValidPointerForNativeRetain(object))
210222
object->refCounts.incrementNonAtomic(1);
211223
}
212224

@@ -217,15 +229,15 @@ void swift::swift_nonatomic_release(HeapObject *object) {
217229
SWIFT_RT_ENTRY_IMPL_VISIBILITY
218230
extern "C"
219231
void SWIFT_RT_ENTRY_IMPL(swift_nonatomic_release)(HeapObject *object) {
220-
if (object)
232+
if (isValidPointerForNativeRetain(object))
221233
object->refCounts.decrementAndMaybeDeinitNonAtomic(1);
222234
}
223235

224236
SWIFT_RT_ENTRY_IMPL_VISIBILITY
225237
extern "C"
226238
void SWIFT_RT_ENTRY_IMPL(swift_retain)(HeapObject *object)
227239
SWIFT_CC(RegisterPreservingCC_IMPL) {
228-
if (object)
240+
if (isValidPointerForNativeRetain(object))
229241
object->refCounts.increment(1);
230242
}
231243

@@ -238,7 +250,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY
238250
extern "C"
239251
void SWIFT_RT_ENTRY_IMPL(swift_retain_n)(HeapObject *object, uint32_t n)
240252
SWIFT_CC(RegisterPreservingCC_IMPL) {
241-
if (object)
253+
if (isValidPointerForNativeRetain(object))
242254
object->refCounts.increment(n);
243255
}
244256

@@ -251,7 +263,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY
251263
extern "C"
252264
void SWIFT_RT_ENTRY_IMPL(swift_nonatomic_retain_n)(HeapObject *object, uint32_t n)
253265
SWIFT_CC(RegisterPreservingCC_IMPL) {
254-
if (object)
266+
if (isValidPointerForNativeRetain(object))
255267
object->refCounts.incrementNonAtomic(n);
256268
}
257269

@@ -264,7 +276,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY
264276
extern "C"
265277
void SWIFT_RT_ENTRY_IMPL(swift_release)(HeapObject *object)
266278
SWIFT_CC(RegisterPreservingCC_IMPL) {
267-
if (object)
279+
if (isValidPointerForNativeRetain(object))
268280
object->refCounts.decrementAndMaybeDeinit(1);
269281
}
270282

@@ -277,7 +289,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY
277289
extern "C"
278290
void SWIFT_RT_ENTRY_IMPL(swift_release_n)(HeapObject *object, uint32_t n)
279291
SWIFT_CC(RegisterPreservingCC_IMPL) {
280-
if (object)
292+
if (isValidPointerForNativeRetain(object))
281293
object->refCounts.decrementAndMaybeDeinit(n);
282294
}
283295

@@ -294,7 +306,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY
294306
extern "C"
295307
void SWIFT_RT_ENTRY_IMPL(swift_nonatomic_release_n)(HeapObject *object, uint32_t n)
296308
SWIFT_CC(RegisterPreservingCC_IMPL) {
297-
if (object)
309+
if (isValidPointerForNativeRetain(object))
298310
object->refCounts.decrementAndMaybeDeinitNonAtomic(n);
299311
}
300312

@@ -308,15 +320,15 @@ size_t swift::swift_unownedRetainCount(HeapObject *object) {
308320

309321
void swift::swift_unownedRetain(HeapObject *object)
310322
SWIFT_CC(RegisterPreservingCC_IMPL) {
311-
if (!object)
323+
if (!isValidPointerForNativeRetain(object))
312324
return;
313325

314326
object->refCounts.incrementUnowned(1);
315327
}
316328

317329
void swift::swift_unownedRelease(HeapObject *object)
318330
SWIFT_CC(RegisterPreservingCC_IMPL) {
319-
if (!object)
331+
if (!isValidPointerForNativeRetain(object))
320332
return;
321333

322334
// Only class objects can be unowned-retained and unowned-released.
@@ -334,15 +346,15 @@ void swift::swift_unownedRelease(HeapObject *object)
334346

335347
void swift::swift_unownedRetain_n(HeapObject *object, int n)
336348
SWIFT_CC(RegisterPreservingCC_IMPL) {
337-
if (!object)
349+
if (!isValidPointerForNativeRetain(object))
338350
return;
339351

340352
object->refCounts.incrementUnowned(n);
341353
}
342354

343355
void swift::swift_unownedRelease_n(HeapObject *object, int n)
344356
SWIFT_CC(RegisterPreservingCC_IMPL) {
345-
if (!object)
357+
if (!isValidPointerForNativeRetain(object))
346358
return;
347359

348360
// Only class objects can be unowned-retained and unowned-released.
@@ -359,7 +371,7 @@ void swift::swift_unownedRelease_n(HeapObject *object, int n)
359371

360372
HeapObject *swift::swift_tryPin(HeapObject *object)
361373
SWIFT_CC(RegisterPreservingCC_IMPL) {
362-
assert(object);
374+
assert(isValidPointerForNativeRetain(object));
363375

364376
// Try to set the flag. If this succeeds, the caller will be
365377
// responsible for clearing it.
@@ -373,7 +385,7 @@ HeapObject *swift::swift_tryPin(HeapObject *object)
373385

374386
void swift::swift_unpin(HeapObject *object)
375387
SWIFT_CC(RegisterPreservingCC_IMPL) {
376-
if (object)
388+
if (isValidPointerForNativeRetain(object))
377389
object->refCounts.decrementAndUnpinAndMaybeDeinit();
378390
}
379391

@@ -398,15 +410,15 @@ HeapObject *swift::swift_nonatomic_tryPin(HeapObject *object)
398410

399411
void swift::swift_nonatomic_unpin(HeapObject *object)
400412
SWIFT_CC(RegisterPreservingCC_IMPL) {
401-
if (object)
413+
if (isValidPointerForNativeRetain(object))
402414
object->refCounts.decrementAndUnpinAndMaybeDeinitNonAtomic();
403415
}
404416

405417
SWIFT_RT_ENTRY_IMPL_VISIBILITY
406418
extern "C"
407419
HeapObject *SWIFT_RT_ENTRY_IMPL(swift_tryRetain)(HeapObject *object)
408420
SWIFT_CC(RegisterPreservingCC_IMPL) {
409-
if (!object)
421+
if (!isValidPointerForNativeRetain(object))
410422
return nullptr;
411423

412424
if (object->refCounts.tryIncrement()) return object;
@@ -421,14 +433,14 @@ bool swift_isDeallocating(HeapObject *object) {
421433
SWIFT_RT_ENTRY_IMPL_VISIBILITY
422434
extern "C"
423435
bool SWIFT_RT_ENTRY_IMPL(swift_isDeallocating)(HeapObject *object) {
424-
if (!object)
436+
if (!isValidPointerForNativeRetain(object))
425437
return false;
426438
return object->refCounts.isDeiniting();
427439
}
428440

429441
void swift::swift_unownedRetainStrong(HeapObject *object)
430442
SWIFT_CC(RegisterPreservingCC_IMPL) {
431-
if (!object)
443+
if (!isValidPointerForNativeRetain(object))
432444
return;
433445
assert(object->refCounts.getUnownedCount() &&
434446
"object is not currently unowned-retained");
@@ -439,7 +451,7 @@ void swift::swift_unownedRetainStrong(HeapObject *object)
439451

440452
void swift::swift_unownedRetainStrongAndRelease(HeapObject *object)
441453
SWIFT_CC(RegisterPreservingCC_IMPL) {
442-
if (!object)
454+
if (!isValidPointerForNativeRetain(object))
443455
return;
444456
assert(object->refCounts.getUnownedCount() &&
445457
"object is not currently unowned-retained");
@@ -454,7 +466,7 @@ void swift::swift_unownedRetainStrongAndRelease(HeapObject *object)
454466
}
455467

456468
void swift::swift_unownedCheck(HeapObject *object) {
457-
if (!object) return;
469+
if (!isValidPointerForNativeRetain(object)) return;
458470
assert(object->refCounts.getUnownedCount() &&
459471
"object is not currently unowned-retained");
460472

0 commit comments

Comments
 (0)