Thread overview
OK to do bit-packing with GC pointers?
Jul 22, 2022
Ben Jones
Jul 22, 2022
Ben Jones
Jul 22, 2022
H. S. Teoh
Aug 09, 2022
Ali Çehreli
July 22, 2022

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)));
        }
    }

}

July 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

July 22, 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.
July 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"

-Steve

Can 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

July 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.

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

July 23, 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.

July 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.

August 09, 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