Initialising Context Pointer during Semantic Analysis
Teodor Dutu
teodor.dutu at gmail.com
Fri Nov 25 16:10:36 UTC 2022
Hi,
For SAoC 2022, I want to translate DRuntime hooks to templates. I
am working on `_d_newitem{U,T,iT}`. The compiler uses them to
lower `new S(args)` expressions, where `S` is a `struct`.
To instantiate the new template hooks, the lowering has to be
moved from the glue layer to the semantic analysis. However, when
the constructed `struct` is nested, the lowering logic also needs
to copy the `struct`'s context pointer(s). This is currently
[handled by the glue layer in
`e2ir.d`](https://github.com/dlang/dmd/blob/6bf60ea0eb174631ede0074a77d3898d943e0b30/compiler/src/dmd/e2ir.d#L1191-L1209). Now the same logic needs to be replicated in the semantic analysis, where there is no machinery to find the right frame pointer, such as [`getEthis()` in `toir.d`](https://github.com/dlang/dmd/blob/6bf60ea0eb174631ede0074a77d3898d943e0b30/compiler/src/dmd/toir.d#L212).
After discussing with my mentors, we have come up with 2 possible
approaches:
1. Add a new AST node for copying context pointers to
`expression.d`: `ContextPointerExp`. The new lowering of `new
S(args)` in the semantic phase will insert a `ContextPointerExp`
node and then the glue layer will visit it and copy the correct
context pointer to the newly created `struct`. This approach is
efficient from a runtime perspective, as it doesn't add any
unnecessary computation, but has the disadvantage of requiring
changes beyond the frontend. Thus it won't be transparent for LDC
and GDC, who will have to handle `ContextPointerExp` in their own
glue layers.
1. Change the lowering to something like this:
```d
S* s = new S();
// lowering:
S* s = (S tmp, _d_newitem(tmp));
```
This way, `tmp`'s context pointer will be set by default and
`_d_newitem` will be able to simply copy it from `tmp` to `s` in
a way similar to
[`copyEmplace()`](https://github.com/dlang/dmd/blob/6bf60ea0eb174631ede0074a77d3898d943e0b30/druntime/src/core/lifetime.d#L1276-L1280). This solution is not without faults, though, as it requires creating and initialising `tmp` only to get its context pointer.
`void`-initialising `tmp` from the snippet above is not a
solution, as that also leaves the context pointer uninitialised.
The code below either seg faults, or prints a random value for
`s.y` because the context pointer of `s` is `null`:
```d
void main()
{
int x = 3;
struct S
{
int y;
void bar()
{
y = x;
}
}
S s = void;
s.bar();
writeln(s);
}
```
Do you see a better approach than 2? How should we handle context
pointers in the semantic phase?
Thanks,
Teo
More information about the Digitalmars-d
mailing list