Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit fb17fe9

Browse files
authored
Merge pull request #2057 from somzzz/moving_gc_init
GC Initialized on First Alloc merged-on-behalf-of: unknown
2 parents dd5fe6f + c025466 commit fb17fe9

File tree

7 files changed

+303
-19
lines changed

7 files changed

+303
-19
lines changed

changelog/lazy-gc-init.dd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
the garbage collector is now lazily initialized on first use
2+
3+
The runtime now lazily initializes the GC on first use, thus allowing applications that do not use the GC to skip its initialization.

mak/SRCS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ SRCS=\
298298
src\gc\proxy.d \
299299
src\gc\impl\conservative\gc.d \
300300
src\gc\impl\manual\gc.d \
301+
src\gc\impl\proto\gc.d \
301302
\
302303
src\rt\aApply.d \
303304
src\rt\aApplyR.d \

src/gc/impl/proto/gc.d

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
2+
module gc.impl.proto.gc;
3+
4+
import gc.config;
5+
import gc.gcinterface;
6+
7+
import rt.util.container.array;
8+
9+
import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc;
10+
static import core.memory;
11+
12+
extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; /* dmd @@@BUG11461@@@ */
13+
14+
private
15+
{
16+
extern (C) void gc_init_nothrow() nothrow @nogc;
17+
extern (C) void gc_term();
18+
19+
extern (C) void gc_enable() nothrow;
20+
extern (C) void gc_disable() nothrow;
21+
22+
extern (C) void* gc_malloc( size_t sz, uint ba = 0, const TypeInfo = null ) pure nothrow;
23+
extern (C) void* gc_calloc( size_t sz, uint ba = 0, const TypeInfo = null ) pure nothrow;
24+
extern (C) BlkInfo gc_qalloc( size_t sz, uint ba = 0, const TypeInfo = null ) pure nothrow;
25+
extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0, const TypeInfo = null ) pure nothrow;
26+
extern (C) size_t gc_reserve( size_t sz ) nothrow;
27+
28+
extern (C) void gc_addRange( void* p, size_t sz, const TypeInfo ti = null ) nothrow @nogc;
29+
extern (C) void gc_addRoot( void* p ) nothrow @nogc;
30+
}
31+
32+
class ProtoGC : GC
33+
{
34+
Array!Root roots;
35+
Array!Range ranges;
36+
37+
// Call this function when initializing the real GC
38+
// upon ProtoGC term. This function should be called
39+
// after the real GC is in place.
40+
void term()
41+
{
42+
// Transfer all ranges
43+
foreach (ref r; ranges)
44+
{
45+
// Range(p, p + sz, cast() ti)
46+
gc_addRange(r.pbot, r.ptop - r.pbot, r.ti);
47+
}
48+
49+
// Transfer all roots
50+
foreach (ref r; roots)
51+
{
52+
gc_addRoot(r.proot);
53+
}
54+
}
55+
56+
this()
57+
{
58+
}
59+
60+
void Dtor()
61+
{
62+
}
63+
64+
void enable()
65+
{
66+
gc_init_nothrow();
67+
gc_enable();
68+
}
69+
70+
void disable()
71+
{
72+
gc_init_nothrow();
73+
gc_disable();
74+
}
75+
76+
void collect() nothrow
77+
{
78+
}
79+
80+
void collectNoStack() nothrow
81+
{
82+
}
83+
84+
void minimize() nothrow
85+
{
86+
}
87+
88+
uint getAttr(void* p) nothrow
89+
{
90+
return 0;
91+
}
92+
93+
uint setAttr(void* p, uint mask) nothrow
94+
{
95+
return 0;
96+
}
97+
98+
uint clrAttr(void* p, uint mask) nothrow
99+
{
100+
return 0;
101+
}
102+
103+
void* malloc(size_t size, uint bits, const TypeInfo ti) nothrow
104+
{
105+
gc_init_nothrow();
106+
return gc_malloc(size, bits, ti);
107+
}
108+
109+
BlkInfo qalloc(size_t size, uint bits, const TypeInfo ti) nothrow
110+
{
111+
gc_init_nothrow();
112+
return gc_qalloc(size, bits, ti);
113+
}
114+
115+
void* calloc(size_t size, uint bits, const TypeInfo ti) nothrow
116+
{
117+
gc_init_nothrow();
118+
return gc_calloc(size, bits, ti);
119+
}
120+
121+
void* realloc(void* p, size_t size, uint bits, const TypeInfo ti) nothrow
122+
{
123+
gc_init_nothrow();
124+
return gc_realloc(p, size, bits, ti);
125+
}
126+
127+
size_t extend(void* p, size_t minsize, size_t maxsize, const TypeInfo ti) nothrow
128+
{
129+
return 0;
130+
}
131+
132+
size_t reserve(size_t size) nothrow
133+
{
134+
gc_init_nothrow();
135+
return reserve(size);
136+
}
137+
138+
void free(void* p) nothrow @nogc
139+
{
140+
if (p) assert(false, "Invalid memory deallocation");
141+
}
142+
143+
void* addrOf(void* p) nothrow @nogc
144+
{
145+
return null;
146+
}
147+
148+
size_t sizeOf(void* p) nothrow @nogc
149+
{
150+
return 0;
151+
}
152+
153+
BlkInfo query(void* p) nothrow
154+
{
155+
return BlkInfo.init;
156+
}
157+
158+
core.memory.GC.Stats stats() nothrow
159+
{
160+
return typeof(return).init;
161+
}
162+
163+
164+
void addRoot(void* p) nothrow @nogc
165+
{
166+
roots.insertBack(Root(p));
167+
}
168+
169+
void removeRoot(void* p) nothrow @nogc
170+
{
171+
foreach (ref r; roots)
172+
{
173+
if (r is p)
174+
{
175+
r = roots.back;
176+
roots.popBack();
177+
return;
178+
}
179+
}
180+
assert(false);
181+
}
182+
183+
@property RootIterator rootIter() return @nogc
184+
{
185+
return &rootsApply;
186+
}
187+
188+
private int rootsApply(scope int delegate(ref Root) nothrow dg)
189+
{
190+
foreach (ref r; roots)
191+
{
192+
if (auto result = dg(r))
193+
return result;
194+
}
195+
return 0;
196+
}
197+
198+
void addRange(void* p, size_t sz, const TypeInfo ti = null) nothrow @nogc
199+
{
200+
ranges.insertBack(Range(p, p + sz, cast() ti));
201+
}
202+
203+
void removeRange(void* p) nothrow @nogc
204+
{
205+
foreach (ref r; ranges)
206+
{
207+
if (r.pbot is p)
208+
{
209+
r = ranges.back;
210+
ranges.popBack();
211+
return;
212+
}
213+
}
214+
assert(false);
215+
}
216+
217+
@property RangeIterator rangeIter() return @nogc
218+
{
219+
return &rangesApply;
220+
}
221+
222+
private int rangesApply(scope int delegate(ref Range) nothrow dg)
223+
{
224+
foreach (ref r; ranges)
225+
{
226+
if (auto result = dg(r))
227+
return result;
228+
}
229+
return 0;
230+
}
231+
232+
void runFinalizers(in void[] segment) nothrow
233+
{
234+
}
235+
236+
bool inFinalizer() nothrow
237+
{
238+
return false;
239+
}
240+
}

src/gc/proxy.d

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module gc.proxy;
1515

1616
import gc.impl.conservative.gc;
1717
import gc.impl.manual.gc;
18+
import gc.impl.proto.gc;
1819
import gc.config;
1920
import gc.gcinterface;
2021

@@ -25,28 +26,55 @@ private
2526
static import core.memory;
2627
alias BlkInfo = core.memory.GC.BlkInfo;
2728

28-
__gshared GC instance;
29-
__gshared GC proxiedGC; // used to iterate roots of Windows DLLs
29+
import core.internal.spinlock;
30+
static SpinLock instanceLock;
3031

32+
__gshared bool isInstanceInit = false;
33+
__gshared GC instance = new ProtoGC();
34+
__gshared GC proxiedGC; // used to iterate roots of Windows DLLs
3135
}
3236

33-
3437
extern (C)
3538
{
36-
3739
void gc_init()
3840
{
39-
config.initialize();
40-
ManualGC.initialize(instance);
41-
ConservativeGC.initialize(instance);
42-
if (instance is null)
41+
instanceLock.lock();
42+
if (!isInstanceInit)
4343
{
44-
import core.stdc.stdio : fprintf, stderr;
45-
import core.stdc.stdlib : exit;
44+
auto protoInstance = instance;
45+
config.initialize();
46+
ManualGC.initialize(instance);
47+
ConservativeGC.initialize(instance);
48+
49+
if (instance is protoInstance)
50+
{
51+
import core.stdc.stdio : fprintf, stderr;
52+
import core.stdc.stdlib : exit;
53+
54+
fprintf(stderr, "No GC was initialized, please recheck the name of the selected GC ('%.*s').\n", cast(int)config.gc.length, config.gc.ptr);
55+
instanceLock.unlock();
56+
exit(1);
57+
58+
// Shouldn't get here.
59+
assert(0);
60+
}
61+
62+
// Transfer all ranges and roots to the real GC.
63+
(cast(ProtoGC) protoInstance).term();
64+
isInstanceInit = true;
65+
}
66+
instanceLock.unlock();
67+
}
4668

47-
fprintf(stderr, "No GC was initialized, please recheck the name of the selected GC ('%.*s').\n", cast(int)config.gc.length, config.gc.ptr);
48-
exit(1);
69+
void gc_init_nothrow() nothrow
70+
{
71+
scope(failure)
72+
{
73+
import core.internal.abort;
74+
abort("Cannot initialize the garbage collector.\n");
75+
assert(0);
4976
}
77+
gc_init();
5078
}
5179

5280
void gc_term()
@@ -61,11 +89,14 @@ extern (C)
6189
// NOTE: Due to popular demand, this has been re-enabled. It still has
6290
// the problems mentioned above though, so I guess we'll see.
6391

64-
instance.collectNoStack(); // not really a 'collect all' -- still scans
65-
// static data area, roots, and ranges.
92+
if (isInstanceInit)
93+
{
94+
instance.collectNoStack(); // not really a 'collect all' -- still scans
95+
// static data area, roots, and ranges.
6696

67-
ManualGC.finalize(instance);
68-
ConservativeGC.finalize(instance);
97+
ManualGC.finalize(instance);
98+
ConservativeGC.finalize(instance);
99+
}
69100
}
70101

71102
void gc_enable()
@@ -158,12 +189,12 @@ extern (C)
158189
return instance.stats();
159190
}
160191

161-
void gc_addRoot( void* p ) nothrow
192+
void gc_addRoot( void* p ) nothrow @nogc
162193
{
163194
return instance.addRoot( p );
164195
}
165196

166-
void gc_addRange( void* p, size_t sz, const TypeInfo ti = null ) nothrow
197+
void gc_addRange( void* p, size_t sz, const TypeInfo ti = null ) nothrow @nogc
167198
{
168199
return instance.addRange( p, sz, ti );
169200
}

src/rt/dmain2.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ extern (C) int rt_init()
197197
// in other druntime systems.
198198
_d_initMonoTime();
199199
thread_init();
200-
gc_init();
200+
// TODO: fixme - calls GC.addRange -> Initializes GC
201201
initStaticDataGC();
202202
lifetime_init();
203203
rt_moduleCtor();

test/exceptions/src/unknown_gc.d

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
import core.memory;
2+
13
extern(C) __gshared string[] rt_options = [ "gcopt=gc:unknowngc" ];
24

35
void main()
46
{
7+
// GC initialized upon first call -> Unknown GC error is thrown
8+
GC.enable();
59
}

test/nogc.d

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extern(C) __gshared string[] rt_options = [ "gcopt=gc:non-existing" ];
2+
3+
void main() @nogc
4+
{
5+
}

0 commit comments

Comments
 (0)