On Wed, 22 Apr 2026 13:20:27 GMT, Marc Chevalier <[email protected]> wrote:

> `acmp` for value object might be expensive: it may need substitutability 
> test, which is done through a Java call. That is the last resort when 
> everything failed, that is: we are in the presence of two value objects of 
> the same class, not statically known or speculated (profile absent or 
> polluted). While a lot of the acmp logic is trying to improve acmp at 
> compile-time, this change proposes a runtime check to take a fast path.
> 
> The idea is that if the object is small enough, we can read all the fields at 
> once with a single 8-byte load, we exclude the non-interesting bits with a 
> mask, and we can simply compare the masked value from both objects.
> 
> The first step happens at class loading. When the class is loaded, we check 
> whether all the fields can be read at once, from which offset, and the mask 
> to filter out useless bits. Useless bits may have two sources:
> - padding between fields
> - header: this happens because we cannot necessarily start reading at 
> `payload_offset`, the payload might be smaller than a long, and we could 
> overread. On the other hand, the header is always long enough (never less 
> than 8 bytes), so we may read from somewhere in the header to make sure we 
> don't go further than the payload. This piece of header must be filtered out.
> 
> This strategy may not apply if the object is too big, or if it contains an 
> oop. Loading oop without precaution, concurrently with the GC is not a good 
> idea. This limitation is rather harmless: this fast path is mostly made not 
> to pay the price of a complicated `acmp` for magically migrated classes (such 
> as `Integer`), which are small and don't contain oops.
> 
> There is an interesting corner case: the mask can be 0 for an empty value 
> class. We use a negative offset to signal that the fast path doesn't apply, 
> since it is not a valid value for the offset: we shouldn't load before the 
> object.
> 
> The second step is to prepare the runtime check. In `do_acmp`, when we used 
> to prepare the Java call, now we have a parallel fast path. The condition 
> uses the fact that we already have the class node available (used for 
> checking operands have the same types). We can get the fast acmp offset from 
> the class, check if it looks valid (that is non-negative), and if so, take 
> the fast path that will load the mask, do the two loads and masking, and 
> compare the given values. If the class of the operand is known precisely at 
> parsing, we don't emit the fast path since the call will be nicely 
> intrinsified.
> 
> The third step is to prevent the fast ...

src/hotspot/share/code/nmethod.cpp line 3464:

> 3462:                                              p2i(oops_end()),
> 3463:                                              oops_size());
> 3464:   if (mutable_data_size () > 0) st->print_cr(" mutable data   [" 
> INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",

Not actually related, but I was annoyed at the misaligned output.

src/hotspot/share/oops/instanceKlass.cpp line 4158:

> 4156:   st->print(BULLET"trans. interfaces: "); 
> transitive_interfaces()->print_value_on(st); st->cr();
> 4157: 
> 4158:   st->print(BULLET"secondary supers:  "); 
> secondary_supers()->print_value_on(st); st->cr();

More alignment issues.

-------------

PR Review Comment: 
https://git.openjdk.org/valhalla/pull/2353#discussion_r3124243181
PR Review Comment: 
https://git.openjdk.org/valhalla/pull/2353#discussion_r3124246108

Reply via email to