On Tue, 28 Apr 2026 06:56:15 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 thir... > > Marc Chevalier has updated the pull request with a new target base due to a > merge or a rebase. The pull request now contains 31 commits: > > - Move the flag around > - Merge remote-tracking branch lworld into JDK-8381472 > - Printing is gone again > - Remove the old way > - Fix asserts > - Let new version do the job > - Flag + using _layout_info > - Printing is back > - cosmetics > - Typo in acmp > - ... and 21 more: > https://git.openjdk.org/valhalla/compare/cfda30f3...88740943 As for performance, the microbench shows that the cost of the test is small compared to the potential win, so a small fraction of fast path should be enough for being beneficial. But there are also real benchmarks: - Renaissance-ChiSquare: the gap between mainline and valhalla with enable-preview seems to drop from 30-45% to ~20% - Renaissance-DecTree: the gap reduction is more modest, but still seems observable, from ~21% to ~18% - Renaissance-NaiveBayes: this one doesn't seem to be improved (not negatively either) I think the outcome is worth doing this fast path, especially now that the computation of the mask is much simpler. ------------- PR Comment: https://git.openjdk.org/valhalla/pull/2353#issuecomment-4334378417
