RFR: 8361892: AArch64: Incorrect matching rule leading to improper oop instruction encoding
Aleksey Shipilev
shade at openjdk.org
Fri Jul 11 12:44:44 UTC 2025
On Thu, 10 Jul 2025 18:29:14 GMT, Yadong Wang <yadongwang at openjdk.org> wrote:
> The bug is that the predicate rule of immByteMapBase would cause a ConP Node for oop incorrect matching with byte_map_base when the placeholder jni handle address was just allocated to the address of byte_map_base.
>
> C2 uses JNI handles as placeholders to encoding constant oops, and one of some handle maybe locate at the address of byte_map_base, which is not memory reserved by CardTable. It's possible because JNIHandleBlocks are allocated by malloc.
>
> // The assembler store_check code will do an unsigned shift of the oop,
> // then add it to _byte_map_base, i.e.
> //
> // _byte_map = _byte_map_base + (uintptr_t(low_bound) >> card_shift)
> _byte_map = (CardValue*) rs.base();
> _byte_map_base = _byte_map - (uintptr_t(low_bound) >> _card_shift);
>
> In aarch64 port, C2 will incorrectly match ConP for oop to ConP for byte_map_base by the immByteMapBase operand.
>
> // Card Table Byte Map Base
> operand immByteMapBase()
> %{
> // Get base of card map
> predicate((jbyte*)n->get_ptr() ==
> ((CardTableModRefBS*)(Universe::heap()->barrier_set()))->byte_map_base);
> match(ConP);
>
> op_cost(0);
> format %{ %}
> interface(CONST_INTER);
> %}
>
> // Load Byte Map Base Constant
> instruct loadByteMapBase(iRegPNoSp dst, immByteMapBase con)
> %{
> match(Set dst con);
>
> ins_cost(INSN_COST);
> format %{ "adr $dst, $con\t# Byte Map Base" %}
>
> ins_encode(aarch64_enc_mov_byte_map_base(dst, con));
>
> ins_pipe(ialu_imm);
> %}
>
> As below, a typical incorrect instructions generated by C2 for java.lang.ref.Finalizer.register(Ljava/lang/Object;)V (10 bytes) @ 0x0000ffff25caf0bc [0x0000ffff25caee80+0x23c], where 0xffff21730000 is the byte_map_base address mistakenly used as an object address:
> 0xffff25caf08c: ldaxr x8, [x11]
> 0xffff25caf090: cmp x10, x8
> 0xffff25caf094: b.ne 0xffff25caf0a0 // b.any
> 0xffff25caf098: stlxr w8, x28, [x11]
> 0xffff25caf09c: cbnz w8, 0xffff25caf08c
> 0xffff25caf0a0: orr x11, xzr, #0x3
> 0xffff25caf0a4: str x11, [x13]
> 0xffff25caf0a8: b.eq 0xffff25caef80 // b.none
> 0xffff25caf0ac: str x14, [sp]
> 0xffff25caf0b0: add x2, sp, #0x20
> 0xffff25caf0b4: adrp x1, 0xffff21730000
> 0xffff25caf0b8: bl 0xffff256fffc0
> 0xffff25caf0bc: ldr x14, [sp]
> 0xffff25caf0c0: b 0xffff25caef80
> 0xffff25caf0c4: add x13, sp, #0x20
> 0xffff25caf0c8: adrp x12, 0xffff21730000
> 0xffff25caf0cc: ldr x10, [x13]
> 0xffff25caf0d0: cmp x10, xzr
> 0xffff25caf0d4: b.eq 0xffff25caf130 // b.none
> 0xffff25caf0d8: ldr x11, [x12]
> 0xffff25caf0dc: tbnz w10, #1, 0xffff25caf0f...
It is such a beautiful bug to read about on Friday.
So the net effect of this mismatch is that we miss oop relocation/record when `ConP` accidentally mismatches to card table base, did I get that right?
> Yes, it maybe a better solution for jdk main line, because immPollPage was remove in https://bugs.openjdk.org/browse/JDK-8220051. But how about jdk8u backport?
I think we should do these things separately:
1. `immByteMapBase` rule removal in AArch64, this PR, then backport it to 25, 21, 17, maybe to 11, 8
2. `immByteMapBase` rule removal in RISC-V, separate PR, then backport it to 25, 21
3. `immPollPage` rule removal in AArch64, in 11u and 8u specific PRs
The backports for (1) would not be clean, as Generational Shenandoah barrier checks would likely trigger technical conflicts in the code that is being removed. So there is doubly no point in going for clean backports, we should really slice them by the rule we are removing.
-------------
PR Comment: https://git.openjdk.org/jdk/pull/26249#issuecomment-3062188862
More information about the hotspot-compiler-dev
mailing list