Enable trapping null checks for architectures whcih cannot fold uncompress into address #227
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The Problem:
UseTrappingNullChecksPhase checks to see whether a read from an object field is guarded by an IfNode/IsNullNode and, where possible, converts the read to use an implicit null check and splices the If out of the graph. The check involves identifying whether the oop address tested by the IsNullNode equals the oop base address used by the ReadNode. When using compressed oops this can lead to failures on architectures other than x86.
If the oop value in question is a narrow oop then the IsNullNode is passed a CompressionNode. It dereferences this to store the underlying NarrowOop value as the target value to be tested for null. If this same CompressionNode is used as the base or index for the ReadNode then the comparison will not succeed unless the address lowering can optimize the address to strip the CompressionNode and employ the underlying narrowoop as it's base or index, with a suitable base + index addressing mode.
x86 is able to do this because it can generate offset loads which also apply a shift to the input address. AArch64 can use either a base + shifted index register addressing mode or a base + offset mode but cannot combine the two (I suspect the same problem arises on SPARC?). As a result the addresss equality check always fails on AArch64 causing a NullCheckNode to be inserted. The NullCheckNode is converted to an uncompress and explicit load via the resulting address. to trigger a SEGV in case the oop is null. What is worse, the following read(s) re-execute the uncompress.
The Fix:
The fix changes the comparison to detect the situation where the input base or index address to the ReadNode is a CompressionNode, indirecting through it to locate the underlying NarrowOop base/index. This ensures that a corresponding IsNullNode guard is correctly detected even when CompressionNode folding is not possible.
Testing:
I detected this problem by eyeballing the code generated for String::equals on AArch64 and x86 where StringLatin1::equals had been inlined (using compileOnly,java.lang.String*::equals). The reads of the underlying byte arrays are both implicit null candidates.
On x86 there is no difference in before and after. On AArch64 before the fix each byte array load was preceded by an uncompress, a null check load (with offset 0) and a 2nd uncompress feeding the byte array load (with offset 12). After the fix there was only a single uncompress preceding the byte array load. The latter served as an implicit null check (preceding uncompress was tagged with an OopMap).
I also reran unit tests on Aarch64 with no problems detected.