|  | /** | 
|  | * This module provides an interface to the garbage collector used by | 
|  | * applications written in the D programming language. It allows the | 
|  | * garbage collector in the runtime to be swapped without affecting | 
|  | * binary compatibility of applications. | 
|  | * | 
|  | * Using this module is not necessary in typical D code. It is mostly | 
|  | * useful when doing low-level _memory management. | 
|  | * | 
|  | * Notes_to_users: | 
|  | * | 
|  | $(OL | 
|  | $(LI The GC is a conservative mark-and-sweep collector. It only runs a | 
|  | collection cycle when an allocation is requested of it, never | 
|  | otherwise. Hence, if the program is not doing allocations, | 
|  | there will be no GC collection pauses. The pauses occur because | 
|  | all threads the GC knows about are halted so the threads' stacks | 
|  | and registers can be scanned for references to GC allocated data. | 
|  | ) | 
|  |  | 
|  | $(LI The GC does not know about threads that were created by directly calling | 
|  | the OS/C runtime thread creation APIs and D threads that were detached | 
|  | from the D runtime after creation. | 
|  | Such threads will not be paused for a GC collection, and the GC might not detect | 
|  | references to GC allocated data held by them. This can cause memory corruption. | 
|  | There are several ways to resolve this issue: | 
|  | $(OL | 
|  | $(LI Do not hold references to GC allocated data in such threads.) | 
|  | $(LI Register/unregister such data with calls to $(LREF addRoot)/$(LREF removeRoot) and | 
|  | $(LREF addRange)/$(LREF removeRange).) | 
|  | $(LI Maintain another reference to that same data in another thread that the | 
|  | GC does know about.) | 
|  | $(LI Disable GC collection cycles while that thread is active with $(LREF disable)/$(LREF enable).) | 
|  | $(LI Register the thread with the GC using $(REF thread_attachThis, core,thread,osthread)/$(REF thread_detachThis, core,thread,threadbase).) | 
|  | ) | 
|  | ) | 
|  | ) | 
|  | * | 
|  | * Notes_to_implementors: | 
|  | * $(UL | 
|  | * $(LI On POSIX systems, the signals `SIGRTMIN` and `SIGRTMIN + 1` are reserved | 
|  | *   by this module for use in the garbage collector implementation. | 
|  | *   Typically, they will be used to stop and resume other threads | 
|  | *   when performing a collection, but an implementation may choose | 
|  | *   not to use this mechanism (or not stop the world at all, in the | 
|  | *   case of concurrent garbage collectors).) | 
|  | * | 
|  | * $(LI Registers, the stack, and any other _memory locations added through | 
|  | *   the $(D GC.$(LREF addRange)) function are always scanned conservatively. | 
|  | *   This means that even if a variable is e.g. of type $(D float), | 
|  | *   it will still be scanned for possible GC pointers. And, if the | 
|  | *   word-interpreted representation of the variable matches a GC-managed | 
|  | *   _memory block's address, that _memory block is considered live.) | 
|  | * | 
|  | * $(LI Implementations are free to scan the non-root heap in a precise | 
|  | *   manner, so that fields of types like $(D float) will not be considered | 
|  | *   relevant when scanning the heap. Thus, casting a GC pointer to an | 
|  | *   integral type (e.g. $(D size_t)) and storing it in a field of that | 
|  | *   type inside the GC heap may mean that it will not be recognized | 
|  | *   if the _memory block was allocated with precise type info or with | 
|  | *   the $(D GC.BlkAttr.$(LREF NO_SCAN)) attribute.) | 
|  | * | 
|  | * $(LI Destructors will always be executed while other threads are | 
|  | *   active; that is, an implementation that stops the world must not | 
|  | *   execute destructors until the world has been resumed.) | 
|  | * | 
|  | * $(LI A destructor of an object must not access object references | 
|  | *   within the object. This means that an implementation is free to | 
|  | *   optimize based on this rule.) | 
|  | * | 
|  | * $(LI An implementation is free to perform heap compaction and copying | 
|  | *   so long as no valid GC pointers are invalidated in the process. | 
|  | *   However, _memory allocated with $(D GC.BlkAttr.$(LREF NO_MOVE)) must | 
|  | *   not be moved/copied.) | 
|  | * | 
|  | * $(LI Implementations must support interior pointers. That is, if the | 
|  | *   only reference to a GC-managed _memory block points into the | 
|  | *   middle of the block rather than the beginning (for example), the | 
|  | *   GC must consider the _memory block live. The exception to this | 
|  | *   rule is when a _memory block is allocated with the | 
|  | *   $(D GC.BlkAttr.$(LREF NO_INTERIOR)) attribute; it is the user's | 
|  | *   responsibility to make sure such _memory blocks have a proper pointer | 
|  | *   to them when they should be considered live.) | 
|  | * | 
|  | * $(LI It is acceptable for an implementation to store bit flags into | 
|  | *   pointer values and GC-managed _memory blocks, so long as such a | 
|  | *   trick is not visible to the application. In practice, this means | 
|  | *   that only a stop-the-world collector can do this.) | 
|  | * | 
|  | * $(LI Implementations are free to assume that GC pointers are only | 
|  | *   stored on word boundaries. Unaligned pointers may be ignored | 
|  | *   entirely.) | 
|  | * | 
|  | * $(LI Implementations are free to run collections at any point. It is, | 
|  | *   however, recommendable to only do so when an allocation attempt | 
|  | *   happens and there is insufficient _memory available.) | 
|  | * ) | 
|  | * | 
|  | * Copyright: Copyright Sean Kelly 2005 - 2015. | 
|  | * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | 
|  | * Authors:   Sean Kelly, Alex Rønne Petersen | 
|  | * Source:    $(DRUNTIMESRC core/_memory.d) | 
|  | */ | 
|  |  | 
|  | module core.memory; | 
|  |  | 
|  | version (ARM) | 
|  | version = AnyARM; | 
|  | else version (AArch64) | 
|  | version = AnyARM; | 
|  |  | 
|  | version (iOS) | 
|  | version = iOSDerived; | 
|  | else version (TVOS) | 
|  | version = iOSDerived; | 
|  | else version (WatchOS) | 
|  | version = iOSDerived; | 
|  |  | 
|  | private | 
|  | { | 
|  | extern (C) uint gc_getAttr( void* p ) pure nothrow; | 
|  | extern (C) uint gc_setAttr( void* p, uint a ) pure nothrow; | 
|  | extern (C) uint gc_clrAttr( void* p, uint a ) pure nothrow; | 
|  |  | 
|  | extern (C) void*   gc_addrOf( void* p ) pure nothrow @nogc; | 
|  | extern (C) size_t  gc_sizeOf( void* p ) pure nothrow @nogc; | 
|  |  | 
|  | struct BlkInfo_ | 
|  | { | 
|  | void*  base; | 
|  | size_t size; | 
|  | uint   attr; | 
|  | } | 
|  |  | 
|  | extern (C) BlkInfo_ gc_query(return scope void* p) pure nothrow; | 
|  | extern (C) GC.Stats gc_stats ( ) @safe nothrow @nogc; | 
|  | extern (C) GC.ProfileStats gc_profileStats ( ) nothrow @nogc @safe; | 
|  | } | 
|  |  | 
|  | version (CoreDoc) | 
|  | { | 
|  | /** | 
|  | * The minimum size of a system page in bytes. | 
|  | * | 
|  | * This is a compile time, platform specific value. This value might not | 
|  | * be accurate, since it might be possible to change this value. Whenever | 
|  | * possible, please use $(LREF pageSize) instead, which is initialized | 
|  | * during runtime. | 
|  | * | 
|  | * The minimum size is useful when the context requires a compile time known | 
|  | * value, like the size of a static array: `ubyte[minimumPageSize] buffer`. | 
|  | */ | 
|  | enum minimumPageSize : size_t; | 
|  | } | 
|  | else version (AnyARM) | 
|  | { | 
|  | version (iOSDerived) | 
|  | enum size_t minimumPageSize = 16384; | 
|  | else | 
|  | enum size_t minimumPageSize = 4096; | 
|  | } | 
|  | else | 
|  | enum size_t minimumPageSize = 4096; | 
|  |  | 
|  | /// | 
|  | unittest | 
|  | { | 
|  | ubyte[minimumPageSize] buffer; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * The size of a system page in bytes. | 
|  | * | 
|  | * This value is set at startup time of the application. It's safe to use | 
|  | * early in the start process, like in shared module constructors and | 
|  | * initialization of the D runtime itself. | 
|  | */ | 
|  | immutable size_t pageSize; | 
|  |  | 
|  | /// | 
|  | unittest | 
|  | { | 
|  | ubyte[] buffer = new ubyte[pageSize]; | 
|  | } | 
|  |  | 
|  | // The reason for this elaborated way of declaring a function is: | 
|  | // | 
|  | // * `pragma(crt_constructor)` is used to declare a constructor that is called by | 
|  | // the C runtime, before C main. This allows the `pageSize` value to be used | 
|  | // during initialization of the D runtime. This also avoids any issues with | 
|  | // static module constructors and circular references. | 
|  | // | 
|  | // * `pragma(mangle)` is used because `pragma(crt_constructor)` requires a | 
|  | // function with C linkage. To avoid any name conflict with other C symbols, | 
|  | // standard D mangling is used. | 
|  | // | 
|  | // * The extra function declaration, without the body, is to be able to get the | 
|  | // D mangling of the function without the need to hardcode the value. | 
|  | // | 
|  | // * The extern function declaration also has the side effect of making it | 
|  | // impossible to manually call the function with standard syntax. This is to | 
|  | // make it more difficult to call the function again, manually. | 
|  | private void initialize(); | 
|  | pragma(crt_constructor) | 
|  | pragma(mangle, `_D` ~ initialize.mangleof) | 
|  | private extern (C) void initialize() @system | 
|  | { | 
|  | version (Posix) | 
|  | { | 
|  | import core.sys.posix.unistd : sysconf, _SC_PAGESIZE; | 
|  |  | 
|  | (cast() pageSize) = cast(size_t) sysconf(_SC_PAGESIZE); | 
|  | } | 
|  | else version (Windows) | 
|  | { | 
|  | import core.sys.windows.winbase : GetSystemInfo, SYSTEM_INFO; | 
|  |  | 
|  | SYSTEM_INFO si; | 
|  | GetSystemInfo(&si); | 
|  | (cast() pageSize) = cast(size_t) si.dwPageSize; | 
|  | } | 
|  | else | 
|  | static assert(false, __FUNCTION__ ~ " is not implemented on this platform"); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This struct encapsulates all garbage collection functionality for the D | 
|  | * programming language. | 
|  | */ | 
|  | struct GC | 
|  | { | 
|  | @disable this(); | 
|  |  | 
|  | /** | 
|  | * Aggregation of GC stats to be exposed via public API | 
|  | */ | 
|  | static struct Stats | 
|  | { | 
|  | /// number of used bytes on the GC heap (might only get updated after a collection) | 
|  | size_t usedSize; | 
|  | /// number of free bytes on the GC heap (might only get updated after a collection) | 
|  | size_t freeSize; | 
|  | /// number of bytes allocated for current thread since program start | 
|  | ulong allocatedInCurrentThread; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Aggregation of current profile information | 
|  | */ | 
|  | static struct ProfileStats | 
|  | { | 
|  | import core.time : Duration; | 
|  | /// total number of GC cycles | 
|  | size_t numCollections; | 
|  | /// total time spent doing GC | 
|  | Duration totalCollectionTime; | 
|  | /// total time threads were paused doing GC | 
|  | Duration totalPauseTime; | 
|  | /// largest time threads were paused during one GC cycle | 
|  | Duration maxPauseTime; | 
|  | /// largest time spent doing one GC cycle | 
|  | Duration maxCollectionTime; | 
|  | } | 
|  |  | 
|  | extern(C): | 
|  |  | 
|  | /** | 
|  | * Enables automatic garbage collection behavior if collections have | 
|  | * previously been suspended by a call to disable.  This function is | 
|  | * reentrant, and must be called once for every call to disable before | 
|  | * automatic collections are enabled. | 
|  | */ | 
|  | pragma(mangle, "gc_enable") static void enable() nothrow pure; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Disables automatic garbage collections performed to minimize the | 
|  | * process footprint.  Collections may continue to occur in instances | 
|  | * where the implementation deems necessary for correct program behavior, | 
|  | * such as during an out of memory condition.  This function is reentrant, | 
|  | * but enable must be called once for each call to disable. | 
|  | */ | 
|  | pragma(mangle, "gc_disable") static void disable() nothrow pure; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Begins a full collection.  While the meaning of this may change based | 
|  | * on the garbage collector implementation, typical behavior is to scan | 
|  | * all stack segments for roots, mark accessible memory blocks as alive, | 
|  | * and then to reclaim free space.  This action may need to suspend all | 
|  | * running threads for at least part of the collection process. | 
|  | */ | 
|  | pragma(mangle, "gc_collect") static void collect() nothrow pure; | 
|  |  | 
|  | /** | 
|  | * Indicates that the managed memory space be minimized by returning free | 
|  | * physical memory to the operating system.  The amount of free memory | 
|  | * returned depends on the allocator design and on program behavior. | 
|  | */ | 
|  | pragma(mangle, "gc_minimize") static void minimize() nothrow pure; | 
|  |  | 
|  | extern(D): | 
|  |  | 
|  | /** | 
|  | * Elements for a bit field representing memory block attributes.  These | 
|  | * are manipulated via the getAttr, setAttr, clrAttr functions. | 
|  | */ | 
|  | enum BlkAttr : uint | 
|  | { | 
|  | NONE        = 0b0000_0000, /// No attributes set. | 
|  | FINALIZE    = 0b0000_0001, /// Finalize the data in this block on collect. | 
|  | NO_SCAN     = 0b0000_0010, /// Do not scan through this block on collect. | 
|  | NO_MOVE     = 0b0000_0100, /// Do not move this memory block on collect. | 
|  | /** | 
|  | This block contains the info to allow appending. | 
|  |  | 
|  | This can be used to manually allocate arrays. Initial slice size is 0. | 
|  |  | 
|  | Note: The slice's usable size will not match the block size. Use | 
|  | $(LREF capacity) to retrieve actual usable capacity. | 
|  |  | 
|  | Example: | 
|  | ---- | 
|  | // Allocate the underlying array. | 
|  | int*  pToArray = cast(int*)GC.malloc(10 * int.sizeof, GC.BlkAttr.NO_SCAN | GC.BlkAttr.APPENDABLE); | 
|  | // Bind a slice. Check the slice has capacity information. | 
|  | int[] slice = pToArray[0 .. 0]; | 
|  | assert(capacity(slice) > 0); | 
|  | // Appending to the slice will not relocate it. | 
|  | slice.length = 5; | 
|  | slice ~= 1; | 
|  | assert(slice.ptr == p); | 
|  | ---- | 
|  | */ | 
|  | APPENDABLE  = 0b0000_1000, | 
|  |  | 
|  | /** | 
|  | This block is guaranteed to have a pointer to its base while it is | 
|  | alive.  Interior pointers can be safely ignored.  This attribute is | 
|  | useful for eliminating false pointers in very large data structures | 
|  | and is only implemented for data structures at least a page in size. | 
|  | */ | 
|  | NO_INTERIOR = 0b0001_0000, | 
|  |  | 
|  | STRUCTFINAL = 0b0010_0000, // the block has a finalizer for (an array of) structs | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Contains aggregate information about a block of managed memory.  The | 
|  | * purpose of this struct is to support a more efficient query style in | 
|  | * instances where detailed information is needed. | 
|  | * | 
|  | * base = A pointer to the base of the block in question. | 
|  | * size = The size of the block, calculated from base. | 
|  | * attr = Attribute bits set on the memory block. | 
|  | */ | 
|  | alias BlkInfo = BlkInfo_; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Returns a bit field representing all block attributes set for the memory | 
|  | * referenced by p.  If p references memory not originally allocated by | 
|  | * this garbage collector, points to the interior of a memory block, or if | 
|  | * p is null, zero will be returned. | 
|  | * | 
|  | * Params: | 
|  | *  p = A pointer to the root of a valid memory block or to null. | 
|  | * | 
|  | * Returns: | 
|  | *  A bit field containing any bits set for the memory block referenced by | 
|  | *  p or zero on error. | 
|  | */ | 
|  | static uint getAttr( const scope void* p ) nothrow | 
|  | { | 
|  | return gc_getAttr(cast(void*) p); | 
|  | } | 
|  |  | 
|  |  | 
|  | /// ditto | 
|  | static uint getAttr(void* p) pure nothrow | 
|  | { | 
|  | return gc_getAttr( p ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Sets the specified bits for the memory references by p.  If p references | 
|  | * memory not originally allocated by this garbage collector, points to the | 
|  | * interior of a memory block, or if p is null, no action will be | 
|  | * performed. | 
|  | * | 
|  | * Params: | 
|  | *  p = A pointer to the root of a valid memory block or to null. | 
|  | *  a = A bit field containing any bits to set for this memory block. | 
|  | * | 
|  | * Returns: | 
|  | *  The result of a call to getAttr after the specified bits have been | 
|  | *  set. | 
|  | */ | 
|  | static uint setAttr( const scope void* p, uint a ) nothrow | 
|  | { | 
|  | return gc_setAttr(cast(void*) p, a); | 
|  | } | 
|  |  | 
|  |  | 
|  | /// ditto | 
|  | static uint setAttr(void* p, uint a) pure nothrow | 
|  | { | 
|  | return gc_setAttr( p, a ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Clears the specified bits for the memory references by p.  If p | 
|  | * references memory not originally allocated by this garbage collector, | 
|  | * points to the interior of a memory block, or if p is null, no action | 
|  | * will be performed. | 
|  | * | 
|  | * Params: | 
|  | *  p = A pointer to the root of a valid memory block or to null. | 
|  | *  a = A bit field containing any bits to clear for this memory block. | 
|  | * | 
|  | * Returns: | 
|  | *  The result of a call to getAttr after the specified bits have been | 
|  | *  cleared. | 
|  | */ | 
|  | static uint clrAttr( const scope void* p, uint a ) nothrow | 
|  | { | 
|  | return gc_clrAttr(cast(void*) p, a); | 
|  | } | 
|  |  | 
|  |  | 
|  | /// ditto | 
|  | static uint clrAttr(void* p, uint a) pure nothrow | 
|  | { | 
|  | return gc_clrAttr( p, a ); | 
|  | } | 
|  |  | 
|  | extern(C): | 
|  |  | 
|  | /** | 
|  | * Requests an aligned block of managed memory from the garbage collector. | 
|  | * This memory may be deleted at will with a call to free, or it may be | 
|  | * discarded and cleaned up automatically during a collection run.  If | 
|  | * allocation fails, this function will call onOutOfMemory which is | 
|  | * expected to throw an OutOfMemoryError. | 
|  | * | 
|  | * Params: | 
|  | *  sz = The desired allocation size in bytes. | 
|  | *  ba = A bitmask of the attributes to set on this block. | 
|  | *  ti = TypeInfo to describe the memory. The GC might use this information | 
|  | *       to improve scanning for pointers or to call finalizers. | 
|  | * | 
|  | * Returns: | 
|  | *  A reference to the allocated memory or null if insufficient memory | 
|  | *  is available. | 
|  | * | 
|  | * Throws: | 
|  | *  OutOfMemoryError on allocation failure. | 
|  | */ | 
|  | version (D_ProfileGC) | 
|  | pragma(mangle, "gc_mallocTrace") static void* malloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null, | 
|  | string file = __FILE__, int line = __LINE__, string func = __FUNCTION__) pure nothrow; | 
|  | else | 
|  | pragma(mangle, "gc_malloc") static void* malloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null) pure nothrow; | 
|  |  | 
|  | /** | 
|  | * Requests an aligned block of managed memory from the garbage collector. | 
|  | * This memory may be deleted at will with a call to free, or it may be | 
|  | * discarded and cleaned up automatically during a collection run.  If | 
|  | * allocation fails, this function will call onOutOfMemory which is | 
|  | * expected to throw an OutOfMemoryError. | 
|  | * | 
|  | * Params: | 
|  | *  sz = The desired allocation size in bytes. | 
|  | *  ba = A bitmask of the attributes to set on this block. | 
|  | *  ti = TypeInfo to describe the memory. The GC might use this information | 
|  | *       to improve scanning for pointers or to call finalizers. | 
|  | * | 
|  | * Returns: | 
|  | *  Information regarding the allocated memory block or BlkInfo.init on | 
|  | *  error. | 
|  | * | 
|  | * Throws: | 
|  | *  OutOfMemoryError on allocation failure. | 
|  | */ | 
|  | version (D_ProfileGC) | 
|  | pragma(mangle, "gc_qallocTrace") static BlkInfo qalloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null, | 
|  | string file = __FILE__, int line = __LINE__, string func = __FUNCTION__) pure nothrow; | 
|  | else | 
|  | pragma(mangle, "gc_qalloc") static BlkInfo qalloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null) pure nothrow; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Requests an aligned block of managed memory from the garbage collector, | 
|  | * which is initialized with all bits set to zero.  This memory may be | 
|  | * deleted at will with a call to free, or it may be discarded and cleaned | 
|  | * up automatically during a collection run.  If allocation fails, this | 
|  | * function will call onOutOfMemory which is expected to throw an | 
|  | * OutOfMemoryError. | 
|  | * | 
|  | * Params: | 
|  | *  sz = The desired allocation size in bytes. | 
|  | *  ba = A bitmask of the attributes to set on this block. | 
|  | *  ti = TypeInfo to describe the memory. The GC might use this information | 
|  | *       to improve scanning for pointers or to call finalizers. | 
|  | * | 
|  | * Returns: | 
|  | *  A reference to the allocated memory or null if insufficient memory | 
|  | *  is available. | 
|  | * | 
|  | * Throws: | 
|  | *  OutOfMemoryError on allocation failure. | 
|  | */ | 
|  | version (D_ProfileGC) | 
|  | pragma(mangle, "gc_callocTrace") static void* calloc(size_t sz, uint ba = 0, const TypeInfo ti = null, | 
|  | string file = __FILE__, int line = __LINE__, string func = __FUNCTION__) pure nothrow; | 
|  | else | 
|  | pragma(mangle, "gc_calloc") static void* calloc(size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Extend, shrink or allocate a new block of memory keeping the contents of | 
|  | * an existing block | 
|  | * | 
|  | * If `sz` is zero, the memory referenced by p will be deallocated as if | 
|  | * by a call to `free`. | 
|  | * If `p` is `null`, new memory will be allocated via `malloc`. | 
|  | * If `p` is pointing to memory not allocated from the GC or to the interior | 
|  | * of an allocated memory block, no operation is performed and null is returned. | 
|  | * | 
|  | * Otherwise, a new memory block of size `sz` will be allocated as if by a | 
|  | * call to `malloc`, or the implementation may instead resize or shrink the memory | 
|  | * block in place. | 
|  | * The contents of the new memory block will be the same as the contents | 
|  | * of the old memory block, up to the lesser of the new and old sizes. | 
|  | * | 
|  | * The caller guarantees that there are no other live pointers to the | 
|  | * passed memory block, still it might not be freed immediately by `realloc`. | 
|  | * The garbage collector can reclaim the memory block in a later | 
|  | * collection if it is unused. | 
|  | * If allocation fails, this function will throw an `OutOfMemoryError`. | 
|  | * | 
|  | * If `ba` is zero (the default) the attributes of the existing memory | 
|  | * will be used for an allocation. | 
|  | * If `ba` is not zero and no new memory is allocated, the bits in ba will | 
|  | * replace those of the current memory block. | 
|  | * | 
|  | * Params: | 
|  | *  p  = A pointer to the base of a valid memory block or to `null`. | 
|  | *  sz = The desired allocation size in bytes. | 
|  | *  ba = A bitmask of the BlkAttr attributes to set on this block. | 
|  | *  ti = TypeInfo to describe the memory. The GC might use this information | 
|  | *       to improve scanning for pointers or to call finalizers. | 
|  | * | 
|  | * Returns: | 
|  | *  A reference to the allocated memory on success or `null` if `sz` is | 
|  | *  zero or the pointer does not point to the base of an GC allocated | 
|  | *  memory block. | 
|  | * | 
|  | * Throws: | 
|  | *  `OutOfMemoryError` on allocation failure. | 
|  | */ | 
|  | version (D_ProfileGC) | 
|  | pragma(mangle, "gc_reallocTrace") static void* realloc(return scope void* p, size_t sz, uint ba = 0, const TypeInfo ti = null, | 
|  | string file = __FILE__, int line = __LINE__, string func = __FUNCTION__) pure nothrow; | 
|  | else | 
|  | pragma(mangle, "gc_realloc") static void* realloc(return scope void* p, size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow; | 
|  |  | 
|  | // https://issues.dlang.org/show_bug.cgi?id=13111 | 
|  | /// | 
|  | unittest | 
|  | { | 
|  | enum size1 = 1 << 11 + 1; // page in large object pool | 
|  | enum size2 = 1 << 22 + 1; // larger than large object pool size | 
|  |  | 
|  | auto data1 = cast(ubyte*)GC.calloc(size1); | 
|  | auto data2 = cast(ubyte*)GC.realloc(data1, size2); | 
|  |  | 
|  | GC.BlkInfo info = GC.query(data2); | 
|  | assert(info.size >= size2); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Requests that the managed memory block referenced by p be extended in | 
|  | * place by at least mx bytes, with a desired extension of sz bytes.  If an | 
|  | * extension of the required size is not possible or if p references memory | 
|  | * not originally allocated by this garbage collector, no action will be | 
|  | * taken. | 
|  | * | 
|  | * Params: | 
|  | *  p  = A pointer to the root of a valid memory block or to null. | 
|  | *  mx = The minimum extension size in bytes. | 
|  | *  sz = The desired extension size in bytes. | 
|  | *  ti = TypeInfo to describe the full memory block. The GC might use | 
|  | *       this information to improve scanning for pointers or to | 
|  | *       call finalizers. | 
|  | * | 
|  | * Returns: | 
|  | *  The size in bytes of the extended memory block referenced by p or zero | 
|  | *  if no extension occurred. | 
|  | * | 
|  | * Note: | 
|  | *  Extend may also be used to extend slices (or memory blocks with | 
|  | *  $(LREF APPENDABLE) info). However, use the return value only | 
|  | *  as an indicator of success. $(LREF capacity) should be used to | 
|  | *  retrieve actual usable slice capacity. | 
|  | */ | 
|  | version (D_ProfileGC) | 
|  | pragma(mangle, "gc_extendTrace") static size_t extend(void* p, size_t mx, size_t sz, const TypeInfo ti = null, | 
|  | string file = __FILE__, int line = __LINE__, string func = __FUNCTION__) pure nothrow; | 
|  | else | 
|  | pragma(mangle, "gc_extend") static size_t extend(void* p, size_t mx, size_t sz, const TypeInfo ti = null) pure nothrow; | 
|  |  | 
|  | /// Standard extending | 
|  | unittest | 
|  | { | 
|  | size_t size = 1000; | 
|  | int* p = cast(int*)GC.malloc(size * int.sizeof, GC.BlkAttr.NO_SCAN); | 
|  |  | 
|  | //Try to extend the allocated data by 1000 elements, preferred 2000. | 
|  | size_t u = GC.extend(p, 1000 * int.sizeof, 2000 * int.sizeof); | 
|  | if (u != 0) | 
|  | size = u / int.sizeof; | 
|  | } | 
|  | /// slice extending | 
|  | unittest | 
|  | { | 
|  | int[] slice = new int[](1000); | 
|  | int*  p     = slice.ptr; | 
|  |  | 
|  | //Check we have access to capacity before attempting the extend | 
|  | if (slice.capacity) | 
|  | { | 
|  | //Try to extend slice by 1000 elements, preferred 2000. | 
|  | size_t u = GC.extend(p, 1000 * int.sizeof, 2000 * int.sizeof); | 
|  | if (u != 0) | 
|  | { | 
|  | slice.length = slice.capacity; | 
|  | assert(slice.length >= 2000); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Requests that at least sz bytes of memory be obtained from the operating | 
|  | * system and marked as free. | 
|  | * | 
|  | * Params: | 
|  | *  sz = The desired size in bytes. | 
|  | * | 
|  | * Returns: | 
|  | *  The actual number of bytes reserved or zero on error. | 
|  | */ | 
|  | pragma(mangle, "gc_reserve") static size_t reserve(size_t sz) nothrow pure; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Deallocates the memory referenced by p.  If p is null, no action occurs. | 
|  | * If p references memory not originally allocated by this garbage | 
|  | * collector, if p points to the interior of a memory block, or if this | 
|  | * method is called from a finalizer, no action will be taken.  The block | 
|  | * will not be finalized regardless of whether the FINALIZE attribute is | 
|  | * set.  If finalization is desired, call $(REF1 destroy, object) prior to `GC.free`. | 
|  | * | 
|  | * Params: | 
|  | *  p = A pointer to the root of a valid memory block or to null. | 
|  | */ | 
|  | pragma(mangle, "gc_free") static void free(void* p) pure nothrow @nogc; | 
|  |  | 
|  | extern(D): | 
|  |  | 
|  | /** | 
|  | * Returns the base address of the memory block containing p.  This value | 
|  | * is useful to determine whether p is an interior pointer, and the result | 
|  | * may be passed to routines such as sizeOf which may otherwise fail.  If p | 
|  | * references memory not originally allocated by this garbage collector, if | 
|  | * p is null, or if the garbage collector does not support this operation, | 
|  | * null will be returned. | 
|  | * | 
|  | * Params: | 
|  | *  p = A pointer to the root or the interior of a valid memory block or to | 
|  | *      null. | 
|  | * | 
|  | * Returns: | 
|  | *  The base address of the memory block referenced by p or null on error. | 
|  | */ | 
|  | static inout(void)* addrOf( inout(void)* p ) nothrow @nogc pure @trusted | 
|  | { | 
|  | return cast(inout(void)*)gc_addrOf(cast(void*)p); | 
|  | } | 
|  |  | 
|  | /// ditto | 
|  | static void* addrOf(void* p) pure nothrow @nogc @trusted | 
|  | { | 
|  | return gc_addrOf(p); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the true size of the memory block referenced by p.  This value | 
|  | * represents the maximum number of bytes for which a call to realloc may | 
|  | * resize the existing block in place.  If p references memory not | 
|  | * originally allocated by this garbage collector, points to the interior | 
|  | * of a memory block, or if p is null, zero will be returned. | 
|  | * | 
|  | * Params: | 
|  | *  p = A pointer to the root of a valid memory block or to null. | 
|  | * | 
|  | * Returns: | 
|  | *  The size in bytes of the memory block referenced by p or zero on error. | 
|  | */ | 
|  | static size_t sizeOf( const scope void* p ) nothrow @nogc /* FIXME pure */ | 
|  | { | 
|  | return gc_sizeOf(cast(void*)p); | 
|  | } | 
|  |  | 
|  |  | 
|  | /// ditto | 
|  | static size_t sizeOf(void* p) pure nothrow @nogc | 
|  | { | 
|  | return gc_sizeOf( p ); | 
|  | } | 
|  |  | 
|  | // verify that the reallocation doesn't leave the size cache in a wrong state | 
|  | unittest | 
|  | { | 
|  | auto data = cast(int*)realloc(null, 4096); | 
|  | size_t size = GC.sizeOf(data); | 
|  | assert(size >= 4096); | 
|  | data = cast(int*)GC.realloc(data, 4100); | 
|  | size = GC.sizeOf(data); | 
|  | assert(size >= 4100); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns aggregate information about the memory block containing p.  If p | 
|  | * references memory not originally allocated by this garbage collector, if | 
|  | * p is null, or if the garbage collector does not support this operation, | 
|  | * BlkInfo.init will be returned.  Typically, support for this operation | 
|  | * is dependent on support for addrOf. | 
|  | * | 
|  | * Params: | 
|  | *  p = A pointer to the root or the interior of a valid memory block or to | 
|  | *      null. | 
|  | * | 
|  | * Returns: | 
|  | *  Information regarding the memory block referenced by p or BlkInfo.init | 
|  | *  on error. | 
|  | */ | 
|  | static BlkInfo query(return scope const void* p) nothrow | 
|  | { | 
|  | return gc_query(cast(void*)p); | 
|  | } | 
|  |  | 
|  |  | 
|  | /// ditto | 
|  | static BlkInfo query(return scope void* p) pure nothrow | 
|  | { | 
|  | return gc_query( p ); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns runtime stats for currently active GC implementation | 
|  | * See `core.memory.GC.Stats` for list of available metrics. | 
|  | */ | 
|  | static Stats stats() @safe nothrow @nogc | 
|  | { | 
|  | return gc_stats(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns runtime profile stats for currently active GC implementation | 
|  | * See `core.memory.GC.ProfileStats` for list of available metrics. | 
|  | */ | 
|  | static ProfileStats profileStats() nothrow @nogc @safe | 
|  | { | 
|  | return gc_profileStats(); | 
|  | } | 
|  |  | 
|  | extern(C): | 
|  |  | 
|  | /** | 
|  | * Adds an internal root pointing to the GC memory block referenced by p. | 
|  | * As a result, the block referenced by p itself and any blocks accessible | 
|  | * via it will be considered live until the root is removed again. | 
|  | * | 
|  | * If p is null, no operation is performed. | 
|  | * | 
|  | * Params: | 
|  | *  p = A pointer into a GC-managed memory block or null. | 
|  | * | 
|  | * Example: | 
|  | * --- | 
|  | * // Typical C-style callback mechanism; the passed function | 
|  | * // is invoked with the user-supplied context pointer at a | 
|  | * // later point. | 
|  | * extern(C) void addCallback(void function(void*), void*); | 
|  | * | 
|  | * // Allocate an object on the GC heap (this would usually be | 
|  | * // some application-specific context data). | 
|  | * auto context = new Object; | 
|  | * | 
|  | * // Make sure that it is not collected even if it is no | 
|  | * // longer referenced from D code (stack, GC heap, …). | 
|  | * GC.addRoot(cast(void*)context); | 
|  | * | 
|  | * // Also ensure that a moving collector does not relocate | 
|  | * // the object. | 
|  | * GC.setAttr(cast(void*)context, GC.BlkAttr.NO_MOVE); | 
|  | * | 
|  | * // Now context can be safely passed to the C library. | 
|  | * addCallback(&myHandler, cast(void*)context); | 
|  | * | 
|  | * extern(C) void myHandler(void* ctx) | 
|  | * { | 
|  | *     // Assuming that the callback is invoked only once, the | 
|  | *     // added root can be removed again now to allow the GC | 
|  | *     // to collect it later. | 
|  | *     GC.removeRoot(ctx); | 
|  | *     GC.clrAttr(ctx, GC.BlkAttr.NO_MOVE); | 
|  | * | 
|  | *     auto context = cast(Object)ctx; | 
|  | *     // Use context here… | 
|  | * } | 
|  | * --- | 
|  | */ | 
|  | pragma(mangle, "gc_addRoot") static void addRoot(const void* p) nothrow @nogc pure; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Removes the memory block referenced by p from an internal list of roots | 
|  | * to be scanned during a collection.  If p is null or is not a value | 
|  | * previously passed to addRoot() then no operation is performed. | 
|  | * | 
|  | * Params: | 
|  | *  p = A pointer into a GC-managed memory block or null. | 
|  | */ | 
|  | pragma(mangle, "gc_removeRoot") static void removeRoot(const void* p) nothrow @nogc pure; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Adds $(D p[0 .. sz]) to the list of memory ranges to be scanned for | 
|  | * pointers during a collection. If p is null, no operation is performed. | 
|  | * | 
|  | * Note that $(D p[0 .. sz]) is treated as an opaque range of memory assumed | 
|  | * to be suitably managed by the caller. In particular, if p points into a | 
|  | * GC-managed memory block, addRange does $(I not) mark this block as live. | 
|  | * | 
|  | * Params: | 
|  | *  p  = A pointer to a valid memory address or to null. | 
|  | *  sz = The size in bytes of the block to add. If sz is zero then the | 
|  | *       no operation will occur. If p is null then sz must be zero. | 
|  | *  ti = TypeInfo to describe the memory. The GC might use this information | 
|  | *       to improve scanning for pointers or to call finalizers | 
|  | * | 
|  | * Example: | 
|  | * --- | 
|  | * // Allocate a piece of memory on the C heap. | 
|  | * enum size = 1_000; | 
|  | * auto rawMemory = core.stdc.stdlib.malloc(size); | 
|  | * | 
|  | * // Add it as a GC range. | 
|  | * GC.addRange(rawMemory, size); | 
|  | * | 
|  | * // Now, pointers to GC-managed memory stored in | 
|  | * // rawMemory will be recognized on collection. | 
|  | * --- | 
|  | */ | 
|  | pragma(mangle, "gc_addRange") | 
|  | static void addRange(const void* p, size_t sz, const TypeInfo ti = null) @nogc nothrow pure; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Removes the memory range starting at p from an internal list of ranges | 
|  | * to be scanned during a collection. If p is null or does not represent | 
|  | * a value previously passed to addRange() then no operation is | 
|  | * performed. | 
|  | * | 
|  | * Params: | 
|  | *  p  = A pointer to a valid memory address or to null. | 
|  | */ | 
|  | pragma(mangle, "gc_removeRange") static void removeRange(const void* p) nothrow @nogc pure; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Runs any finalizer that is located in address range of the | 
|  | * given code segment.  This is used before unloading shared | 
|  | * libraries.  All matching objects which have a finalizer in this | 
|  | * code segment are assumed to be dead, using them while or after | 
|  | * calling this method has undefined behavior. | 
|  | * | 
|  | * Params: | 
|  | *  segment = address range of a code segment. | 
|  | */ | 
|  | pragma(mangle, "gc_runFinalizers") static void runFinalizers(const scope void[] segment); | 
|  |  | 
|  | /** | 
|  | * Queries the GC whether the current thread is running object finalization | 
|  | * as part of a GC collection, or an explicit call to runFinalizers. | 
|  | * | 
|  | * As some GC implementations (such as the current conservative one) don't | 
|  | * support GC memory allocation during object finalization, this function | 
|  | * can be used to guard against such programming errors. | 
|  | * | 
|  | * Returns: | 
|  | *  true if the current thread is in a finalizer, a destructor invoked by | 
|  | *  the GC. | 
|  | */ | 
|  | pragma(mangle, "gc_inFinalizer") static bool inFinalizer() nothrow @nogc @safe; | 
|  |  | 
|  | /// | 
|  | @safe nothrow @nogc unittest | 
|  | { | 
|  | // Only code called from a destructor is executed during finalization. | 
|  | assert(!GC.inFinalizer); | 
|  | } | 
|  |  | 
|  | /// | 
|  | unittest | 
|  | { | 
|  | enum Outcome | 
|  | { | 
|  | notCalled, | 
|  | calledManually, | 
|  | calledFromDruntime | 
|  | } | 
|  |  | 
|  | static class Resource | 
|  | { | 
|  | static Outcome outcome; | 
|  |  | 
|  | this() | 
|  | { | 
|  | outcome = Outcome.notCalled; | 
|  | } | 
|  |  | 
|  | ~this() | 
|  | { | 
|  | if (GC.inFinalizer) | 
|  | { | 
|  | outcome = Outcome.calledFromDruntime; | 
|  |  | 
|  | import core.exception : InvalidMemoryOperationError; | 
|  | try | 
|  | { | 
|  | /* | 
|  | * Presently, allocating GC memory during finalization | 
|  | * is forbidden and leads to | 
|  | * `InvalidMemoryOperationError` being thrown. | 
|  | * | 
|  | * `GC.inFinalizer` can be used to guard against | 
|  | * programming erros such as these and is also a more | 
|  | * efficient way to verify whether a destructor was | 
|  | * invoked by the GC. | 
|  | */ | 
|  | cast(void) GC.malloc(1); | 
|  | assert(false); | 
|  | } | 
|  | catch (InvalidMemoryOperationError e) | 
|  | { | 
|  | return; | 
|  | } | 
|  | assert(false); | 
|  | } | 
|  | else | 
|  | outcome = Outcome.calledManually; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void createGarbage() | 
|  | { | 
|  | auto r = new Resource; | 
|  | r = null; | 
|  | } | 
|  |  | 
|  | assert(Resource.outcome == Outcome.notCalled); | 
|  | createGarbage(); | 
|  | GC.collect; | 
|  | assert( | 
|  | Resource.outcome == Outcome.notCalled || | 
|  | Resource.outcome == Outcome.calledFromDruntime); | 
|  |  | 
|  | auto r = new Resource; | 
|  | GC.runFinalizers((cast(const void*)typeid(Resource).destructor)[0..1]); | 
|  | assert(Resource.outcome == Outcome.calledFromDruntime); | 
|  | Resource.outcome = Outcome.notCalled; | 
|  |  | 
|  | debug(MEMSTOMP) {} else | 
|  | { | 
|  | // assume Resource data is still available | 
|  | r.destroy; | 
|  | assert(Resource.outcome == Outcome.notCalled); | 
|  | } | 
|  |  | 
|  | r = new Resource; | 
|  | assert(Resource.outcome == Outcome.notCalled); | 
|  | r.destroy; | 
|  | assert(Resource.outcome == Outcome.calledManually); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the number of bytes allocated for the current thread | 
|  | * since program start. It is the same as | 
|  | * GC.stats().allocatedInCurrentThread, but faster. | 
|  | */ | 
|  | pragma(mangle, "gc_allocatedInCurrentThread") static ulong allocatedInCurrentThread() nothrow; | 
|  |  | 
|  | /// Using allocatedInCurrentThread | 
|  | nothrow unittest | 
|  | { | 
|  | ulong currentlyAllocated = GC.allocatedInCurrentThread(); | 
|  | struct DataStruct | 
|  | { | 
|  | long l1; | 
|  | long l2; | 
|  | long l3; | 
|  | long l4; | 
|  | } | 
|  | DataStruct* unused = new DataStruct; | 
|  | assert(GC.allocatedInCurrentThread() == currentlyAllocated + 32); | 
|  | assert(GC.stats().allocatedInCurrentThread == currentlyAllocated + 32); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Pure variants of C's memory allocation functions `malloc`, `calloc`, and | 
|  | * `realloc` and deallocation function `free`. | 
|  | * | 
|  | * UNIX 98 requires that errno be set to ENOMEM upon failure. | 
|  | * Purity is achieved by saving and restoring the value of `errno`, thus | 
|  | * behaving as if it were never changed. | 
|  | * | 
|  | * See_Also: | 
|  | *     $(LINK2 https://dlang.org/spec/function.html#pure-functions, D's rules for purity), | 
|  | *     which allow for memory allocation under specific circumstances. | 
|  | */ | 
|  | void* pureMalloc()(size_t size) @trusted pure @nogc nothrow | 
|  | { | 
|  | const errnosave = fakePureErrno; | 
|  | void* ret = fakePureMalloc(size); | 
|  | fakePureErrno = errnosave; | 
|  | return ret; | 
|  | } | 
|  | /// ditto | 
|  | void* pureCalloc()(size_t nmemb, size_t size) @trusted pure @nogc nothrow | 
|  | { | 
|  | const errnosave = fakePureErrno; | 
|  | void* ret = fakePureCalloc(nmemb, size); | 
|  | fakePureErrno = errnosave; | 
|  | return ret; | 
|  | } | 
|  | /// ditto | 
|  | void* pureRealloc()(void* ptr, size_t size) @system pure @nogc nothrow | 
|  | { | 
|  | const errnosave = fakePureErrno; | 
|  | void* ret = fakePureRealloc(ptr, size); | 
|  | fakePureErrno = errnosave; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /// ditto | 
|  | void pureFree()(void* ptr) @system pure @nogc nothrow | 
|  | { | 
|  | version (Posix) | 
|  | { | 
|  | // POSIX free doesn't set errno | 
|  | fakePureFree(ptr); | 
|  | } | 
|  | else | 
|  | { | 
|  | const errnosave = fakePureErrno; | 
|  | fakePureFree(ptr); | 
|  | fakePureErrno = errnosave; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// | 
|  | @system pure nothrow @nogc unittest | 
|  | { | 
|  | ubyte[] fun(size_t n) pure | 
|  | { | 
|  | void* p = pureMalloc(n); | 
|  | p !is null || n == 0 || assert(0); | 
|  | scope(failure) p = pureRealloc(p, 0); | 
|  | p = pureRealloc(p, n *= 2); | 
|  | p !is null || n == 0 || assert(0); | 
|  | return cast(ubyte[]) p[0 .. n]; | 
|  | } | 
|  |  | 
|  | auto buf = fun(100); | 
|  | assert(buf.length == 200); | 
|  | pureFree(buf.ptr); | 
|  | } | 
|  |  | 
|  | @system pure nothrow @nogc unittest | 
|  | { | 
|  | const int errno = fakePureErrno(); | 
|  |  | 
|  | void* x = pureMalloc(10);            // normal allocation | 
|  | assert(errno == fakePureErrno()); // errno shouldn't change | 
|  | assert(x !is null);                   // allocation should succeed | 
|  |  | 
|  | x = pureRealloc(x, 10);              // normal reallocation | 
|  | assert(errno == fakePureErrno()); // errno shouldn't change | 
|  | assert(x !is null);                   // allocation should succeed | 
|  |  | 
|  | fakePureFree(x); | 
|  |  | 
|  | void* y = pureCalloc(10, 1);         // normal zeroed allocation | 
|  | assert(errno == fakePureErrno()); // errno shouldn't change | 
|  | assert(y !is null);                   // allocation should succeed | 
|  |  | 
|  | fakePureFree(y); | 
|  |  | 
|  | // Workaround bug in glibc 2.26 | 
|  | // See also: https://issues.dlang.org/show_bug.cgi?id=17956 | 
|  | void* z = pureMalloc(size_t.max & ~255); // won't affect `errno` | 
|  | assert(errno == fakePureErrno()); // errno shouldn't change | 
|  | assert(z is null); | 
|  | } | 
|  |  | 
|  | // locally purified for internal use here only | 
|  |  | 
|  | static import core.stdc.errno; | 
|  | static if (__traits(getOverloads, core.stdc.errno, "errno").length == 1 | 
|  | && __traits(getLinkage, core.stdc.errno.errno) == "C") | 
|  | { | 
|  | extern(C) pragma(mangle, __traits(identifier, core.stdc.errno.errno)) | 
|  | private ref int fakePureErrno() @nogc nothrow pure @system; | 
|  | } | 
|  | else | 
|  | { | 
|  | extern(C) private @nogc nothrow pure @system | 
|  | { | 
|  | pragma(mangle, __traits(identifier, core.stdc.errno.getErrno)) | 
|  | @property int fakePureErrno(); | 
|  |  | 
|  | pragma(mangle, __traits(identifier, core.stdc.errno.setErrno)) | 
|  | @property int fakePureErrno(int); | 
|  | } | 
|  | } | 
|  |  | 
|  | version (D_BetterC) {} | 
|  | else // TODO: remove this function after Phobos no longer needs it. | 
|  | extern (C) private @system @nogc nothrow | 
|  | { | 
|  | ref int fakePureErrnoImpl() | 
|  | { | 
|  | import core.stdc.errno; | 
|  | return errno(); | 
|  | } | 
|  | } | 
|  |  | 
|  | extern (C) private pure @system @nogc nothrow | 
|  | { | 
|  | pragma(mangle, "malloc") void* fakePureMalloc(size_t); | 
|  | pragma(mangle, "calloc") void* fakePureCalloc(size_t nmemb, size_t size); | 
|  | pragma(mangle, "realloc") void* fakePureRealloc(void* ptr, size_t size); | 
|  |  | 
|  | pragma(mangle, "free") void fakePureFree(void* ptr); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Destroys and then deallocates an object. | 
|  |  | 
|  | In detail, `__delete(x)` returns with no effect if `x` is `null`. Otherwise, it | 
|  | performs the following actions in sequence: | 
|  | $(UL | 
|  | $(LI | 
|  | Calls the destructor `~this()` for the object referred to by `x` | 
|  | (if `x` is a class or interface reference) or | 
|  | for the object pointed to by `x` (if `x` is a pointer to a `struct`). | 
|  | Arrays of structs call the destructor, if defined, for each element in the array. | 
|  | If no destructor is defined, this step has no effect. | 
|  | ) | 
|  | $(LI | 
|  | Frees the memory allocated for `x`. If `x` is a reference to a class | 
|  | or interface, the memory allocated for the underlying instance is freed. If `x` is | 
|  | a pointer, the memory allocated for the pointed-to object is freed. If `x` is a | 
|  | built-in array, the memory allocated for the array is freed. | 
|  | If `x` does not refer to memory previously allocated with `new` (or the lower-level | 
|  | equivalents in the GC API), the behavior is undefined. | 
|  | ) | 
|  | $(LI | 
|  | Lastly, `x` is set to `null`. Any attempt to read or write the freed memory via | 
|  | other references will result in undefined behavior. | 
|  | ) | 
|  | ) | 
|  |  | 
|  | Note: Users should prefer $(REF1 destroy, object) to explicitly finalize objects, | 
|  | and only resort to $(REF __delete, core,memory) when $(REF destroy, object) | 
|  | wouldn't be a feasible option. | 
|  |  | 
|  | Params: | 
|  | x = aggregate object that should be destroyed | 
|  |  | 
|  | See_Also: $(REF1 destroy, object), $(REF free, core,GC) | 
|  |  | 
|  | History: | 
|  |  | 
|  | The `delete` keyword allowed to free GC-allocated memory. | 
|  | As this is inherently not `@safe`, it has been deprecated. | 
|  | This function has been added to provide an easy transition from `delete`. | 
|  | It performs the same functionality as the former `delete` keyword. | 
|  | */ | 
|  | void __delete(T)(ref T x) @system | 
|  | { | 
|  | static void _destructRecurse(S)(ref S s) | 
|  | if (is(S == struct)) | 
|  | { | 
|  | static if (__traits(hasMember, S, "__xdtor") && | 
|  | // Bugzilla 14746: Check that it's the exact member of S. | 
|  | __traits(isSame, S, __traits(parent, s.__xdtor))) | 
|  | s.__xdtor(); | 
|  | } | 
|  |  | 
|  | // See also: https://github.com/dlang/dmd/blob/v2.078.0/src/dmd/e2ir.d#L3886 | 
|  | static if (is(T == interface)) | 
|  | { | 
|  | .object.destroy(x); | 
|  | } | 
|  | else static if (is(T == class)) | 
|  | { | 
|  | .object.destroy(x); | 
|  | } | 
|  | else static if (is(T == U*, U)) | 
|  | { | 
|  | static if (is(U == struct)) | 
|  | { | 
|  | if (x) | 
|  | _destructRecurse(*x); | 
|  | } | 
|  | } | 
|  | else static if (is(T : E[], E)) | 
|  | { | 
|  | static if (is(E == struct)) | 
|  | { | 
|  | foreach_reverse (ref e; x) | 
|  | _destructRecurse(e); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | static assert(0, "It is not possible to delete: `" ~ T.stringof ~ "`"); | 
|  | } | 
|  |  | 
|  | static if (is(T == interface) || | 
|  | is(T == class) || | 
|  | is(T == U2*, U2)) | 
|  | { | 
|  | GC.free(GC.addrOf(cast(void*) x)); | 
|  | x = null; | 
|  | } | 
|  | else static if (is(T : E2[], E2)) | 
|  | { | 
|  | GC.free(GC.addrOf(cast(void*) x.ptr)); | 
|  | x = null; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Deleting classes | 
|  | unittest | 
|  | { | 
|  | bool dtorCalled; | 
|  | class B | 
|  | { | 
|  | int test; | 
|  | ~this() | 
|  | { | 
|  | dtorCalled = true; | 
|  | } | 
|  | } | 
|  | B b = new B(); | 
|  | B a = b; | 
|  | b.test = 10; | 
|  |  | 
|  | assert(GC.addrOf(cast(void*) b) != null); | 
|  | __delete(b); | 
|  | assert(b is null); | 
|  | assert(dtorCalled); | 
|  | assert(GC.addrOf(cast(void*) b) == null); | 
|  | // but be careful, a still points to it | 
|  | assert(a !is null); | 
|  | assert(GC.addrOf(cast(void*) a) == null); // but not a valid GC pointer | 
|  | } | 
|  |  | 
|  | /// Deleting interfaces | 
|  | unittest | 
|  | { | 
|  | bool dtorCalled; | 
|  | interface A | 
|  | { | 
|  | int quack(); | 
|  | } | 
|  | class B : A | 
|  | { | 
|  | int a; | 
|  | int quack() | 
|  | { | 
|  | a++; | 
|  | return a; | 
|  | } | 
|  | ~this() | 
|  | { | 
|  | dtorCalled = true; | 
|  | } | 
|  | } | 
|  | A a = new B(); | 
|  | a.quack(); | 
|  |  | 
|  | assert(GC.addrOf(cast(void*) a) != null); | 
|  | __delete(a); | 
|  | assert(a is null); | 
|  | assert(dtorCalled); | 
|  | assert(GC.addrOf(cast(void*) a) == null); | 
|  | } | 
|  |  | 
|  | /// Deleting structs | 
|  | unittest | 
|  | { | 
|  | bool dtorCalled; | 
|  | struct A | 
|  | { | 
|  | string test; | 
|  | ~this() | 
|  | { | 
|  | dtorCalled = true; | 
|  | } | 
|  | } | 
|  | auto a = new A("foo"); | 
|  |  | 
|  | assert(GC.addrOf(cast(void*) a) != null); | 
|  | __delete(a); | 
|  | assert(a is null); | 
|  | assert(dtorCalled); | 
|  | assert(GC.addrOf(cast(void*) a) == null); | 
|  |  | 
|  | // https://issues.dlang.org/show_bug.cgi?id=22779 | 
|  | A *aptr; | 
|  | __delete(aptr); | 
|  | } | 
|  |  | 
|  | /// Deleting arrays | 
|  | unittest | 
|  | { | 
|  | int[] a = [1, 2, 3]; | 
|  | auto b = a; | 
|  |  | 
|  | assert(GC.addrOf(b.ptr) != null); | 
|  | __delete(b); | 
|  | assert(b is null); | 
|  | assert(GC.addrOf(b.ptr) == null); | 
|  | // but be careful, a still points to it | 
|  | assert(a !is null); | 
|  | assert(GC.addrOf(a.ptr) == null); // but not a valid GC pointer | 
|  | } | 
|  |  | 
|  | /// Deleting arrays of structs | 
|  | unittest | 
|  | { | 
|  | int dtorCalled; | 
|  | struct A | 
|  | { | 
|  | int a; | 
|  | ~this() | 
|  | { | 
|  | assert(dtorCalled == a); | 
|  | dtorCalled++; | 
|  | } | 
|  | } | 
|  | auto arr = [A(1), A(2), A(3)]; | 
|  | arr[0].a = 2; | 
|  | arr[1].a = 1; | 
|  | arr[2].a = 0; | 
|  |  | 
|  | assert(GC.addrOf(arr.ptr) != null); | 
|  | __delete(arr); | 
|  | assert(dtorCalled == 3); | 
|  | assert(GC.addrOf(arr.ptr) == null); | 
|  | } | 
|  |  | 
|  | // Deleting raw memory | 
|  | unittest | 
|  | { | 
|  | import core.memory : GC; | 
|  | auto a = GC.malloc(5); | 
|  | assert(GC.addrOf(cast(void*) a) != null); | 
|  | __delete(a); | 
|  | assert(a is null); | 
|  | assert(GC.addrOf(cast(void*) a) == null); | 
|  | } | 
|  |  | 
|  | // __delete returns with no effect if x is null | 
|  | unittest | 
|  | { | 
|  | Object x = null; | 
|  | __delete(x); | 
|  |  | 
|  | struct S { ~this() { } } | 
|  | class C { } | 
|  | interface I { } | 
|  |  | 
|  | int[] a; __delete(a); | 
|  | S[] as; __delete(as); | 
|  | C c; __delete(c); | 
|  | I i; __delete(i); | 
|  | C* pc = &c; __delete(*pc); | 
|  | I* pi = &i; __delete(*pi); | 
|  | int* pint; __delete(pint); | 
|  | S* ps; __delete(ps); | 
|  | } | 
|  |  | 
|  | // https://issues.dlang.org/show_bug.cgi?id=19092 | 
|  | unittest | 
|  | { | 
|  | const(int)[] x = [1, 2, 3]; | 
|  | assert(GC.addrOf(x.ptr) != null); | 
|  | __delete(x); | 
|  | assert(x is null); | 
|  | assert(GC.addrOf(x.ptr) == null); | 
|  |  | 
|  | immutable(int)[] y = [1, 2, 3]; | 
|  | assert(GC.addrOf(y.ptr) != null); | 
|  | __delete(y); | 
|  | assert(y is null); | 
|  | assert(GC.addrOf(y.ptr) == null); | 
|  | } | 
|  |  | 
|  | // test realloc behaviour | 
|  | unittest | 
|  | { | 
|  | static void set(int* p, size_t size) | 
|  | { | 
|  | foreach (i; 0 .. size) | 
|  | *p++ = cast(int) i; | 
|  | } | 
|  | static void verify(int* p, size_t size) | 
|  | { | 
|  | foreach (i; 0 .. size) | 
|  | assert(*p++ == i); | 
|  | } | 
|  | static void test(size_t memsize) | 
|  | { | 
|  | int* p = cast(int*) GC.malloc(memsize * int.sizeof); | 
|  | assert(p); | 
|  | set(p, memsize); | 
|  | verify(p, memsize); | 
|  |  | 
|  | int* q = cast(int*) GC.realloc(p + 4, 2 * memsize * int.sizeof); | 
|  | assert(q == null); | 
|  |  | 
|  | q = cast(int*) GC.realloc(p + memsize / 2, 2 * memsize * int.sizeof); | 
|  | assert(q == null); | 
|  |  | 
|  | q = cast(int*) GC.realloc(p + memsize - 1, 2 * memsize * int.sizeof); | 
|  | assert(q == null); | 
|  |  | 
|  | int* r = cast(int*) GC.realloc(p, 5 * memsize * int.sizeof); | 
|  | verify(r, memsize); | 
|  | set(r, 5 * memsize); | 
|  |  | 
|  | int* s = cast(int*) GC.realloc(r, 2 * memsize * int.sizeof); | 
|  | verify(s, 2 * memsize); | 
|  |  | 
|  | assert(GC.realloc(s, 0) == null); // free | 
|  | assert(GC.addrOf(p) == null); | 
|  | } | 
|  |  | 
|  | test(16); | 
|  | test(200); | 
|  | test(800); // spans large and small pools | 
|  | test(1200); | 
|  | test(8000); | 
|  |  | 
|  | void* p = GC.malloc(100); | 
|  | assert(GC.realloc(&p, 50) == null); // non-GC pointer | 
|  | } | 
|  |  | 
|  | // test GC.profileStats | 
|  | unittest | 
|  | { | 
|  | auto stats = GC.profileStats(); | 
|  | GC.collect(); | 
|  | auto nstats = GC.profileStats(); | 
|  | assert(nstats.numCollections > stats.numCollections); | 
|  | } | 
|  |  | 
|  | // in rt.lifetime: | 
|  | private extern (C) void* _d_newitemU(scope const TypeInfo _ti) @system pure nothrow; | 
|  |  | 
|  | /** | 
|  | Moves a value to a new GC allocation. | 
|  |  | 
|  | Params: | 
|  | value = Value to be moved. If the argument is an lvalue and a struct with a | 
|  | destructor or postblit, it will be reset to its `.init` value. | 
|  |  | 
|  | Returns: | 
|  | A pointer to the new GC-allocated value. | 
|  | */ | 
|  | T* moveToGC(T)(auto ref T value) | 
|  | { | 
|  | static T* doIt(ref T value) @trusted | 
|  | { | 
|  | import core.lifetime : moveEmplace; | 
|  | auto mem = cast(T*) _d_newitemU(typeid(T)); // allocate but don't initialize | 
|  | moveEmplace(value, *mem); | 
|  | return mem; | 
|  | } | 
|  |  | 
|  | return doIt(value); // T dtor might be @system | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | struct S | 
|  | { | 
|  | int x; | 
|  | this(this) @disable; | 
|  | ~this() @safe pure nothrow @nogc {} | 
|  | } | 
|  |  | 
|  | S* p; | 
|  |  | 
|  | // rvalue | 
|  | p = moveToGC(S(123)); | 
|  | assert(p.x == 123); | 
|  |  | 
|  | // lvalue | 
|  | auto lval = S(456); | 
|  | p = moveToGC(lval); | 
|  | assert(p.x == 456); | 
|  | assert(lval.x == 0); | 
|  | } | 
|  |  | 
|  | // @system dtor | 
|  | unittest | 
|  | { | 
|  | struct S | 
|  | { | 
|  | int x; | 
|  | ~this() @system {} | 
|  | } | 
|  |  | 
|  | // lvalue case is @safe, ref param isn't destructed | 
|  | static assert(__traits(compiles, (ref S lval) @safe { moveToGC(lval); })); | 
|  |  | 
|  | // rvalue case is @system, value param is destructed | 
|  | static assert(!__traits(compiles, () @safe { moveToGC(S(0)); })); | 
|  | } |