d: Merge dmd, druntime d8e3976a58, phobos 7a6e95688
[official-gcc.git] / gcc / d / dmd / root / rmem.d
blob19652072376bf52b043fd50523366b9715b898d0
1 /**
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
12 module dmd.root.rmem;
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
25 if (isGCEnabled)
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
33 if (isGCEnabled)
34 return GC.free(p);
36 pureFree(p);
39 static void* xmalloc(size_t size) pure nothrow
41 if (isGCEnabled)
42 return size ? GC.malloc(size) : null;
44 return size ? check(pureMalloc(size)) : null;
47 static void* xmalloc_noscan(size_t size) pure nothrow
49 if (isGCEnabled)
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
57 if (isGCEnabled)
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
65 if (isGCEnabled)
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
73 if (isGCEnabled)
74 return GC.realloc(p, size);
76 if (!size)
78 pureFree(p);
79 return null;
82 return check(pureRealloc(p, size));
85 static void* xrealloc_noscan(void* p, size_t size) pure nothrow
87 if (isGCEnabled)
88 return GC.realloc(p, size, GC.BlkAttr.NO_SCAN);
90 if (!size)
92 pureFree(p);
93 return null;
96 return check(pureRealloc(p, size));
99 static void* error() pure nothrow @nogc @safe
101 onOutOfMemoryError();
102 assert(0);
106 * Check p for null. If it is, issue out of memory error
107 * and exit program.
108 * Params:
109 * p = pointer to check for null
110 * Returns:
111 * p if not 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
135 if (isGCEnabled)
136 GC.addRange(p, size);
139 static void removeRange(const(void)* p) nothrow @nogc
141 if (isGCEnabled)
142 GC.removeRange(p);
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)
162 heapleft -= m_size;
163 auto p = heapp;
164 heapp = cast(void*)(cast(char*)heapp + m_size);
165 return p;
168 if (m_size > CHUNK_SIZE)
170 return Mem.check(malloc(m_size));
173 heapleft = CHUNK_SIZE;
174 heapp = Mem.check(malloc(CHUNK_SIZE));
175 goto L1;
178 extern (D) void* allocmemory(size_t m_size) nothrow
180 if (mem.isGCEnabled)
181 return GC.malloc(m_size);
183 return allocmemoryNoFree(m_size);
186 version (DigitalMars)
188 enum OVERRIDE_MEMALLOC = true;
190 else version (LDC)
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));
196 else version (GNU)
198 version (IN_GCC)
199 enum OVERRIDE_MEMALLOC = false;
200 else
201 enum OVERRIDE_MEMALLOC = true;
203 else
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;
246 version (LDC)
248 extern (C) Object _d_allocclass(const ClassInfo ci) nothrow
250 if (mem.isGCEnabled)
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);
261 return p;
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);
269 return p;
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
277 return t.init;
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.
294 * See_Also:
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;
300 /// ditto
301 pragma(mangle, "calloc") void* pureCalloc(size_t nmemb, size_t size) @trusted;
303 /// ditto
304 pragma(mangle, "realloc") void* pureRealloc(void* ptr, size_t size) @system;
306 /// ditto
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.
316 Params:
317 s = string to copy
319 Returns: A null-terminated copy of the input array.
321 extern (D) char[] xarraydup(const(char)[] s) pure nothrow
323 if (!s)
324 return null;
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
330 return a;
334 pure nothrow unittest
336 auto s1 = "foo";
337 auto s2 = s1.xarraydup;
338 s2[0] = 'b';
339 assert(s1 == "foo");
340 assert(s2 == "boo");
341 assert(*(s2.ptr + s2.length) == '\0');
342 string sEmpty;
343 assert(sEmpty.xarraydup is null);
347 Makes a copy of the given array on newly allocated memory.
349 Params:
350 s = array to copy
352 Returns: A copy of the input array.
354 extern (D) T[] arraydup(T)(const scope T[] s) pure nothrow
356 if (!s)
357 return null;
359 const dim = s.length;
360 auto p = (cast(T*)mem.xmalloc(T.sizeof * dim))[0 .. dim];
361 p[] = s;
362 return p;
366 pure nothrow unittest
368 auto s1 = [0, 1, 2];
369 auto s2 = s1.arraydup;
370 s2[0] = 4;
371 assert(s1 == [0, 1, 2]);
372 assert(s2 == [4, 1, 2]);
373 string sEmpty;
374 assert(sEmpty.arraydup is null);