//===--- HeapObject.h - Swift Language Allocation ABI -----------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://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"

#if SWIFT_OBJC_INTEROP
#include <objc/objc.h>
#endif /* SWIFT_OBJC_INTEROP */

// Bring in the definition of HeapObject 
#include "../../../stdlib/public/SwiftShims/HeapObject.h"

namespace swift {
  
struct InProcess;

template <typename Runtime> struct TargetMetadata;
using Metadata = TargetMetadata<InProcess>;
  
template <typename Runtime> struct TargetHeapMetadata;
using HeapMetadata = TargetHeapMetadata<InProcess>;

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.
SWIFT_RT_ENTRY_VISIBILITY
HeapObject *swift_allocObject(HeapMetadata const *metadata,
                              size_t requiredSize,
                              size_t requiredAlignmentMask)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RUNTIME_EXPORT
HeapObject *(*SWIFT_CC(RegisterPreservingCC) _swift_allocObject)(
                                              HeapMetadata const *metadata,
                                              size_t requiredSize,
                                              size_t requiredAlignmentMask);

/// Initializes the object header of a stack allocated object.
///
/// \param metadata - the object's metadata which is stored in the header
/// \param object - the pointer to the object's memory on the stack
/// \returns the passed object pointer.
SWIFT_RUNTIME_EXPORT
HeapObject *swift_initStackObject(HeapMetadata const *metadata,
                                  HeapObject *object);

/// Performs verification that the lifetime of a stack allocated object has
/// ended. It aborts if the reference counts of the object indicate that the
/// object did escape to some other location.
SWIFT_RUNTIME_EXPORT
void swift_verifyEndOfLifetime(HeapObject *object);

/// A structure that's two pointers in size.
///
/// C functions can use the TwoWordPair::Return type to return a value in
/// two registers, compatible with Swift's calling convention for tuples
/// and structs of two word-sized elements.
template<typename A, typename B>
struct TwoWordPair {
  A first;
  B second;
  
  TwoWordPair() = default;
  TwoWordPair(A first, B second);

  // FIXME: rdar://16257592 arm codegen doesn'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__ || defined(__CYGWIN__) || defined(_MSC_VER)
#if defined(__CYGWIN__)
  enum class Return : unsigned __int128 {};
#else
  enum class Return : unsigned long long {};
#endif

  operator Return() const {
    union {
      TwoWordPair value;
      Return mangled;
    } reinterpret = {*this};
    
    return reinterpret.mangled;
  }
  
  /*implicit*/ TwoWordPair(Return r) {
    union {
      Return mangled;
      TwoWordPair value;
    } reinterpret = {r};
    
    *this = reinterpret.value;
  }
#else
  using Return = TwoWordPair;
#endif
};
  
template<typename A, typename B>
inline TwoWordPair<A,B>::TwoWordPair(A first, B second)
  : first(first), second(second)
{
  static_assert(sizeof(A) == sizeof(void*),
                "first type must be word-sized");
  static_assert(sizeof(B) == sizeof(void*),
                "second type must be word-sized");
  static_assert(alignof(TwoWordPair) == alignof(void*),
                "pair must be word-aligned");
}
  
using BoxPair = TwoWordPair<HeapObject *, OpaqueValue *>;

/// 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.
SWIFT_RUNTIME_EXPORT
BoxPair::Return swift_allocBox(Metadata const *type);

SWIFT_RUNTIME_EXPORT
BoxPair::Return (*_swift_allocBox)(Metadata const *type);

/// Performs a uniqueness check on the pointer to a box structure. If the check
/// fails allocates a new box and stores the pointer in the buffer.
///
///  if (!isUnique(buffer[0]))
///    buffer[0] = swift_allocBox(type)
SWIFT_RUNTIME_EXPORT
BoxPair::Return swift_makeBoxUnique(OpaqueValue *buffer, Metadata const *type,
                                    size_t alignMask);

/// Returns the address of a heap object representing all empty box types.
SWIFT_RUNTIME_EXPORT
HeapObject* swift_allocEmptyBox();

// 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.

SWIFT_RT_ENTRY_VISIBILITY
void *swift_slowAlloc(size_t bytes, size_t alignMask)
     SWIFT_CC(RegisterPreservingCC);


// If the caller cannot promise to zero the object during destruction,
// then call these corresponding APIs:
SWIFT_RT_ENTRY_VISIBILITY
void swift_slowDealloc(void *ptr, size_t bytes, size_t alignMask)
     SWIFT_CC(RegisterPreservingCC);

/// Atomically increments the retain count of an object.
///
/// \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 may also prove worthwhile to have this use a custom CC
/// which preserves a larger set of registers.
SWIFT_RT_ENTRY_VISIBILITY
void swift_retain(HeapObject *object)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RUNTIME_EXPORT
void (*SWIFT_CC(RegisterPreservingCC) _swift_retain)(HeapObject *object);

SWIFT_RT_ENTRY_VISIBILITY
void swift_retain_n(HeapObject *object, uint32_t n)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RUNTIME_EXPORT
void (*SWIFT_CC(RegisterPreservingCC) _swift_retain_n)(HeapObject *object,
                                                       uint32_t n);

SWIFT_RT_ENTRY_VISIBILITY
void swift_nonatomic_retain(HeapObject *object)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RUNTIME_EXPORT
void (*SWIFT_CC(RegisterPreservingCC) _swift_nonatomic_retain)(HeapObject *object);

SWIFT_RT_ENTRY_VISIBILITY
void swift_nonatomic_retain_n(HeapObject *object, uint32_t n)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RUNTIME_EXPORT
void (*SWIFT_CC(RegisterPreservingCC) _swift_nonatomic_retain_n)(HeapObject *object,
                                                       uint32_t n);

/// Atomically increments the reference count of an object, unless it has
/// already been destroyed. Returns nil if the object is dead.
SWIFT_RT_ENTRY_VISIBILITY
HeapObject *swift_tryRetain(HeapObject *object)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RUNTIME_EXPORT
HeapObject * (* SWIFT_CC(RegisterPreservingCC) _swift_tryRetain)(HeapObject *);

/// Returns true if an object is in the process of being deallocated.
SWIFT_RUNTIME_EXPORT
bool swift_isDeallocating(HeapObject *object);

SWIFT_RUNTIME_EXPORT
bool (* SWIFT_CC(RegisterPreservingCC) _swift_isDeallocating)(HeapObject *);


/// Attempts to atomically pin an object and increment its reference
/// count.  Returns nil if the object was already pinned.
///
/// The standard protocol is that the caller is responsible for
/// calling swift_unpin on the return value.
///
/// The object reference may not be nil.
SWIFT_RT_ENTRY_VISIBILITY
HeapObject *swift_tryPin(HeapObject *object)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RT_ENTRY_VISIBILITY
HeapObject *swift_nonatomic_tryPin(HeapObject *object)
    SWIFT_CC(RegisterPreservingCC);

/// Given that an object is pinned, atomically unpin it and decrement
/// the reference count.
///
/// The object reference may be nil (to simplify the protocol).
SWIFT_RT_ENTRY_VISIBILITY
void swift_unpin(HeapObject *object)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RT_ENTRY_VISIBILITY
void swift_nonatomic_unpin(HeapObject *object)
    SWIFT_CC(RegisterPreservingCC);

/// 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.
SWIFT_RT_ENTRY_VISIBILITY
void swift_release(HeapObject *object)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RUNTIME_EXPORT
void (*SWIFT_CC(RegisterPreservingCC)
                     _swift_release)(HeapObject *object);

SWIFT_RT_ENTRY_VISIBILITY
void swift_nonatomic_release(HeapObject *object)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RUNTIME_EXPORT
void (*SWIFT_CC(RegisterPreservingCC)
                     _swift_nonatomic_release)(HeapObject *object);


/// Atomically decrements the retain count of an object n times. If the retain
/// count reaches zero, the object is destroyed
SWIFT_RT_ENTRY_VISIBILITY
void swift_release_n(HeapObject *object, uint32_t n)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RUNTIME_EXPORT
void (*SWIFT_CC(RegisterPreservingCC)
                     _swift_release_n)(HeapObject *object, uint32_t n);

/// Sets the RC_DEALLOCATING_FLAG flag. This is done non-atomically.
/// The strong reference count of \p object must be 1 and no other thread may
/// retain the object during executing this function.
SWIFT_RUNTIME_EXPORT
void swift_setDeallocating(HeapObject *object);

SWIFT_RT_ENTRY_VISIBILITY
void swift_nonatomic_release_n(HeapObject *object, uint32_t n)
    SWIFT_CC(RegisterPreservingCC);

SWIFT_RUNTIME_EXPORT
void (*SWIFT_CC(RegisterPreservingCC)
                     _swift_nonatomic_release_n)(HeapObject *object, uint32_t n);

// Refcounting observation hooks for memory tools. Don't use these.
SWIFT_RUNTIME_EXPORT
size_t swift_retainCount(HeapObject *object);
SWIFT_RUNTIME_EXPORT
size_t swift_unownedRetainCount(HeapObject *object);

/// Is this pointer a non-null unique reference to an object
/// that uses Swift reference counting?
SWIFT_RUNTIME_EXPORT
bool swift_isUniquelyReferencedNonObjC(const void *);

/// Is this non-null pointer a unique reference to an object
/// that uses Swift reference counting?
SWIFT_RUNTIME_EXPORT
bool swift_isUniquelyReferencedNonObjC_nonNull(const void *);

/// Is this non-null pointer a reference to an object that uses Swift
/// reference counting and is either uniquely referenced or pinned?
SWIFT_RUNTIME_EXPORT
bool swift_isUniquelyReferencedOrPinnedNonObjC_nonNull(const void *);

/// Is this non-null BridgeObject a unique reference to an object
/// that uses Swift reference counting?
SWIFT_RUNTIME_EXPORT
bool swift_isUniquelyReferencedNonObjC_nonNull_bridgeObject(
  uintptr_t bits);

/// Is this non-null BridgeObject a unique or pinned reference to an
/// object that uses Swift reference counting?
SWIFT_RUNTIME_EXPORT
bool swift_isUniquelyReferencedOrPinnedNonObjC_nonNull_bridgeObject(
  uintptr_t bits);

/// Is this native Swift pointer a non-null unique reference to
/// an object?
SWIFT_RUNTIME_EXPORT
bool swift_isUniquelyReferenced_native(const struct HeapObject *);

/// Is this native Swift pointer a non-null unique or pinned reference
/// to an object?
SWIFT_RT_ENTRY_VISIBILITY
bool swift_isUniquelyReferencedOrPinned_native(
  const struct HeapObject *) SWIFT_CC(RegisterPreservingCC);

/// Is this non-null native Swift pointer a unique reference to
/// an object?
SWIFT_RT_ENTRY_VISIBILITY
bool swift_isUniquelyReferenced_nonNull_native(
  const struct HeapObject *) SWIFT_CC(RegisterPreservingCC);

/// Does this non-null native Swift pointer refer to an object that
/// is either uniquely referenced or pinned?
SWIFT_RT_ENTRY_VISIBILITY
bool swift_isUniquelyReferencedOrPinned_nonNull_native(
  const struct HeapObject *) SWIFT_CC(RegisterPreservingCC);

/// Deallocate the given memory.
///
/// It must have been returned by swift_allocObject and the strong reference
/// must have the RC_DEALLOCATING_FLAG flag set, but otherwise the object is
/// 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.
SWIFT_RT_ENTRY_VISIBILITY
void swift_deallocObject(HeapObject *object, size_t allocatedSize,
                         size_t allocatedAlignMask)
    SWIFT_CC(RegisterPreservingCC);

/// Deallocate the given memory.
///
/// It must have been returned by swift_allocObject, possibly used as an
/// Objective-C class instance, and the strong reference must have the
/// RC_DEALLOCATING_FLAG flag set, but otherwise the object is 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.
SWIFT_RUNTIME_EXPORT
void swift_deallocClassInstance(HeapObject *object,
                                 size_t allocatedSize,
                                 size_t allocatedAlignMask);

/// Deallocate the given memory after destroying instance variables.
///
/// Destroys instance variables in classes more derived than the given metatype.
///
/// It must have been returned by swift_allocObject, possibly used as an
/// Objective-C class instance, and the strong reference must be equal to 1.
///
/// \param object - may be null
/// \param type - most derived class whose instance variables do not need to
///   be destroyed
/// \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
SWIFT_RUNTIME_EXPORT
void swift_deallocPartialClassInstance(HeapObject *object,
                                       const HeapMetadata *type,
                                       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.
SWIFT_RUNTIME_EXPORT
void swift_deallocBox(HeapObject *object);

/// Project the value out of a box. `object` must have been allocated
/// using `swift_allocBox`, or by the compiler using a statically-emitted
/// box metadata object.
SWIFT_RUNTIME_EXPORT
OpaqueValue *swift_projectBox(HeapObject *object);

/// 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) {
    swift_retain(*other);
    object = *other;
    ;
  }
  SwiftRAII(SwiftRAII &&other) : object(*other) {
    other.object = nullptr;
  }
  SwiftRAII &operator=(const SwiftRAII &other) {
    if (object)
      swift_release(object);
    swift_retain(*other);
    object = *other;
    return *this;
  }
  SwiftRAII &operator=(SwiftRAII &&other) {
    if (object)
      swift_release(object);
    object = *other;
    other.object = nullptr;
    return *this;
  }

  HeapObject *operator *() const { return object; }
};

/*****************************************************************************/
/**************************** UNOWNED REFERENCES *****************************/
/*****************************************************************************/

/// An unowned reference in memory.  This is ABI.
struct UnownedReference {
  HeapObject *Value;
};

/// Increment the unowned retain count.
SWIFT_RT_ENTRY_VISIBILITY
void swift_unownedRetain(HeapObject *value)
    SWIFT_CC(RegisterPreservingCC);

/// Decrement the unowned retain count.
SWIFT_RT_ENTRY_VISIBILITY
void swift_unownedRelease(HeapObject *value)
    SWIFT_CC(RegisterPreservingCC);

/// Increment the unowned retain count.
SWIFT_RT_ENTRY_VISIBILITY
void swift_nonatomic_unownedRetain(HeapObject *value)
    SWIFT_CC(RegisterPreservingCC);

/// Decrement the unowned retain count.
SWIFT_RT_ENTRY_VISIBILITY
void swift_nonatomic_unownedRelease(HeapObject *value)
    SWIFT_CC(RegisterPreservingCC);

/// Increment the unowned retain count by n.
SWIFT_RT_ENTRY_VISIBILITY
void swift_unownedRetain_n(HeapObject *value, int n)
    SWIFT_CC(RegisterPreservingCC);

/// Decrement the unowned retain count by n.
SWIFT_RT_ENTRY_VISIBILITY
void swift_unownedRelease_n(HeapObject *value, int n)
    SWIFT_CC(RegisterPreservingCC);

/// Increment the unowned retain count by n.
SWIFT_RT_ENTRY_VISIBILITY
void swift_nonatomic_unownedRetain_n(HeapObject *value, int n)
    SWIFT_CC(RegisterPreservingCC);

/// Decrement the unowned retain count by n.
SWIFT_RT_ENTRY_VISIBILITY
void swift_nonatomic_unownedRelease_n(HeapObject *value, int n)
    SWIFT_CC(RegisterPreservingCC);

/// Increment the strong retain count of an object, aborting if it has
/// been deallocated.
SWIFT_RT_ENTRY_VISIBILITY
void swift_unownedRetainStrong(HeapObject *value)
    SWIFT_CC(RegisterPreservingCC);

/// Increment the strong retain count of an object, aborting if it has
/// been deallocated.
SWIFT_RT_ENTRY_VISIBILITY
void swift_nonatomic_unownedRetainStrong(HeapObject *value)
    SWIFT_CC(RegisterPreservingCC);

/// Increment the strong retain count of an object which may have been
/// deallocated, aborting if it has been deallocated, and decrement its
/// unowned reference count.
SWIFT_RT_ENTRY_VISIBILITY
void swift_unownedRetainStrongAndRelease(HeapObject *value)
    SWIFT_CC(RegisterPreservingCC);

/// Increment the strong retain count of an object which may have been
/// deallocated, aborting if it has been deallocated, and decrement its
/// unowned reference count.
SWIFT_RT_ENTRY_VISIBILITY
void swift_nonatomic_unownedRetainStrongAndRelease(HeapObject *value)
    SWIFT_CC(RegisterPreservingCC);

/// Aborts if the object has been deallocated.
SWIFT_RUNTIME_EXPORT
void swift_unownedCheck(HeapObject *value);

static inline void swift_unownedInit(UnownedReference *ref, HeapObject *value) {
  ref->Value = value;
  swift_unownedRetain(value);
}

static inline void swift_unownedAssign(UnownedReference *ref,
                                       HeapObject *value) {
  auto oldValue = ref->Value;
  if (value != oldValue) {
    swift_unownedRetain(value);
    ref->Value = value;
    swift_unownedRelease(oldValue);
  }
}

static inline HeapObject *swift_unownedLoadStrong(UnownedReference *ref) {
  auto value = ref->Value;
  swift_unownedRetainStrong(value);
  return value;
}

static inline void *swift_unownedTakeStrong(UnownedReference *ref) {
  auto value = ref->Value;
  swift_unownedRetainStrongAndRelease(value);
  return value;
}

static inline void swift_unownedDestroy(UnownedReference *ref) {
  swift_unownedRelease(ref->Value);
}

static inline void swift_unownedCopyInit(UnownedReference *dest,
                                         UnownedReference *src) {
  dest->Value = src->Value;
  swift_unownedRetain(dest->Value);
}

static inline void swift_unownedTakeInit(UnownedReference *dest,
                                         UnownedReference *src) {
  dest->Value = src->Value;
}

static inline void swift_unownedCopyAssign(UnownedReference *dest,
                                           UnownedReference *src) {
  auto newValue = src->Value;
  auto oldValue = dest->Value;
  if (newValue != oldValue) {
    dest->Value = newValue;
    swift_unownedRetain(newValue);
    swift_unownedRelease(oldValue);
  }
}

static inline void swift_unownedTakeAssign(UnownedReference *dest,
                                           UnownedReference *src) {
  auto newValue = src->Value;
  auto oldValue = dest->Value;
  dest->Value = newValue;
  swift_unownedRelease(oldValue);
}

static inline bool swift_unownedIsEqual(UnownedReference *ref,
                                        HeapObject *value) {
  bool isEqual = ref->Value == value;
  if (isEqual)
    swift_unownedCheck(value);
  return isEqual;
}

/*****************************************************************************/
/****************************** WEAK REFERENCES ******************************/
/*****************************************************************************/

// Defined in Runtime/WeakReference.h
class WeakReference;

/// Initialize a weak reference.
///
/// \param ref - never null
/// \param value - can be null
SWIFT_RUNTIME_EXPORT
void swift_weakInit(WeakReference *ref, HeapObject *value);

/// Assign a new value to a weak reference.
///
/// \param ref - never null
/// \param value - can be null
SWIFT_RUNTIME_EXPORT
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
SWIFT_RUNTIME_EXPORT
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
SWIFT_RUNTIME_EXPORT
HeapObject *swift_weakTakeStrong(WeakReference *ref);

/// Destroy a weak reference.
///
/// \param ref - never null, but can refer to a null object
SWIFT_RUNTIME_EXPORT
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
SWIFT_RUNTIME_EXPORT
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
SWIFT_RUNTIME_EXPORT
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
SWIFT_RUNTIME_EXPORT
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
SWIFT_RUNTIME_EXPORT
void swift_weakTakeAssign(WeakReference *dest, WeakReference *src);

/*****************************************************************************/
/************************* OTHER REFERENCE-COUNTING **************************/
/*****************************************************************************/

SWIFT_RUNTIME_EXPORT
void *swift_bridgeObjectRetain(void *value)
    SWIFT_CC(DefaultCC);
/// Increment the strong retain count of a bridged object by n.
SWIFT_RUNTIME_EXPORT
void *swift_bridgeObjectRetain_n(void *value, int n)
    SWIFT_CC(DefaultCC);

SWIFT_RUNTIME_EXPORT
void *swift_nonatomic_bridgeObjectRetain(void *value)
    SWIFT_CC(DefaultCC);

/// Increment the strong retain count of a bridged object by n.
SWIFT_RUNTIME_EXPORT
void *swift_nonatomic_bridgeObjectRetain_n(void *value, int n)
    SWIFT_CC(DefaultCC);

/*****************************************************************************/
/************************ UNKNOWN REFERENCE-COUNTING *************************/
/*****************************************************************************/

#if SWIFT_OBJC_INTEROP

/// Increment the strong retain count of an object which might not be a native
/// Swift object.
SWIFT_RUNTIME_EXPORT
void swift_unknownRetain(void *value)
    SWIFT_CC(DefaultCC);
/// Increment the strong retain count of an object which might not be a native
/// Swift object by n.
SWIFT_RUNTIME_EXPORT
void swift_unknownRetain_n(void *value, int n)
    SWIFT_CC(DefaultCC);

/// Increment the strong retain count of an object which might not be a native
/// Swift object.
SWIFT_RUNTIME_EXPORT
void swift_nonatomic_unknownRetain(void *value)
    SWIFT_CC(DefaultCC);
/// Increment the strong retain count of an object which might not be a native
/// Swift object by n.
SWIFT_RUNTIME_EXPORT
void swift_nonatomic_unknownRetain_n(void *value, int n)
    SWIFT_CC(DefaultCC);


#else

static inline void swift_unknownRetain(void *value)
    SWIFT_CC(DefaultCC) {
  swift_retain(static_cast<HeapObject *>(value));
}

static inline void swift_unknownRetain_n(void *value, int n)
    SWIFT_CC(DefaultCC) {
  swift_retain_n(static_cast<HeapObject *>(value), n);
}

static inline void swift_nonatomic_unknownRetain(void *value)
    SWIFT_CC(DefaultCC) {
  swift_nonatomic_retain(static_cast<HeapObject *>(value));
}

static inline void swift_nonatomic_unknownRetain_n(void *value, int n)
    SWIFT_CC(DefaultCC) {
  swift_nonatomic_retain_n(static_cast<HeapObject *>(value), n);
}


#endif /* SWIFT_OBJC_INTEROP */

SWIFT_RUNTIME_EXPORT
void swift_bridgeObjectRelease(void *value)
    SWIFT_CC(DefaultCC);
/// Decrement the strong retain count of a bridged object by n.
SWIFT_RUNTIME_EXPORT
void swift_bridgeObjectRelease_n(void *value, int n)
    SWIFT_CC(DefaultCC);

SWIFT_RUNTIME_EXPORT
void swift_nonatomic_bridgeObjectRelease(void *value)
    SWIFT_CC(DefaultCC);
/// Decrement the strong retain count of a bridged object by n.
SWIFT_RUNTIME_EXPORT
void swift_nonatomic_bridgeObjectRelease_n(void *value, int n)
    SWIFT_CC(DefaultCC);

#if SWIFT_OBJC_INTEROP

/// Decrement the strong retain count of an object which might not be a native
/// Swift object.
SWIFT_RUNTIME_EXPORT
void swift_unknownRelease(void *value)
    SWIFT_CC(DefaultCC);
/// Decrement the strong retain count of an object which might not be a native
/// Swift object by n.
SWIFT_RUNTIME_EXPORT
void swift_unknownRelease_n(void *value, int n)
    SWIFT_CC(DefaultCC);

/// Decrement the strong retain count of an object which might not be a native
/// Swift object.
SWIFT_RUNTIME_EXPORT
void swift_nonatomic_unknownRelease(void *value)
    SWIFT_CC(DefaultCC);
/// Decrement the strong retain count of an object which might not be a native
/// Swift object by n.
SWIFT_RUNTIME_EXPORT
void swift_nonatomic_unknownRelease_n(void *value, int n)
    SWIFT_CC(DefaultCC);

#else

static inline void swift_unknownRelease(void *value)
    SWIFT_CC(RegisterPreservingCC) {
  swift_release(static_cast<HeapObject *>(value));
}

static inline void swift_unknownRelease_n(void *value, int n)
    SWIFT_CC(RegisterPreservingCC) {
  swift_release_n(static_cast<HeapObject *>(value), n);
}

static inline void swift_nonatomic_unknownRelease(void *value)
    SWIFT_CC(RegisterPreservingCC) {
  swift_nonatomic_release(static_cast<HeapObject *>(value));
}

static inline void swift_nonatomic_unknownRelease_n(void *value, int n)
    SWIFT_CC(RegisterPreservingCC) {
  swift_nonatomic_release_n(static_cast<HeapObject *>(value), n);
}

#endif /* SWIFT_OBJC_INTEROP */

/*****************************************************************************/
/************************** UNKNOWN WEAK REFERENCES **************************/
/*****************************************************************************/

#if SWIFT_OBJC_INTEROP

/// Initialize a weak reference.
///
/// \param ref - never null
/// \param value - not necessarily a native Swift object; can be null
SWIFT_RUNTIME_EXPORT
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
SWIFT_RUNTIME_EXPORT
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
SWIFT_RUNTIME_EXPORT
void *swift_unknownWeakLoadStrong(WeakReference *ref);

#else

static inline void *swift_unknownWeakLoadStrong(WeakReference *ref) {
  return static_cast<void *>(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
SWIFT_RUNTIME_EXPORT
void *swift_unknownWeakTakeStrong(WeakReference *ref);

#else

static inline void *swift_unknownWeakTakeStrong(WeakReference *ref) {
  return static_cast<void *>(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.
SWIFT_RUNTIME_EXPORT
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.
SWIFT_RUNTIME_EXPORT
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.
SWIFT_RUNTIME_EXPORT
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.
SWIFT_RUNTIME_EXPORT
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.
SWIFT_RUNTIME_EXPORT
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 */

/*****************************************************************************/
/************************ UNKNOWN UNOWNED REFERENCES *************************/
/*****************************************************************************/

#if SWIFT_OBJC_INTEROP

/// Initialize an unowned reference to an object with unknown reference
/// counting.
SWIFT_RUNTIME_EXPORT
void swift_unknownUnownedInit(UnownedReference *ref, void *value);

#else

static inline void swift_unknownUnownedInit(UnownedReference *ref,
                                            void *value) {
  swift_unownedInit(ref, static_cast<HeapObject*>(value));
}

#endif /* SWIFT_OBJC_INTEROP */

#if SWIFT_OBJC_INTEROP

/// Assign to an unowned reference holding an object with unknown reference
/// counting.
SWIFT_RUNTIME_EXPORT
void swift_unknownUnownedAssign(UnownedReference *ref, void *value);

#else

static inline void swift_unknownUnownedAssign(UnownedReference *ref,
                                              void *value) {
  swift_unownedAssign(ref, static_cast<HeapObject*>(value));
}

#endif /* SWIFT_OBJC_INTEROP */

#if SWIFT_OBJC_INTEROP

/// Load from an unowned reference to an object with unknown reference
/// counting.
SWIFT_RUNTIME_EXPORT
void *swift_unknownUnownedLoadStrong(UnownedReference *ref);

#else

static inline void *swift_unknownUnownedLoadStrong(UnownedReference *ref) {
  return swift_unownedLoadStrong(ref);
}

#endif /* SWIFT_OBJC_INTEROP */

#if SWIFT_OBJC_INTEROP

/// Take from an unowned reference to an object with unknown reference
/// counting.
SWIFT_RUNTIME_EXPORT
void *swift_unknownUnownedTakeStrong(UnownedReference *ref);

#else

static inline void *swift_unknownUnownedTakeStrong(UnownedReference *ref) {
  return swift_unownedTakeStrong(ref);
}

#endif /* SWIFT_OBJC_INTEROP */

#if SWIFT_OBJC_INTEROP
  
/// Destroy an unowned reference to an object with unknown reference counting.
SWIFT_RUNTIME_EXPORT
void swift_unknownUnownedDestroy(UnownedReference *ref);

#else

static inline void swift_unknownUnownedDestroy(UnownedReference *ref) {
  swift_unownedDestroy(ref);
}

#endif /* SWIFT_OBJC_INTEROP */

#if SWIFT_OBJC_INTEROP

/// Copy-initialize an unowned reference variable from one that might not
/// refer to a native Swift object.
SWIFT_RUNTIME_EXPORT
void swift_unknownUnownedCopyInit(UnownedReference *dest,
                                  UnownedReference *src);

#else

static inline void swift_unknownUnownedCopyInit(UnownedReference *dest,
                                                UnownedReference *src) {
  swift_unownedCopyInit(dest, src);
}

#endif /* SWIFT_OBJC_INTEROP */

#if SWIFT_OBJC_INTEROP

/// Take-initialize an unowned reference variable from one that might not
/// refer to a native Swift object.
SWIFT_RUNTIME_EXPORT
void swift_unknownUnownedTakeInit(UnownedReference *dest,
                                             UnownedReference *src);

#else

static inline void swift_unknownUnownedTakeInit(UnownedReference *dest,
                                                UnownedReference *src) {
  swift_unownedTakeInit(dest, src);
}

#endif /* SWIFT_OBJC_INTEROP */

#if SWIFT_OBJC_INTEROP

/// Copy-assign an unowned reference variable from another when either
/// or both variables might not refer to a native Swift object.
SWIFT_RUNTIME_EXPORT
void swift_unknownUnownedCopyAssign(UnownedReference *dest,
                                               UnownedReference *src);

#else

static inline void swift_unknownUnownedCopyAssign(UnownedReference *dest,
                                                  UnownedReference *src) {
  swift_unownedCopyAssign(dest, src);
}

#endif /* SWIFT_OBJC_INTEROP */

#if SWIFT_OBJC_INTEROP

/// Take-assign an unowned reference variable from another when either
/// or both variables might not refer to a native Swift object.
SWIFT_RUNTIME_EXPORT
void swift_unknownUnownedTakeAssign(UnownedReference *dest,
                                               UnownedReference *src);

#else

static inline void swift_unknownUnownedTakeAssign(UnownedReference *dest,
                                                  UnownedReference *src) {
  swift_unownedTakeAssign(dest, src);
}

#endif /* SWIFT_OBJC_INTEROP */

#if SWIFT_OBJC_INTEROP

/// Return `*ref == value` when ref might not refer to a native Swift object.
/// Does not halt when *ref is a dead object as long as *ref != value.
SWIFT_RUNTIME_EXPORT
bool swift_unknownUnownedIsEqual(UnownedReference *ref, void *value);

#else

static inline bool swift_unknownUnownedIsEqual(UnownedReference *ref,
                                               void *value) {
  return swift_unownedIsEqual(ref, static_cast<HeapObject *>(value));
}

#endif /* SWIFT_OBJC_INTEROP */

/// Return the name of a Swift type represented by a metadata object.
SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT
TwoWordPair<const char *, uintptr_t>::Return
swift_getTypeName(const Metadata *type, bool qualified);  

} // end namespace swift

#endif /* SWIFT_RUNTIME_ALLOC_H */
