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