Skip to content

Commit 6e37d62

Browse files
authored
Merge pull request #8528 from jacob-carlborg/reset-state
Add `deinitializeDMD` function to deinitialize the front end merged-on-behalf-of: unknown
2 parents fd2f4ed + 46c27f1 commit 6e37d62

11 files changed

Lines changed: 296 additions & 2 deletions

File tree

src/dmd/builtin.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,17 @@ public extern (C++) void builtin_init()
425425
add_builtin("_D4core5bitop7_popcntFNaNbNiNfmZi", &eval_popcnt);
426426
}
427427

428+
/**
429+
* Deinitializes the global state of the compiler.
430+
*
431+
* This can be used to restore the state set by `builtin_init` to its original
432+
* state.
433+
*/
434+
public void builtinDeinitialize()
435+
{
436+
builtins = builtins.init;
437+
}
438+
428439
/**********************************
429440
* Determine if function is a builtin one that we can
430441
* evaluate at compile time.

src/dmd/dmodule.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,17 @@ extern (C++) final class Module : Package
299299
modules = new DsymbolTable();
300300
}
301301

302+
/**
303+
* Deinitializes the global state of the compiler.
304+
*
305+
* This can be used to restore the state set by `_init` to its original
306+
* state.
307+
*/
308+
static void deinitialize()
309+
{
310+
modules = modules.init;
311+
}
312+
302313
extern (C++) __gshared AggregateDeclaration moduleinfo;
303314

304315
const(char)* arg; // original argument name

src/dmd/expression.d

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,22 @@ extern (C++) abstract class Expression : RootObject
640640
CTFEExp.showcontext = new CTFEExp(TOK.showCtfeContext);
641641
}
642642

643+
/**
644+
* Deinitializes the global state of the compiler.
645+
*
646+
* This can be used to restore the state set by `_init` to its original
647+
* state.
648+
*/
649+
static void deinitialize()
650+
{
651+
CTFEExp.cantexp = CTFEExp.cantexp.init;
652+
CTFEExp.voidexp = CTFEExp.voidexp.init;
653+
CTFEExp.breakexp = CTFEExp.breakexp.init;
654+
CTFEExp.continueexp = CTFEExp.continueexp.init;
655+
CTFEExp.gotoexp = CTFEExp.gotoexp.init;
656+
CTFEExp.showcontext = CTFEExp.showcontext.init;
657+
}
658+
643659
/*********************************
644660
* Does *not* do a deep copy.
645661
*/

src/dmd/frontend.d

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,35 @@ void initDMD()
7676
FileCache._init();
7777
}
7878

79+
/**
80+
Deinitializes the global variables of the DMD compiler.
81+
82+
This can be used to restore the state set by `initDMD` to its original state.
83+
Useful if there's a need for multiple sessions of the DMD compiler in the same
84+
application.
85+
*/
86+
void deinitializeDMD()
87+
{
88+
import dmd.builtin : builtinDeinitialize;
89+
import dmd.dmodule : Module;
90+
import dmd.expression : Expression;
91+
import dmd.globals : global;
92+
import dmd.id : Id;
93+
import dmd.mtype : Type;
94+
import dmd.objc : Objc;
95+
import dmd.target : target;
96+
97+
global.deinitialize();
98+
99+
Type.deinitialize();
100+
Id.deinitialize();
101+
Module.deinitialize();
102+
target.deinitialize();
103+
Expression.deinitialize();
104+
Objc.deinitialize();
105+
builtinDeinitialize();
106+
}
107+
79108
/**
80109
Add import path to the `global.path`.
81110
Params:

src/dmd/globals.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,17 @@ struct Global
404404
params.color = Console.detectTerminal();
405405
}
406406

407+
/**
408+
* Deinitializes the global state of the compiler.
409+
*
410+
* This can be used to restore the state set by `_init` to its original
411+
* state.
412+
*/
413+
void deinitialize()
414+
{
415+
this = this.init;
416+
}
417+
407418
/**
408419
Returns: the version as the number that would be returned for __VERSION__
409420
*/

src/dmd/id.d

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ struct Id
3939
{
4040
mixin(msgtable.generate(&initializer));
4141
}
42+
43+
/**
44+
* Deinitializes the global state of the compiler.
45+
*
46+
* This can be used to restore the state set by `initialize` to its original
47+
* state.
48+
*/
49+
void deinitialize()
50+
{
51+
mixin(msgtable.generate(&deinitializer));
52+
}
4253
}
4354

4455
private:
@@ -487,3 +498,9 @@ string initializer(Msgtable m)
487498
{
488499
return m.ident ~ ` = Identifier.idPool("` ~ m.name ~ `");`;
489500
}
501+
502+
// Used to generate the code for each deinitializer.
503+
string deinitializer(Msgtable m)
504+
{
505+
return m.ident ~ " = Identifier.init;";
506+
}

src/dmd/mtype.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,17 @@ extern (C++) abstract class Type : RootObject
905905
thash_t = tsize_t;
906906
}
907907

908+
/**
909+
* Deinitializes the global state of the compiler.
910+
*
911+
* This can be used to restore the state set by `_init` to its original
912+
* state.
913+
*/
914+
static void deinitialize()
915+
{
916+
stringtable = stringtable.init;
917+
}
918+
908919
final d_uns64 size()
909920
{
910921
return size(Loc.initial);

src/dmd/objc.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,17 @@ extern(C++) abstract class Objc
188188
_objc = new Unsupported;
189189
}
190190

191+
/**
192+
* Deinitializes the global state of the compiler.
193+
*
194+
* This can be used to restore the state set by `_init` to its original
195+
* state.
196+
*/
197+
static void deinitialize()
198+
{
199+
_objc = _objc.init;
200+
}
201+
191202
abstract void setObjc(ClassDeclaration cd);
192203
abstract void setObjc(InterfaceDeclaration);
193204

src/dmd/target.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,17 @@ struct Target
180180
params.isDragonFlyBSD || params.isOSX;
181181
}
182182

183+
/**
184+
* Deinitializes the global state of the compiler.
185+
*
186+
* This can be used to restore the state set by `_init` to its original
187+
* state.
188+
*/
189+
void deinitialize()
190+
{
191+
this = this.init;
192+
}
193+
183194
/**
184195
* Requested target memory alignment size of the given type.
185196
* Params:

test/unit/deinitialization.d

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
module deinitialization;
2+
3+
@("global.deinitialize")
4+
unittest
5+
{
6+
import dmd.globals : global;
7+
8+
static void assertStructsEqual(T)(const ref T a, const ref T b) @nogc pure nothrow
9+
if (is(T == struct))
10+
{
11+
foreach (i, _; typeof(a.tupleof))
12+
{
13+
enum name = __traits(identifier, a.tupleof[i]);
14+
15+
static if (is(typeof(a.tupleof[i]) == const(char*)))
16+
assert(a.tupleof[i].fromStringz == b.tupleof[i].fromStringz, name);
17+
else
18+
assert(a.tupleof[i] == b.tupleof[i], name);
19+
}
20+
}
21+
22+
immutable init = global.init;
23+
assertStructsEqual(global, init);
24+
25+
global._init();
26+
global.deinitialize();
27+
28+
assert(global == global.init);
29+
}
30+
31+
@("Type.deinitialize")
32+
unittest
33+
{
34+
import dmd.mars : addDefaultVersionIdentifiers, setTarget;
35+
import dmd.mtype : Type;
36+
import dmd.globals : global;
37+
38+
assert(Type.stringtable == Type.stringtable.init);
39+
40+
global._init();
41+
setTarget(global.params);
42+
43+
Type._init();
44+
Type.deinitialize();
45+
46+
global.deinitialize();
47+
48+
assert(Type.stringtable == Type.stringtable.init);
49+
}
50+
51+
@("Id.deinitialize")
52+
unittest
53+
{
54+
import dmd.id : Id;
55+
56+
static void assertInitialState()
57+
{
58+
foreach (e ; __traits(allMembers, Id))
59+
{
60+
static if (!__traits(isStaticFunction, mixin("Id." ~ e)))
61+
assert(__traits(getMember, Id, e) is null);
62+
}
63+
}
64+
65+
assertInitialState();
66+
67+
Id.initialize();
68+
Id.deinitialize();
69+
70+
assertInitialState();
71+
}
72+
73+
@("Module.deinitialize")
74+
unittest
75+
{
76+
import dmd.dmodule : Module;
77+
78+
assert(Module.modules is Module.modules.init);
79+
80+
Module._init();
81+
Module.deinitialize();
82+
83+
assert(Module.modules is Module.modules.init);
84+
}
85+
86+
@("Target.deinitialize")
87+
unittest
88+
{
89+
import dmd.globals : Param;
90+
import dmd.mars : setTarget;
91+
import dmd.target : target, Target;
92+
93+
static bool isFPTypeProperties(T)()
94+
{
95+
return is(T == const(typeof(Target.FloatProperties))) ||
96+
is (T == const(typeof(Target.DoubleProperties))) ||
97+
is (T == const(typeof(Target.RealProperties)));
98+
}
99+
100+
static void assertStructsEqual(T)(const ref T a, const ref T b) @nogc pure nothrow
101+
if (is(T == struct))
102+
{
103+
foreach (i, _; typeof(a.tupleof))
104+
{
105+
alias Type = typeof(a.tupleof[i]);
106+
enum name = __traits(identifier, a.tupleof[i]);
107+
108+
static if (!isFPTypeProperties!Type)
109+
assert(a.tupleof[i] == b.tupleof[i], name);
110+
}
111+
}
112+
113+
const init = target.init;
114+
assertStructsEqual(target, init);
115+
116+
Param params;
117+
setTarget(params);
118+
119+
target._init(params);
120+
target.deinitialize();
121+
122+
assertStructsEqual(target, init);
123+
}
124+
125+
@("Expression.deinitialize")
126+
unittest
127+
{
128+
import dmd.ctfeexpr : CTFEExp;
129+
import dmd.expression : Expression;
130+
131+
static void assertInitialState()
132+
{
133+
assert(CTFEExp.cantexp is null);
134+
assert(CTFEExp.voidexp is null);
135+
assert(CTFEExp.breakexp is null);
136+
assert(CTFEExp.continueexp is null);
137+
assert(CTFEExp.gotoexp is null);
138+
assert(CTFEExp.showcontext is null);
139+
}
140+
141+
assertInitialState();
142+
143+
Expression._init();
144+
Expression.deinitialize();
145+
146+
assertInitialState();
147+
}
148+
149+
@("Objc.deinitialize")
150+
unittest
151+
{
152+
import dmd.objc : Objc, objc;
153+
154+
assert(objc is null);
155+
156+
Objc._init();
157+
Objc.deinitialize();
158+
159+
assert(objc is null);
160+
}
161+
162+
private inout(char)[] fromStringz(inout(char)* cString) @nogc @system pure nothrow
163+
{
164+
import core.stdc.string : strlen;
165+
return cString ? cString[0 .. strlen(cString)] : null;
166+
}

0 commit comments

Comments
 (0)