digitalmars.D.learn - OK to do bit-packing with GC pointers?
- Ben Jones (50/50) Jul 22 2022 I'm looking to store a pointer to one of 2 unrelated (no
- Steven Schveighoffer (8/14) Jul 22 2022 It's specifically undefined behavior by the spec, but in practice, I
- Ben Jones (9/16) Jul 22 2022 Can you elaborate on why it's probably OK in practice?
- Steven Schveighoffer (16/24) Jul 22 2022 Because the GC deals with interior pointers just fine. Blocks with the
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (9/12) Jul 23 2022 Has nothing to do with type theory, only about GC implementation.
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (6/8) Jul 23 2022 Well, that is wrong for the standard collection where the typing
- H. S. Teoh (9/15) Jul 22 2022 https://dlang.org/spec/garbage.html#pointers_and_gc
- =?UTF-8?Q?Ali_=c3=87ehreli?= (5/6) Aug 09 2022 The slides don't seem to mention the GC but Amaury Séchet had given a
I'm looking to store a pointer to one of 2 unrelated (no inheritance relationship) classes and use the LSb to track which type I have. Is this going to cause any problems with the GC? For one of the classes I'll have a "pointer" to 1 byte past the start of the object. It seems like std.bitmanip.taggedClassRep does something similar, so I assume it's OK, but wanted to double check. Here's the type: ``` struct EitherClass(C1, C2) if (is(C1 == class) && is(C2 == class)){ private size_t data; public: safe: nogc: nothrow: this(C1 c1) trusted { data = cast(size_t)(cast(void*)(c1)); } this(C2 c2) trusted { data = cast(size_t)(cast(void*)(c2)); data |= 1; } typeof(this) opAssign(C1 c1) trusted { data = cast(size_t)(cast(void*)(c1)); return this; } typeof(this) opAssign(C2 c2) trusted { data = cast(size_t)(cast(void*)(c2)); data |= 1; return this; } bool holds(C)() const if(is(C == C1) || is(C == C2)){ static if(is(C == C1)){ return (data & 1) == 0; } else { return (data & 1) != 0; } } auto get(C)() const trusted if(is(C == C1) || is(C == C2)) { static if(is(C == C1)){ assert(holds!C1); return cast(C1)(cast(void*)(data)); } else { assert(holds!C2); return cast(C2)(cast(void*)(data & ~(1UL))); } } } ```
Jul 22 2022
On 7/22/22 12:50 PM, Ben Jones wrote:I'm looking to store a pointer to one of 2 unrelated (no inheritance relationship) classes and use the LSb to track which type I have. Is this going to cause any problems with the GC? For one of the classes I'll have a "pointer" to 1 byte past the start of the object. It seems like std.bitmanip.taggedClassRep does something similar, so I assume it's OK, but wanted to double check.It's specifically undefined behavior by the spec, but in practice, I think it will work, as long as the block you have isn't marked as not allowing interior pointers. See: https://dlang.org/spec/garbage.html#pointers_and_gc Specifically "Do not take advantage of alignment of pointers to store bit flags in the low order bits" -Steve
Jul 22 2022
On Friday, 22 July 2022 at 16:57:21 UTC, Steven Schveighoffer wrote:It's specifically undefined behavior by the spec, but in practice, I think it will work, as long as the block you have isn't marked as not allowing interior pointers. See: https://dlang.org/spec/garbage.html#pointers_and_gc Specifically "Do not take advantage of alignment of pointers to store bit flags in the low order bits" -SteveCan you elaborate on why it's probably OK in practice? I guess the alternative to is to to make them structs instead of classes and manually alloc/free them (or keep them as classes, but still avoid the GC)? Seems like std.bitmanip.taggedClassRef should have a big warning on it, right? Thanks
Jul 22 2022
On 7/22/22 2:34 PM, Ben Jones wrote:Can you elaborate on why it's probably OK in practice?Because the GC deals with interior pointers just fine. Blocks with the "no interior" bit set are very rare, and for only specialized use, so normally this should not be a problem. I have argued in the past that the spec is effectively impotent on this, since you can easily construct an equivalent pointer without bit manipulation, and the GC *must* handle this case. ```d ubyte *ptr = cast(ubyte *)intptr; ptr += lowbits; ```I guess the alternative to is to to make them structs instead of classes and manually alloc/free them (or keep them as classes, but still avoid the GC)?The alternative is to store the bits in a separate piece of memory than the poitner.Seems like std.bitmanip.taggedClassRef should have a big warning on it, right?Probably. Though like I said, I doubt it matters. Maybe someone with more type theory or GC knowledge knows whether it should be OK or not. -Steve
Jul 22 2022
On Saturday, 23 July 2022 at 00:55:14 UTC, Steven Schveighoffer wrote:Probably. Though like I said, I doubt it matters. Maybe someone with more type theory or GC knowledge knows whether it should be OK or not.Has nothing to do with type theory, only about GC implementation. But his object has no pointer in it so it should be allocated in a "no scan" heap, that can't work. Also `char*` can't work as char cannot contain pointers. I guess you would need to use `void*`. But you need to understand the internals of the GC implementation to do stuff like this.
Jul 23 2022
On Saturday, 23 July 2022 at 08:32:12 UTC, Ola Fosheim Grøstad wrote:Also `char*` can't work as char cannot contain pointers. I guess you would need to use `void*`.Well, that is wrong for the standard collection where the typing is dynamic (based on allocation not on type system). Then any pointer should work as long as it stays within the boundary of the allocated object.
Jul 23 2022
On Fri, Jul 22, 2022 at 04:50:44PM +0000, Ben Jones via Digitalmars-d-learn wrote:I'm looking to store a pointer to one of 2 unrelated (no inheritance relationship) classes and use the LSb to track which type I have. Is this going to cause any problems with the GC? For one of the classes I'll have a "pointer" to 1 byte past the start of the object. It seems like std.bitmanip.taggedClassRep does something similar, so I assume it's OK, but wanted to double check.https://dlang.org/spec/garbage.html#pointers_and_gc Section 28.3, paragraph 3 "Undefined Behaviour", 4th item: Do not take advantage of alignment of pointers to store bit flags in the low order bits: p = cast(void*)(cast(int)p | 1); // error: undefined behavior T -- Never step over a puddle, always step around it. Chances are that whatever made it is still dripping.
Jul 22 2022
On 7/22/22 09:50, Ben Jones wrote:any problems with the GC?The slides don't seem to mention the GC but Amaury Séchet had given a presentation on bit packing: http://dconf.org/2016/talks/sechet.html Ali
Aug 09 2022