GC and pointer masking

Erik Osterlund erik.osterlund at oracle.com
Wed May 28 13:30:34 UTC 2025


It’s worth mentioning that other GCs than ZGC use side tables as part of their barriers that assumes you can take an (address >> x) + y to get to the table element location very efficiently. This no longer works if you start encoding metadata bits in the high order bits, so the barriers would have to add software unmasking to remove the bits as part of these calculations, which presents a sort of anti optimization for GC barriers and hence increases the bar for how useful this would have to be for the GC in order to make it even a net win.

As for ZGC, we don’t have those issues really, but we have a classification scheme for color bits that is probably not widely known… we talk about persistent color bits vs transient color bits. Persistent bits are bits that stick around in the object address between loading the object reference to when it gets stored somewhere. Transient bits, conversely, are removed once loaded and restored when stored.

In the non-generational initial version of ZGC, all bits were persistent bits, implemented with multi-mapped memory. Here, HW address masking could be applied. But there wasn’t really anything in the algorithm that made it necessary for the bits we used to be persistent or transient; either one would have worked really.

As for generational ZGC, not only is the use of transient colors a preference because we got good barriers for it, but it has also allowed us to encode *field properties* instead of object properties. This is used by our remembered sets. You can have two fields with pointers to the same object, which is different in the remembered set bits, which say something about whether a store has been performed or not. These bits are important, but very impractical to encode as persistent bits as load barriers would then have to let bits for pointers pointing to the same object be different. Hence, encoding them as persistent bits would require all == (acmp etc) operations to dynamically check whether two pointers are “roughly equal” instead of exactly equal.

Since we ended up needing support for transient bits. And it turned out we didn’t really have any colors at all that actually needed to be persistent, so we made them all transient. Therefore, we have thus far not gone down this route of optimizing persistent bits. We might end up needing persistent bits in the future. But as of today, we need transient bits, and we don’t need persistent bits.

Hope this helps.

/Erik

> On 23 May 2025, at 15:18, Tony Printezis <tony at rivosinc.com> wrote:
> 
> Hi all,
> 
> Pointer masking is available for some architectures (including RISC-V!). This can allow us to mark the top bits of an object reference with what type of objects it is (young / old / humongous / etc.) without needing to clear those bits explicitly before we use the reference. This can be helpful both in the GC itself but also in the barriers (e.g., efficiently filter out young objects in barriers that are not needed on young objects).
> 
> Has anyone already looked into taking advantage of pointer masking in HotSpot? I tried a couple of searches but I didn’t find anything. If there’s been a discussion on this before, can you please point me to it?
> 
> Thanks,
> 
> Tony



More information about the hotspot-gc-dev mailing list