2 * Allocate memory using `malloc` or the GC depending on the configuration.
4 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
5 * Authors: Walter Bright, https://www.digitalmars.com
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.d, root/_rmem.d)
8 * Documentation: https://dlang.org/phobos/dmd_root_rmem.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/rmem.d
14 import core
.exception
: onOutOfMemoryError
;
15 import core
.stdc
.stdio
;
16 import core
.stdc
.stdlib
;
17 import core
.stdc
.string
;
19 import core
.memory
: GC
;
21 extern (C
++) struct Mem
23 static char* xstrdup(const(char)* s
) nothrow
26 return s ? s
[0 .. strlen(s
) + 1].dup
.ptr
: null;
28 return s ?
cast(char*)check(.strdup(s
)) : null;
31 static void xfree(void* p
) pure nothrow
39 static void* xmalloc(size_t size
) pure nothrow
42 return size ? GC
.malloc(size
) : null;
44 return size ?
check(pureMalloc(size
)) : null;
47 static void* xmalloc_noscan(size_t size
) pure nothrow
50 return size ? GC
.malloc(size
, GC
.BlkAttr
.NO_SCAN
) : null;
52 return size ?
check(pureMalloc(size
)) : null;
55 static void* xcalloc(size_t size
, size_t n
) pure nothrow
58 return size
* n ? GC
.calloc(size
* n
) : null;
60 return (size
&& n
) ?
check(pureCalloc(size
, n
)) : null;
63 static void* xcalloc_noscan(size_t size
, size_t n
) pure nothrow
66 return size
* n ? GC
.calloc(size
* n
, GC
.BlkAttr
.NO_SCAN
) : null;
68 return (size
&& n
) ?
check(pureCalloc(size
, n
)) : null;
71 static void* xrealloc(void* p
, size_t size
) pure nothrow
74 return GC
.realloc(p
, size
);
82 return check(pureRealloc(p
, size
));
85 static void* xrealloc_noscan(void* p
, size_t size
) pure nothrow
88 return GC
.realloc(p
, size
, GC
.BlkAttr
.NO_SCAN
);
96 return check(pureRealloc(p
, size
));
99 static void* error() pure nothrow @nogc @safe
101 onOutOfMemoryError();
106 * Check p for null. If it is, issue out of memory error
109 * p = pointer to check for null
113 static void* check(void* p
) pure nothrow @nogc @safe
115 return p ? p
: error();
118 __gshared
bool _isGCEnabled
= true;
120 // fake purity by making global variable immutable (_isGCEnabled only modified before startup)
121 enum _pIsGCEnabled
= cast(immutable bool*) &_isGCEnabled
;
123 static bool isGCEnabled() pure nothrow @nogc @safe
125 return *_pIsGCEnabled
;
128 static void disableGC() nothrow @nogc
130 _isGCEnabled
= false;
133 static void addRange(const(void)* p
, size_t size
) nothrow @nogc
136 GC
.addRange(p
, size
);
139 static void removeRange(const(void)* p
) nothrow @nogc
146 extern (C
++) const __gshared Mem mem
;
148 enum CHUNK_SIZE
= (256 * 4096 - 64);
150 __gshared size_t heapleft
= 0;
151 __gshared
void* heapp
;
153 extern (D
) void* allocmemoryNoFree(size_t m_size
) nothrow @nogc
155 // 16 byte alignment is better (and sometimes needed) for doubles
156 m_size
= (m_size
+ 15) & ~15;
158 // The layout of the code is selected so the most common case is straight through
159 if (m_size
<= heapleft
)
164 heapp
= cast(void*)(cast(char*)heapp
+ m_size
);
168 if (m_size
> CHUNK_SIZE
)
170 return Mem
.check(malloc(m_size
));
173 heapleft
= CHUNK_SIZE
;
174 heapp
= Mem
.check(malloc(CHUNK_SIZE
));
178 extern (D
) void* allocmemory(size_t m_size
) nothrow
181 return GC
.malloc(m_size
);
183 return allocmemoryNoFree(m_size
);
186 version (DigitalMars
)
188 enum OVERRIDE_MEMALLOC
= true;
192 // Memory allocation functions gained weak linkage when the @weak attribute was introduced.
193 import ldc
.attributes
;
194 enum OVERRIDE_MEMALLOC
= is(typeof(ldc
.attributes
.weak
));
199 enum OVERRIDE_MEMALLOC
= false;
201 enum OVERRIDE_MEMALLOC
= true;
205 enum OVERRIDE_MEMALLOC
= false;
208 static if (OVERRIDE_MEMALLOC
)
210 // Override the host druntime allocation functions in order to use the bump-
211 // pointer allocation scheme (`allocmemoryNoFree()` above) if the GC is disabled.
212 // That scheme is faster and comes with less memory overhead than using a
213 // disabled GC alone.
215 extern (C
) void* _d_allocmemory(size_t m_size
) nothrow
217 return allocmemory(m_size
);
220 private void* allocClass(const ClassInfo ci
) nothrow pure
222 alias BlkAttr
= GC
.BlkAttr
;
224 assert(!(ci
.m_flags
& TypeInfo_Class
.ClassFlags
.isCOMclass
));
226 BlkAttr attr
= BlkAttr
.NONE
;
227 if (ci
.m_flags
& TypeInfo_Class
.ClassFlags
.hasDtor
228 && !(ci
.m_flags
& TypeInfo_Class
.ClassFlags
.isCPPclass
))
229 attr |
= BlkAttr
.FINALIZE
;
230 if (ci
.m_flags
& TypeInfo_Class
.ClassFlags
.noPointers
)
231 attr |
= BlkAttr
.NO_SCAN
;
232 return GC
.malloc(ci
.initializer
.length
, attr
, ci
);
235 extern (C
) void* _d_newitemU(const TypeInfo ti
) nothrow;
237 extern (C
) Object
_d_newclass(const ClassInfo ci
) nothrow
239 const initializer
= ci
.initializer
;
241 auto p
= mem
.isGCEnabled ?
allocClass(ci
) : allocmemoryNoFree(initializer
.length
);
242 memcpy(p
, initializer
.ptr
, initializer
.length
);
243 return cast(Object
) p
;
248 extern (C
) Object
_d_allocclass(const ClassInfo ci
) nothrow
251 return cast(Object
) allocClass(ci
);
253 return cast(Object
) allocmemoryNoFree(ci
.initializer
.length
);
257 extern (C
) void* _d_newitemT(TypeInfo ti
) nothrow
259 auto p
= mem
.isGCEnabled ?
_d_newitemU(ti
) : allocmemoryNoFree(ti
.tsize
);
260 memset(p
, 0, ti
.tsize
);
264 extern (C
) void* _d_newitemiT(TypeInfo ti
) nothrow
266 auto p
= mem
.isGCEnabled ?
_d_newitemU(ti
) : allocmemoryNoFree(ti
.tsize
);
267 const initializer
= ti
.initializer
;
268 memcpy(p
, initializer
.ptr
, initializer
.length
);
272 // TypeInfo.initializer for compilers older than 2.070
273 static if(!__traits(hasMember
, TypeInfo
, "initializer"))
274 private const(void[]) initializer(T
: TypeInfo
)(const T t
)
275 nothrow pure @safe @nogc
281 extern (C
) pure @nogc nothrow
284 * Pure variants of C's memory allocation functions `malloc`, `calloc`, and
285 * `realloc` and deallocation function `free`.
287 * UNIX 98 requires that errno be set to ENOMEM upon failure.
288 * https://linux.die.net/man/3/malloc
289 * However, this is irrelevant for DMD's purposes, and best practice
290 * protocol for using errno is to treat it as an `out` parameter, and not
291 * something with state that can be relied on across function calls.
292 * So, we'll ignore it.
295 * $(LINK2 https://dlang.org/spec/function.html#pure-functions, D's rules for purity),
296 * which allow for memory allocation under specific circumstances.
298 pragma(mangle
, "malloc") void* pureMalloc(size_t size
) @trusted;
301 pragma(mangle
, "calloc") void* pureCalloc(size_t nmemb
, size_t size
) @trusted;
304 pragma(mangle
, "realloc") void* pureRealloc(void* ptr
, size_t size
) @system;
307 pragma(mangle
, "free") void pureFree(void* ptr
) @system;
312 Makes a null-terminated copy of the given string on newly allocated memory.
313 The null-terminator won't be part of the returned string slice. It will be
314 at position `n` where `n` is the length of the input string.
319 Returns: A null-terminated copy of the input array.
321 extern (D
) char[] xarraydup(const(char)[] s
) pure nothrow
326 auto p
= cast(char*)mem
.xmalloc_noscan(s
.length
+ 1);
327 char[] a
= p
[0 .. s
.length
];
328 a
[] = s
[0 .. s
.length
];
329 p
[s
.length
] = 0; // preserve 0 terminator semantics
334 pure nothrow unittest
337 auto s2
= s1
.xarraydup
;
341 assert(*(s2
.ptr
+ s2
.length
) == '\0');
343 assert(sEmpty
.xarraydup
is null);
347 Makes a copy of the given array on newly allocated memory.
352 Returns: A copy of the input array.
354 extern (D
) T
[] arraydup(T
)(const scope T
[] s
) pure nothrow
359 const dim
= s
.length
;
360 auto p
= (cast(T
*)mem
.xmalloc(T
.sizeof
* dim
))[0 .. dim
];
366 pure nothrow unittest
369 auto s2
= s1
.arraydup
;
371 assert(s1
== [0, 1, 2]);
372 assert(s2
== [4, 1, 2]);
374 assert(sEmpty
.arraydup
is null);