Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/dmd/builtin.d
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,17 @@ public extern (C++) void builtin_init()
add_builtin("_D4core5bitop7_popcntFNaNbNiNfmZi", &eval_popcnt);
}

/**
* Deinitializes the global state of the compiler.
*
* This can be used to restore the state set by `builtin_init` to its original
* state.
*/
public void builtinDeinitialize()
Comment thread
thewilsonator marked this conversation as resolved.
{
builtins = builtins.init;
}

/**********************************
* Determine if function is a builtin one that we can
* evaluate at compile time.
Expand Down
11 changes: 11 additions & 0 deletions src/dmd/dmodule.d
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,17 @@ extern (C++) final class Module : Package
modules = new DsymbolTable();
}

/**
* Deinitializes the global state of the compiler.
*
* This can be used to restore the state set by `_init` to its original
* state.
*/
static void deinitialize()
{
modules = modules.init;
}

extern (C++) __gshared AggregateDeclaration moduleinfo;

const(char)* arg; // original argument name
Expand Down
16 changes: 16 additions & 0 deletions src/dmd/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,22 @@ extern (C++) abstract class Expression : RootObject
CTFEExp.showcontext = new CTFEExp(TOK.showCtfeContext);
}

/**
* Deinitializes the global state of the compiler.
*
* This can be used to restore the state set by `_init` to its original
* state.
*/
static void deinitialize()
{
CTFEExp.cantexp = CTFEExp.cantexp.init;
CTFEExp.voidexp = CTFEExp.voidexp.init;
CTFEExp.breakexp = CTFEExp.breakexp.init;
CTFEExp.continueexp = CTFEExp.continueexp.init;
CTFEExp.gotoexp = CTFEExp.gotoexp.init;
CTFEExp.showcontext = CTFEExp.showcontext.init;
}

/*********************************
* Does *not* do a deep copy.
*/
Expand Down
29 changes: 29 additions & 0 deletions src/dmd/frontend.d
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,35 @@ void initDMD()
FileCache._init();
}

/**
Deinitializes the global variables of the DMD compiler.

This can be used to restore the state set by `initDMD` to its original state.
Useful if there's a need for multiple sessions of the DMD compiler in the same
application.
*/
void deinitializeDMD()
{
import dmd.builtin : builtinDeinitialize;
import dmd.dmodule : Module;
import dmd.expression : Expression;
import dmd.globals : global;
import dmd.id : Id;
import dmd.mtype : Type;
import dmd.objc : Objc;
import dmd.target : target;

global.deinitialize();

Type.deinitialize();
Id.deinitialize();
Module.deinitialize();
target.deinitialize();
Expression.deinitialize();
Objc.deinitialize();
builtinDeinitialize();
}

/**
Add import path to the `global.path`.
Params:
Expand Down
11 changes: 11 additions & 0 deletions src/dmd/globals.d
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,17 @@ struct Global
params.color = Console.detectTerminal();
}

/**
* Deinitializes the global state of the compiler.
*
* This can be used to restore the state set by `_init` to its original
* state.
*/
void deinitialize()
{
this = this.init;
}

/**
Returns: the version as the number that would be returned for __VERSION__
*/
Expand Down
17 changes: 17 additions & 0 deletions src/dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ struct Id
{
mixin(msgtable.generate(&initializer));
}

/**
* Deinitializes the global state of the compiler.
*
* This can be used to restore the state set by `initialize` to its original
* state.
*/
void deinitialize()
{
mixin(msgtable.generate(&deinitializer));
}
}

private:
Expand Down Expand Up @@ -487,3 +498,9 @@ string initializer(Msgtable m)
{
return m.ident ~ ` = Identifier.idPool("` ~ m.name ~ `");`;
}

// Used to generate the code for each deinitializer.
string deinitializer(Msgtable m)
{
return m.ident ~ " = Identifier.init;";
}
11 changes: 11 additions & 0 deletions src/dmd/mtype.d
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,17 @@ extern (C++) abstract class Type : RootObject
thash_t = tsize_t;
}

/**
* Deinitializes the global state of the compiler.
*
* This can be used to restore the state set by `_init` to its original
* state.
*/
static void deinitialize()
{
stringtable = stringtable.init;
}

final d_uns64 size()
{
return size(Loc.initial);
Expand Down
11 changes: 11 additions & 0 deletions src/dmd/objc.d
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,17 @@ extern(C++) abstract class Objc
_objc = new Unsupported;
}

/**
* Deinitializes the global state of the compiler.
*
* This can be used to restore the state set by `_init` to its original
* state.
*/
static void deinitialize()
{
_objc = _objc.init;
}

abstract void setObjc(ClassDeclaration cd);
abstract void setObjc(InterfaceDeclaration);

Expand Down
11 changes: 11 additions & 0 deletions src/dmd/target.d
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,17 @@ struct Target
params.isDragonFlyBSD || params.isOSX;
}

/**
* Deinitializes the global state of the compiler.
*
* This can be used to restore the state set by `_init` to its original
* state.
*/
void deinitialize()
{
this = this.init;
}

/**
* Requested target memory alignment size of the given type.
* Params:
Expand Down
166 changes: 166 additions & 0 deletions test/unit/deinitialization.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
module deinitialization;

@("global.deinitialize")
unittest
{
import dmd.globals : global;

static void assertStructsEqual(T)(const ref T a, const ref T b) @nogc pure nothrow
if (is(T == struct))
{
foreach (i, _; typeof(a.tupleof))
{
enum name = __traits(identifier, a.tupleof[i]);

static if (is(typeof(a.tupleof[i]) == const(char*)))
assert(a.tupleof[i].fromStringz == b.tupleof[i].fromStringz, name);
else
assert(a.tupleof[i] == b.tupleof[i], name);
}
}

immutable init = global.init;
assertStructsEqual(global, init);

global._init();
global.deinitialize();

assert(global == global.init);
}

@("Type.deinitialize")
unittest
{
import dmd.mars : addDefaultVersionIdentifiers, setTarget;
import dmd.mtype : Type;
import dmd.globals : global;

assert(Type.stringtable == Type.stringtable.init);

global._init();
setTarget(global.params);

Type._init();
Type.deinitialize();

global.deinitialize();

assert(Type.stringtable == Type.stringtable.init);
}

@("Id.deinitialize")
unittest
{
import dmd.id : Id;

static void assertInitialState()
{
foreach (e ; __traits(allMembers, Id))
{
static if (!__traits(isStaticFunction, mixin("Id." ~ e)))
assert(__traits(getMember, Id, e) is null);
}
}

assertInitialState();

Id.initialize();
Id.deinitialize();

assertInitialState();
}

@("Module.deinitialize")
unittest
{
import dmd.dmodule : Module;

assert(Module.modules is Module.modules.init);

Module._init();
Module.deinitialize();

assert(Module.modules is Module.modules.init);
}

@("Target.deinitialize")
unittest
{
import dmd.globals : Param;
import dmd.mars : setTarget;
import dmd.target : target, Target;

static bool isFPTypeProperties(T)()
{
return is(T == const(typeof(Target.FloatProperties))) ||
is (T == const(typeof(Target.DoubleProperties))) ||
is (T == const(typeof(Target.RealProperties)));
}

static void assertStructsEqual(T)(const ref T a, const ref T b) @nogc pure nothrow
if (is(T == struct))
{
foreach (i, _; typeof(a.tupleof))
{
alias Type = typeof(a.tupleof[i]);
enum name = __traits(identifier, a.tupleof[i]);

static if (!isFPTypeProperties!Type)
assert(a.tupleof[i] == b.tupleof[i], name);
}
}

const init = target.init;
assertStructsEqual(target, init);

Param params;
setTarget(params);

target._init(params);
target.deinitialize();

assertStructsEqual(target, init);
}

@("Expression.deinitialize")
unittest
{
import dmd.ctfeexpr : CTFEExp;
import dmd.expression : Expression;

static void assertInitialState()
{
assert(CTFEExp.cantexp is null);
assert(CTFEExp.voidexp is null);
assert(CTFEExp.breakexp is null);
assert(CTFEExp.continueexp is null);
assert(CTFEExp.gotoexp is null);
assert(CTFEExp.showcontext is null);
}

assertInitialState();

Expression._init();
Expression.deinitialize();

assertInitialState();
}

@("Objc.deinitialize")
unittest
{
import dmd.objc : Objc, objc;

assert(objc is null);

Objc._init();
Objc.deinitialize();

assert(objc is null);
}

private inout(char)[] fromStringz(inout(char)* cString) @nogc @system pure nothrow
{
import core.stdc.string : strlen;
return cString ? cString[0 .. strlen(cString)] : null;
}
4 changes: 2 additions & 2 deletions test/unit/self_test.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import support : afterEach, beforeEach, defaultImportPaths;

@afterEach deinitializeFrontend()
{
// import dmd.frontend : deinitializeDMD;
// deinitializeDMD();
import dmd.frontend : deinitializeDMD;
deinitializeDMD();
}

@("self test")
Expand Down