Repository navigation
Conversation
__traits(vtblSymbol, C) is the vtbl of class C, and __traits(interfaceSymbol, C) is the Interface[] array of class or interface C, which follows its ClassInfo. Their results, and __traits(initSymbol), are now SymbolSlice!T: a length and the address of the symbol. The special cases for the old slice-typed __traits(initSymbol) in CTFE and the glue layer are removed.
0aab637 to
624f1f1
Compare
DMD perf check
Breakdown — compile hello.d
Breakdown — compile Phobos+8.1 M instructions: frontend +4.3 M (+0.12%), codegen +3.8 M (+0.27%)
All measurements
624f1f1 vs merge-base 92ac966 · about these metrics |
dkorpel
left a comment
There was a problem hiding this comment.
As far as CTFE passing goes this looks mostly sound now, although breaking initSymbol and instantiating all these RTInfo!(SymbolSlice!(const(void))) templates does make it look less appealing in another way...
Is there an intention behind the large amount of dmd code additions (determineVtbl vtblBusy __gshared SymbolDeclaration[void*][3] declarations;) or is that just classic Claude being unaware of existing functionality and loving writing new things from scratch?
| T* ptr; | ||
|
|
||
| /// Returns: the slice | ||
| inout(T)[] get() inout @trusted pure nothrow @nogc => ptr[0 .. length]; |
There was a problem hiding this comment.
This function does not have a safe interface currently
There was a problem hiding this comment.
void main() @safe
{
SymbolSlice!(int)(20, malloc(1)).get())[7]; // Out of bounds access
}There was a problem hiding this comment.
[oops, accidentally deleted my comment rather than edit]
How not? It's the symbol length, which is quite certain and not variable.
There was a problem hiding this comment.
Oh I see; yeah it can't be const because transitive const, and therefore it could be modified (or forged!). And so, not really @safe... which sucks, because this has no reason not to be safe. Not sure how to resolve that with this approach :/
|
I agree; I don't actually love this approach; but I was trying to find the least-invasive patch. This doesn't have to apply to the init symbol, but it feels lame to me that I would certainly rather solve this with a native slice expression that worked properly... but from your last review, I figured the best approach might be to try and hoist the symbol reference out from the array. determineVtbl was necessary to flush the vtable before capturing the length; analogous to determineFields. Without that step, your examples where .length would change from one function to the next isn't solved. vtblBusy resists recursion. It could be Claude solving problems however he likes; I had my hands on the reigns pretty tight, but I don't know what I don't know... if he's invented a solution that already has an established pattern, I wouldn't know to flag that. We need code reviews by experts more than ever! |
"all these"? There's just one instance; |
|
His weird solution was to de-duplicate the symbols with that cache, so there's only ever one instance and then comparisons naturally work everywhere. Theoretically, this uses less memory than the alternative (existing way) which is be to synthesise a new node at every symbol reference, and then also proliferate a comparison function to everywhere that checks symbols for equality. The alternate solution actually isn't much more code, but it's theoretically slower; adds cost to every global symbol comparison, and also multiple symbol references duplicate the symbol node. Honestly not clear which approach is better, this cache is probably faster, maybe slightly more memory? Unless symbols are referenced multiple times, then it might be less memory...? |
Right, I thought it would instantiate for every initializer, but it's only 3 instantiations for the 3 traits |
|
ClassDeclaration already stores a vtbl symbol, and determineVtbl is basically 'dsymbolSemantic'. Here's a version instructed to remove the duplicated code and fix unsoundness issues: #23993 |
initSymbol introduced the awkward concept of forward referencing a glue layer value in the frontend. Being conservative in CTFE keeps a can of worms closed. Open it at your own risk :p |
It feels like it's solved though; opaque symbol references are already comprehensively ctfe compatible. Pinning a length beside one just doesn't seem like it should be any more trouble, although it turns out that's a COMPLETELY different thing, and so it is. The length is not from the glue layer, the length is easily known to the frontend directly, which is why we can interact with it from ctfe no problem. |
This is an alternative take on #23940, it creates an artificial slice SymbolSlice!T instead of a real proper one, that way the compiler doesn't need any extra tricks.
The disadvantage is that expressions like typeof(__traits(vtblSymbol, C)) and friends will not report (void*)[], but instead SymbolSlice!(void*), which means they may not interact completely naturally with some set of meta, but these are super-niche things, and really just to facilitate lib-defined ClassInfo; so I think we can live with that imperfection.
__traits(vtblSymbol, C)[] would cause it to present as a natural slice and work through any meta correctly.