Skip to content

Commit ce39199

Browse files
authored
Merge pull request dlang#22861 from dkorpel/d-arrayop
Fix dlang#22860 - DMD emits hardcoded calls to core.atomic Signed-off-by: Nicholas Wilson <thewilsonator@users.noreply.github.com> Signed-off-by: Atila Neves <atilaneves@users.noreply.github.com> Merged-on-behalf-of: Atila Neves <atilaneves@users.noreply.github.com>
2 parents 34943f0 + 3902cc7 commit ce39199

5 files changed

Lines changed: 42 additions & 32 deletions

File tree

changelog/dmd.atomic.dd

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Shared static constructors/destructors in templates now lower to `object._d_atomicOp`
2+
3+
When a shared static constructor or destructor appears inside a template, it may
4+
be instantiated in multiple modules, causing it to run multiple times. A shared
5+
gate variable is used to count and guard executions, ensuring the body runs
6+
exactly once across all modules. The atomic operation on that gate is necessary
7+
because multiple threads may initialize modules concurrently.
8+
9+
This gate operation previously called `core.atomic.atomicOp` directly.
10+
11+
---
12+
shared static this()
13+
{
14+
if (atomicOp!"+="(gate, 1) != 1) return;
15+
// inside a template instantiation
16+
}
17+
---
18+
19+
It now lowers to `object._d_atomicOp`, consistent with how other compiler-generated
20+
runtime hooks are handled.
21+
22+
---
23+
if (.object._d_atomicOp!"+="(gate, 1) != 1) return;
24+
---

compiler/src/dmd/dsymbolsem.d

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4519,7 +4519,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
45194519
* shared int gate;
45204520
* enum op = isDestructor ? "-=" : "+=";
45214521
* enum cmp = isDestructor ? 0 : 1;
4522-
* if (core.atomic.atomicOp!op(gate, 1) != cmp) return;
4522+
* if (._d_atomicOp!op(gate, 1) != cmp) return;
45234523
* ```
45244524
*/
45254525

@@ -4532,12 +4532,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
45324532
Expression e;
45334533
if (isShared)
45344534
{
4535-
e = doAtomicOp(isDestructor ? "-=" : "+=", v.ident, IntegerExp.literal!(1));
4535+
e = doAtomicOp(isDestructor ? "-=" : "+=", v.ident, IntegerExp.literal!(1), sc);
45364536
if (e is null)
4537-
{
4538-
.error(sd.loc, "%s `%s` shared static %s within a template require `core.atomic : atomicOp` to be present", sd.kind, sd.toPrettyChars, what);
45394537
return;
4540-
}
45414538
}
45424539
else
45434540
{
@@ -7362,19 +7359,6 @@ Module loadCoreStdcConfig()
73627359
return loadModuleFromLibrary(core_stdc_config, pkgids, Id.config);
73637360
}
73647361

7365-
/****************************
7366-
* A Singleton that loads core.atomic
7367-
* Returns:
7368-
* Module of core.atomic, null if couldn't find it
7369-
*/
7370-
private Module loadCoreAtomic()
7371-
{
7372-
__gshared Module core_atomic;
7373-
auto pkgids = new Identifier[1];
7374-
pkgids[0] = Id.core;
7375-
return loadModuleFromLibrary(core_atomic, pkgids, Id.atomic);
7376-
}
7377-
73787362
/**********************************
73797363
* Load a Module from the library.
73807364
* Params:
@@ -7405,28 +7389,21 @@ extern (D) private static Module loadModuleFromLibrary(ref Module mod, Identifie
74057389
}
74067390

74077391
/// Do an atomic operation (currently tailored to [shared] static ctors|dtors) needs
7408-
private CallExp doAtomicOp (string op, Identifier var, Expression arg)
7392+
private CallExp doAtomicOp(string op, Identifier var, Expression arg, Scope* sc)
74097393
{
74107394
assert(op == "-=" || op == "+=");
74117395

7412-
Module mod = loadCoreAtomic();
7413-
if (!mod)
7414-
return null; // core.atomic couldn't be loaded
7415-
74167396
const loc = Loc.initial;
74177397

7418-
Objects* tiargs = new Objects(1);
7419-
(*tiargs)[0] = new StringExp(loc, op);
7398+
if (!verifyHookExist(loc, *sc, Id._d_atomicOp, "shared static ctors/dtors"))
7399+
return null;
74207400

7421-
Expressions* args = new Expressions(2);
7422-
(*args)[0] = new IdentifierExp(loc, var);
7423-
(*args)[1] = arg;
74247401

7425-
auto sc = new ScopeExp(loc, mod);
7426-
auto dti = new DotTemplateInstanceExp(
7427-
loc, sc, Id.atomicOp, tiargs);
7402+
Expression e = new IdentifierExp(loc, Id.empty);
7403+
e = new DotIdExp(loc, e, Id.object);
7404+
auto dti = new DotTemplateInstanceExp(loc, e, Id._d_atomicOp, new Objects(new StringExp(loc, op)));
74287405

7429-
return CallExp.create(loc, dti, args);
7406+
return CallExp.create(loc, dti, new Expressions(new IdentifierExp(loc, var), arg));
74307407
}
74317408

74327409
/***************************************************

compiler/src/dmd/frontend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8706,6 +8706,7 @@ struct Id final
87068706
static Identifier* _d_arrayassign_l;
87078707
static Identifier* _d_arrayassign_r;
87088708
static Identifier* _d_cast;
8709+
static Identifier* _d_atomicOp;
87098710
static Identifier* imported;
87108711
static Identifier* InterpolationHeader;
87118712
static Identifier* InterpolationFooter;

compiler/src/dmd/id.d

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ immutable Msgtable[] msgtable =
292292
{ "_d_arrayassign_l" },
293293
{ "_d_arrayassign_r" },
294294
{ "_d_cast" },
295+
{ "_d_atomicOp" },
295296

296297
{ "imported" },
297298
{ "InterpolationHeader" },

druntime/src/object.d

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4773,6 +4773,13 @@ auto _d_sqrt(T)(T x)
47734773
return sqrt(x);
47744774
}
47754775

4776+
// Forwarding hook for shared static ctor/dtor gate operations.
4777+
auto _d_atomicOp(string op, T, V1)(ref shared T val, V1 mod)
4778+
{
4779+
import core.atomic : atomicOp;
4780+
return atomicOp!op(val, mod);
4781+
}
4782+
47764783
public import core.lifetime : _d_newThrowable;
47774784

47784785
public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable);

0 commit comments

Comments
 (0)