mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This is a type that has ownership of a reference while allowing access to the
spare bits inside the pointer, but which can also safely hold an ObjC tagged pointer
reference (with no spare bits of course). It additionally blesses one
Foundation-coordinated bit with the meaning of "has swift refcounting" in order
to get a faster short-circuit to native refcounting. It supports the following
builtin operations:
- Builtin.castToBridgeObject<T>(ref: T, bits: Builtin.Word) ->
Builtin.BridgeObject
Creates a BridgeObject that contains the bitwise-OR of the bit patterns of
"ref" and "bits". It is the user's responsibility to ensure "bits" doesn't
interfere with the reference identity of the resulting value. In other words,
it is undefined behavior unless:
castReferenceFromBridgeObject(castToBridgeObject(ref, bits)) === ref
This means "bits" must be zero if "ref" is a tagged pointer. If "ref" is a real
object pointer, "bits" must not have any non-spare bits set (unless they're
already set in the pointer value). The native discriminator bit may only be set
if the object is Swift-refcounted.
- Builtin.castReferenceFromBridgeObject<T>(bo: Builtin.BridgeObject) -> T
Extracts the reference from a BridgeObject.
- Builtin.castBitPatternFromBridgeObject(bo: Builtin.BridgeObject) -> Builtin.Word
Presents the bit pattern of a BridgeObject as a Word.
BridgeObject's bits are set up as follows on the various platforms:
i386, armv7:
No ObjC tagged pointers
Swift native refcounting flag bit: 0x0000_0001
Other available spare bits: 0x0000_0002
x86_64:
Reserved for ObjC tagged pointers: 0x8000_0000_0000_0001
Swift native refcounting flag bit: 0x0000_0000_0000_0002
Other available spare bits: 0x7F00_0000_0000_0004
arm64:
Reserved for ObjC tagged pointers: 0x8000_0000_0000_0000
Swift native refcounting flag bit: 0x4000_0000_0000_0000
Other available spare bits: 0x3F00_0000_0000_0007
TODO: BridgeObject doesn't present any extra inhabitants. It ought to at least provide null as an extra inhabitant for Optional.
Swift SVN r22880
530 lines
16 KiB
C++
530 lines
16 KiB
C++
//===--- Alloc.h - Swift Language Allocation ABI ---------------*- C++ -*--===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Swift Allocation ABI
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_RUNTIME_ALLOC_H
|
|
#define SWIFT_RUNTIME_ALLOC_H
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include "swift/Runtime/Config.h"
|
|
#include "swift/Runtime/FastEntryPoints.h"
|
|
|
|
// Bring in the definition of HeapObject
|
|
#include "../../../stdlib/shims/HeapObject.h"
|
|
|
|
namespace swift {
|
|
|
|
struct Metadata;
|
|
struct HeapMetadata;
|
|
struct OpaqueValue;
|
|
|
|
/// Allocates a new heap object. The returned memory is
|
|
/// uninitialized outside of the heap-object header. The object
|
|
/// has an initial retain count of 1, and its metadata is set to
|
|
/// the given value.
|
|
///
|
|
/// At some point "soon after return", it will become an
|
|
/// invariant that metadata->getSize(returnValue) will equal
|
|
/// requiredSize.
|
|
///
|
|
/// Either aborts or throws a swift exception if the allocation fails.
|
|
///
|
|
/// \param requiredSize - the required size of the allocation,
|
|
/// including the header
|
|
/// \param requiredAlignmentMask - the required alignment of the allocation;
|
|
/// always one less than a power of 2 that's at least alignof(void*)
|
|
/// \return never null
|
|
///
|
|
/// POSSIBILITIES: The argument order is fair game. It may be useful
|
|
/// to have a variant which guarantees zero-initialized memory.
|
|
extern "C" HeapObject *swift_allocObject(HeapMetadata const *metadata,
|
|
size_t requiredSize,
|
|
size_t requiredAlignmentMask);
|
|
|
|
/// The structure returned by swift_allocPOD and swift_allocBox.
|
|
struct BoxPair {
|
|
/// The pointer to the heap object.
|
|
HeapObject *heapObject;
|
|
|
|
/// The pointer to the value inside the box.
|
|
OpaqueValue *value;
|
|
|
|
// FIXME: rdar://16257592 arm codegen does't call swift_allocBox correctly.
|
|
// Structs are returned indirectly on these platforms, but we want to return
|
|
// in registers, so cram the result into an unsigned long long.
|
|
// Use an enum class with implicit conversions so we don't dirty C callers
|
|
// too much.
|
|
#if __arm__ || __i386__
|
|
enum class Return : unsigned long long {};
|
|
|
|
operator Return() const {
|
|
union {
|
|
BoxPair value;
|
|
Return mangled;
|
|
} reinterpret = {*this};
|
|
|
|
return reinterpret.mangled;
|
|
}
|
|
|
|
BoxPair() = default;
|
|
BoxPair(HeapObject *h, OpaqueValue *v)
|
|
: heapObject(h), value(v) {}
|
|
|
|
/*implicit*/ BoxPair(Return r) {
|
|
union {
|
|
Return mangled;
|
|
BoxPair value;
|
|
} reinterpret = {r};
|
|
|
|
*this = reinterpret.value;
|
|
}
|
|
#else
|
|
using Return = BoxPair;
|
|
#endif
|
|
};
|
|
|
|
/// Allocates a heap object with POD value semantics. The returned memory is
|
|
/// uninitialized outside of the heap object header. The object has an
|
|
/// initial retain count of 1, and its metadata is set to a predefined
|
|
/// POD heap metadata for which destruction is a no-op.
|
|
///
|
|
/// \param dataSize The size of the data area for the allocation.
|
|
/// Excludes the heap metadata header.
|
|
/// \param dataAlignmentMask The alignment of the data area.
|
|
///
|
|
/// \returns a BoxPair in which the heapObject field points to the newly-created
|
|
/// HeapObject and the value field points to the data area inside the
|
|
/// allocation. The value pointer will have the alignment specified
|
|
/// by the dataAlignmentMask and point to dataSize bytes of memory.
|
|
extern "C" BoxPair::Return
|
|
swift_allocPOD(size_t dataSize, size_t dataAlignmentMask);
|
|
|
|
/// Deallocates a heap object known to have been allocated by swift_allocPOD and
|
|
/// to have no remaining owners.
|
|
extern "C" void swift_deallocPOD(HeapObject *obj);
|
|
|
|
/// Allocates a heap object that can contain a value of the given type.
|
|
/// Returns a Box structure containing a HeapObject* pointer to the
|
|
/// allocated object, and a pointer to the value inside the heap object.
|
|
/// The value pointer points to an uninitialized buffer of size and alignment
|
|
/// appropriate to store a value of the given type.
|
|
/// The heap object has an initial retain count of 1, and its metadata is set
|
|
/// such that destroying the heap object destroys the contained value.
|
|
extern "C" BoxPair::Return swift_allocBox(Metadata const *type);
|
|
|
|
// Allocate plain old memory. This is the generalized entry point
|
|
// Never returns nil. The returned memory is uninitialized.
|
|
//
|
|
// An "alignment mask" is just the alignment (a power of 2) minus 1.
|
|
extern "C" void *swift_slowAlloc(size_t bytes, size_t alignMask);
|
|
|
|
// If the caller cannot promise to zero the object during destruction,
|
|
// then call these corresponding APIs:
|
|
extern "C" void swift_slowDealloc(void *ptr, size_t bytes, size_t alignMask);
|
|
|
|
/// Atomically increments the retain count of an object.
|
|
///
|
|
/// \param object - may be null, in which case this is a no-op
|
|
/// \return its argument value exactly
|
|
///
|
|
/// POSSIBILITIES: We may end up wanting a bunch of different variants:
|
|
/// - the general version which correctly handles null values, swift
|
|
/// objects, and ObjC objects
|
|
/// - a variant that assumes that its operand is a swift object
|
|
/// - a variant that can safely use non-atomic operations
|
|
/// - maybe a variant that can assume a non-null object
|
|
/// It may also prove worthwhile to have this use a custom CC
|
|
/// which preserves a larger set of registers.
|
|
extern "C" HeapObject *swift_retain(HeapObject *object);
|
|
extern "C" void swift_retain_noresult(HeapObject *object);
|
|
|
|
static inline HeapObject *_swift_retain_inlined(HeapObject *object) {
|
|
if (object) {
|
|
__sync_fetch_and_add(&object->refCount, RC_INTERVAL);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
/// Atomically increments the reference count of an object, unless it has
|
|
/// already been destroyed. Returns nil if the object is dead.
|
|
extern "C" HeapObject *swift_tryRetain(HeapObject *object);
|
|
|
|
/// Atomically decrements the retain count of an object. If the
|
|
/// retain count reaches zero, the object is destroyed as follows:
|
|
///
|
|
/// size_t allocSize = object->metadata->destroy(object);
|
|
/// if (allocSize) swift_deallocObject(object, allocSize);
|
|
///
|
|
/// \param object - may be null, in which case this is a no-op
|
|
///
|
|
/// POSSIBILITIES: We may end up wanting a bunch of different variants:
|
|
/// - the general version which correctly handles null values, swift
|
|
/// objects, and ObjC objects
|
|
/// - a variant that assumes that its operand is a swift object
|
|
/// - a variant that can safely use non-atomic operations
|
|
/// - maybe a variant that can assume a non-null object
|
|
/// It's unlikely that a custom CC would be beneficial here.
|
|
extern "C" void swift_release(HeapObject *object);
|
|
|
|
/// ObjC compatibility. Never call this.
|
|
extern "C" size_t swift_retainCount(HeapObject *object);
|
|
|
|
/// Deallocate the given memory; it was returned by swift_allocObject
|
|
/// but is otherwise in an unknown state.
|
|
///
|
|
/// \param object - never null
|
|
/// \param allocatedSize - the allocated size of the object from the
|
|
/// program's perspective, i.e. the value
|
|
/// \param allocatedAlignMask - the alignment requirement that was passed
|
|
/// to allocObject
|
|
///
|
|
/// POSSIBILITIES: It may be useful to have a variant which
|
|
/// requires the object to have been fully zeroed from offsets
|
|
/// sizeof(SwiftHeapObject) to allocatedSize.
|
|
extern "C" void swift_deallocObject(HeapObject *object, size_t allocatedSize,
|
|
size_t allocatedAlignMask);
|
|
|
|
/// Deallocate the given memory allocated by swift_allocBox; it was returned
|
|
/// by swift_allocBox but is otherwise in an unknown state. The given Metadata
|
|
/// pointer must be the same metadata pointer that was passed to swift_allocBox
|
|
/// when the memory was allocated.
|
|
extern "C" void swift_deallocBox(HeapObject *object, Metadata const *type);
|
|
|
|
/// RAII object that wraps a Swift heap object and releases it upon
|
|
/// destruction.
|
|
class SwiftRAII {
|
|
HeapObject *object;
|
|
|
|
public:
|
|
SwiftRAII(HeapObject *obj, bool AlreadyRetained) : object(obj) {
|
|
if (!AlreadyRetained)
|
|
swift_retain(obj);
|
|
}
|
|
|
|
~SwiftRAII() {
|
|
if (object)
|
|
swift_release(object);
|
|
}
|
|
|
|
SwiftRAII(const SwiftRAII &other) : object(swift_retain(*other)) {
|
|
;
|
|
}
|
|
SwiftRAII(SwiftRAII &&other) : object(*other) {
|
|
other.object = nullptr;
|
|
}
|
|
SwiftRAII &operator=(const SwiftRAII &other) {
|
|
if (object)
|
|
swift_release(object);
|
|
object = swift_retain(*other);
|
|
return *this;
|
|
}
|
|
SwiftRAII &operator=(SwiftRAII &&other) {
|
|
if (object)
|
|
swift_release(object);
|
|
object = *other;
|
|
other.object = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
HeapObject *operator *() const { return object; }
|
|
};
|
|
|
|
/// Increment the weak retain count.
|
|
extern "C" void swift_weakRetain(HeapObject *value);
|
|
|
|
/// Decrement the weak retain count.
|
|
extern "C" void swift_weakRelease(HeapObject *value);
|
|
|
|
/// Increment the strong retain count of an object which may have been
|
|
/// deallocated.
|
|
extern "C" void swift_retainUnowned(HeapObject *value);
|
|
|
|
/// A weak reference value object. This is ABI.
|
|
struct WeakReference {
|
|
HeapObject *Value;
|
|
};
|
|
|
|
/// Initialize a weak reference.
|
|
///
|
|
/// \param ref - never null
|
|
/// \param value - can be null
|
|
extern "C" void swift_weakInit(WeakReference *ref, HeapObject *value);
|
|
|
|
/// Assign a new value to a weak reference.
|
|
///
|
|
/// \param ref - never null
|
|
/// \param value - can be null
|
|
extern "C" void swift_weakAssign(WeakReference *ref, HeapObject *value);
|
|
|
|
/// Load a value from a weak reference. If the current value is a
|
|
/// non-null object that has begun deallocation, returns null;
|
|
/// otherwise, retains the object before returning.
|
|
///
|
|
/// \param ref - never null
|
|
/// \return can be null
|
|
extern "C" HeapObject *swift_weakLoadStrong(WeakReference *ref);
|
|
|
|
/// Load a value from a weak reference as if by swift_weakLoadStrong,
|
|
/// but leaving the reference in an uninitialized state.
|
|
///
|
|
/// \param ref - never null
|
|
/// \return can be null
|
|
extern "C" HeapObject *swift_weakTakeStrong(WeakReference *ref);
|
|
|
|
/// Destroy a weak reference.
|
|
///
|
|
/// \param ref - never null, but can refer to a null object
|
|
extern "C" void swift_weakDestroy(WeakReference *ref);
|
|
|
|
/// Copy initialize a weak reference.
|
|
///
|
|
/// \param dest - never null, but can refer to a null object
|
|
/// \param src - never null, but can refer to a null object
|
|
extern "C" void swift_weakCopyInit(WeakReference *dest, WeakReference *src);
|
|
|
|
/// Take initialize a weak reference.
|
|
///
|
|
/// \param dest - never null, but can refer to a null object
|
|
/// \param src - never null, but can refer to a null object
|
|
extern "C" void swift_weakTakeInit(WeakReference *dest, WeakReference *src);
|
|
|
|
/// Copy assign a weak reference.
|
|
///
|
|
/// \param dest - never null, but can refer to a null object
|
|
/// \param src - never null, but can refer to a null object
|
|
extern "C" void swift_weakCopyAssign(WeakReference *dest, WeakReference *src);
|
|
|
|
/// Take assign a weak reference.
|
|
///
|
|
/// \param dest - never null, but can refer to a null object
|
|
/// \param src - never null, but can refer to a null object
|
|
extern "C" void swift_weakTakeAssign(WeakReference *dest, WeakReference *src);
|
|
|
|
extern "C" void *swift_bridgeObjectRetain(void *value);
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Increment the strong retain count of an object which might not be a native
|
|
/// Swift object.
|
|
extern "C" void *swift_unknownRetain(void *value);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownRetain(void *value) {
|
|
swift_retain(static_cast<HeapObject *>(value));
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
extern "C" void swift_bridgeObjectRelease(void *value);
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Decrement the strong retain count of an object which might not be a native
|
|
/// Swift object.
|
|
extern "C" void swift_unknownRelease(void *value);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownRelease(void *value) {
|
|
swift_release(static_cast<HeapObject *>(value));
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Increment the strong retain count of an object which may have been
|
|
/// deallocated and which might not be a native Swift object.
|
|
extern "C" void swift_unknownRetainUnowned(void *value);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownRetainUnowned(void *value) {
|
|
swift_retainUnowned(static_cast<HeapObject *>(value));
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Increment the weak-reference count of an object that might not be
|
|
/// a native Swift object.
|
|
extern "C" void swift_unknownWeakRetain(void *value);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownWeakRetain(void *value) {
|
|
swift_weakRetain(static_cast<HeapObject *>(value));
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Decrement the weak-reference count of an object that might not be
|
|
/// a native Swift object.
|
|
extern "C" void swift_unknownWeakRelease(void *value);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownWeakRelease(void *value) {
|
|
swift_weakRelease(static_cast<HeapObject *>(value));
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Initialize a weak reference.
|
|
///
|
|
/// \param ref - never null
|
|
/// \param value - not necessarily a native Swift object; can be null
|
|
extern "C" void swift_unknownWeakInit(WeakReference *ref, void *value);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownWeakInit(WeakReference *ref, void *value) {
|
|
swift_weakInit(ref, static_cast<HeapObject *>(value));
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Assign a new value to a weak reference.
|
|
///
|
|
/// \param ref - never null
|
|
/// \param value - not necessarily a native Swift object; can be null
|
|
extern "C" void swift_unknownWeakAssign(WeakReference *ref, void *value);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownWeakAssign(WeakReference *ref, void *value) {
|
|
swift_weakAssign(ref, static_cast<HeapObject *>(value));
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Load a value from a weak reference, much like swift_weakLoadStrong
|
|
/// but without requiring the variable to refer to a native Swift object.
|
|
///
|
|
/// \param ref - never null
|
|
/// \return can be null
|
|
extern "C" void *swift_unknownWeakLoadStrong(WeakReference *ref);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownWeakLoadStrong(WeakReference *ref) {
|
|
swift_weakLoadStrong(ref);
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Load a value from a weak reference as if by
|
|
/// swift_unknownWeakLoadStrong, but leaving the reference in an
|
|
/// uninitialized state.
|
|
///
|
|
/// \param ref - never null
|
|
/// \return can be null
|
|
extern "C" void *swift_unknownWeakTakeStrong(WeakReference *ref);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownWeakTakeStrong(WeakReference *ref) {
|
|
swift_weakTakeStrong(ref);
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Destroy a weak reference variable that might not refer to a native
|
|
/// Swift object.
|
|
extern "C" void swift_unknownWeakDestroy(WeakReference *object);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownWeakDestroy(WeakReference *object) {
|
|
swift_weakDestroy(object);
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Copy-initialize a weak reference variable from one that might not
|
|
/// refer to a native Swift object.
|
|
extern "C" void swift_unknownWeakCopyInit(WeakReference *dest, WeakReference *src);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownWeakCopyInit(WeakReference *dest, WeakReference *src) {
|
|
swift_weakCopyInit(dest, src);
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Take-initialize a weak reference variable from one that might not
|
|
/// refer to a native Swift object.
|
|
extern "C" void swift_unknownWeakTakeInit(WeakReference *dest, WeakReference *src);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownWeakTakeInit(WeakReference *dest, WeakReference *src) {
|
|
swift_weakTakeInit(dest, src);
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Copy-assign a weak reference variable from another when either
|
|
/// or both variables might not refer to a native Swift object.
|
|
extern "C" void swift_unknownWeakCopyAssign(WeakReference *dest, WeakReference *src);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownWeakCopyAssign(WeakReference *dest, WeakReference *src) {
|
|
swift_weakCopyAssign(dest, src);
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
/// Take-assign a weak reference variable from another when either
|
|
/// or both variables might not refer to a native Swift object.
|
|
extern "C" void swift_unknownWeakTakeAssign(WeakReference *dest, WeakReference *src);
|
|
|
|
#else
|
|
|
|
static inline void swift_unknownWeakTakeAssign(WeakReference *dest, WeakReference *src) {
|
|
swift_weakTakeAssign(dest, src);
|
|
}
|
|
|
|
#endif /* SWIFT_OBJC_INTEROP */
|
|
|
|
} // end namespace swift
|
|
|
|
#endif /* SWIFT_RUNTIME_ALLOC_H */
|