From 3cde231456909ecb3281b19f3f767415c6cede3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Thu, 11 Jun 2026 10:32:23 +0000 Subject: [PATCH 01/10] Add some basic test cases --- .../TestLateInliningWithSliceNarrowing.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java diff --git a/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java new file mode 100644 index 0000000000000..cd554bfbe0ab5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.inlining; + +import java.lang.reflect.Field; +import java.util.Objects; +import jdk.internal.misc.Unsafe; +import jdk.test.lib.Asserts; + +/** + * @test + * @bug 8374783 + * @summary TBD + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run main ${test.main.class} + * @run main/othervm -Xbatch -XX:CompileOnly=${test.main.class}::test* + -XX:CompileCommand=dontinline,${test.main.class}::id + -XX:CompileCommand=delayinline,${test.main.class}::offset* + -XX:CompileCommand=delayinline,${test.main.class}::store + ${test.main.class} + */ + +class A { + int f; +} + +public class TestLateInliningWithSliceNarrowing { + + private static Unsafe UNSAFE = Unsafe.getUnsafe(); + private static final long F_OFFSET; + + static { + try { + Field fField = A.class.getDeclaredField("f"); + F_OFFSET = UNSAFE.objectFieldOffset(fField); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + // Not inlined. + static A id(A a) { + return a; + } + + // Inlined late. + static long offset() { + return F_OFFSET; + } + + // Inlined late. + static long offsetMinusFour() { + return F_OFFSET - 4; + } + + // Inlined late. + static long offsetDividedByTwo() { + return F_OFFSET / 2; + } + + // Inlined late. + static void store(A a) { + a.f = 42; + } + + static int testLoadFromLateDiscoveredOffsetThenStoreAtConstOffset(A a) { + long o = offset(); + int val = UNSAFE.getInt(a, o); + store(a); + return val; + } + + static int testLoadFromLateDiscoveredOffsetPlusFourThenStoreAtConstOffset(A a) { + long o = offsetMinusFour(); + int val = UNSAFE.getInt(a, o + 4); + store(a); + return val; + } + + static int testLoadFromLateDiscoveredOffsetTimesTwoThenStoreAtConstOffset(A a) { + long o = offsetDividedByTwo(); + int val = UNSAFE.getInt(a, o * 2); + store(a); + return val; + } + + static int testLoadFromLateDiscoveredOffsetThenStoreAtConstOffsetThenReloadFromConstOffset(A a) { + A a2 = id(a); + long o = offset(); + int val = UNSAFE.getInt(a, o); + store(a); + return a2.f + val; + } + + public static void main(String[] args) { + for (int i = 0; i < 10_000; i++) { + { + A a = new A(); + int result = testLoadFromLateDiscoveredOffsetThenStoreAtConstOffset(a); + Asserts.assertEquals(0, result); + } + { + A a = new A(); + int result = testLoadFromLateDiscoveredOffsetPlusFourThenStoreAtConstOffset(a); + Asserts.assertEquals(0, result); + } + { + A a = new A(); + int result = testLoadFromLateDiscoveredOffsetTimesTwoThenStoreAtConstOffset(a); + Asserts.assertEquals(0, result); + } + { + A a = new A(); + int result = testLoadFromLateDiscoveredOffsetThenStoreAtConstOffsetThenReloadFromConstOffset(a); + Asserts.assertEquals(42, result); + } + } + } +} From 782163bb93d44a9a962fa03cc2d5d59beedd3bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Thu, 11 Jun 2026 10:33:48 +0000 Subject: [PATCH 02/10] Add basic fix, guarded with UseNewCode (disabled by default) --- src/hotspot/share/opto/callGenerator.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 8209a279cb081..75965da29daea 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -729,6 +729,16 @@ void CallGenerator::do_late_inline_helper() { } C->set_inlining_progress(true); C->set_do_cleanup(kit.stopped()); // path is dead; needs cleanup + Node* result_proj = call->proj_out_or_null(TypeFunc::Parms); + if (C->inlining_incrementally() && result_proj != nullptr && UseNewCode) { + for (DUIterator_Fast imax, i = result_proj->fast_outs(imax); i < imax; i++) { + Node* use = result_proj->fast_out(i); + if (use->is_AddP() && use->in(AddPNode::Offset) == result_proj) { + C->set_do_cleanup(true); + break; + } + } + } kit.replace_call(call, result, true, do_asserts); } } From 61fdb59c4b783f8c7656b674149e4211a0aa1ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Thu, 11 Jun 2026 12:18:28 +0000 Subject: [PATCH 03/10] Rename test methods for clarity --- .../TestLateInliningWithSliceNarrowing.java | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java index cd554bfbe0ab5..9ea2af7e32d27 100644 --- a/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java +++ b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java @@ -24,7 +24,6 @@ package compiler.inlining; import java.lang.reflect.Field; -import java.util.Objects; import jdk.internal.misc.Unsafe; import jdk.test.lib.Asserts; @@ -35,10 +34,10 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * @run main ${test.main.class} - * @run main/othervm -Xbatch -XX:CompileOnly=${test.main.class}::test* - -XX:CompileCommand=dontinline,${test.main.class}::id - -XX:CompileCommand=delayinline,${test.main.class}::offset* - -XX:CompileCommand=delayinline,${test.main.class}::store + * @run main/othervm -Xbatch + -XX:CompileCommand=compileonly,${test.main.class}::test* + -XX:CompileCommand=dontinline,${test.main.class}::notInlined* + -XX:CompileCommand=delayinline,${test.main.class}::late* ${test.main.class} */ @@ -60,57 +59,52 @@ public class TestLateInliningWithSliceNarrowing { } } - // Not inlined. - static A id(A a) { + static A notInlinedId(A a) { return a; } - // Inlined late. - static long offset() { + static long lateOffset() { return F_OFFSET; } - // Inlined late. - static long offsetMinusFour() { + static long lateOffsetMinusFour() { return F_OFFSET - 4; } - // Inlined late. - static long offsetDividedByTwo() { + static long lateOffsetDividedByTwo() { return F_OFFSET / 2; } - // Inlined late. - static void store(A a) { + static void lateStore(A a) { a.f = 42; } static int testLoadFromLateDiscoveredOffsetThenStoreAtConstOffset(A a) { - long o = offset(); + long o = lateOffset(); int val = UNSAFE.getInt(a, o); - store(a); + lateStore(a); return val; } static int testLoadFromLateDiscoveredOffsetPlusFourThenStoreAtConstOffset(A a) { - long o = offsetMinusFour(); + long o = lateOffsetMinusFour(); int val = UNSAFE.getInt(a, o + 4); - store(a); + lateStore(a); return val; } static int testLoadFromLateDiscoveredOffsetTimesTwoThenStoreAtConstOffset(A a) { - long o = offsetDividedByTwo(); + long o = lateOffsetDividedByTwo(); int val = UNSAFE.getInt(a, o * 2); - store(a); + lateStore(a); return val; } static int testLoadFromLateDiscoveredOffsetThenStoreAtConstOffsetThenReloadFromConstOffset(A a) { - A a2 = id(a); - long o = offset(); + A a2 = notInlinedId(a); + long o = lateOffset(); int val = UNSAFE.getInt(a, o); - store(a); + lateStore(a); return a2.f + val; } From 5d86e81b26908ef11bb67a4ed816c9c6bb5542b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Thu, 11 Jun 2026 12:24:47 +0000 Subject: [PATCH 04/10] Add test case to cover assert in getfield parsing logic --- .../TestLateInliningWithSliceNarrowing.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java index 9ea2af7e32d27..0c2db9c36f265 100644 --- a/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java +++ b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java @@ -79,6 +79,10 @@ static void lateStore(A a) { a.f = 42; } + static int lateLoad(A a) { + return a.f; + } + static int testLoadFromLateDiscoveredOffsetThenStoreAtConstOffset(A a) { long o = lateOffset(); int val = UNSAFE.getInt(a, o); @@ -86,6 +90,13 @@ static int testLoadFromLateDiscoveredOffsetThenStoreAtConstOffset(A a) { return val; } + static int testLoadFromLateDiscoveredOffsetThenLoadFromConstOffset(A a) { + long o = lateOffset(); + int val = UNSAFE.getInt(a, o); + lateLoad(a); + return val; + } + static int testLoadFromLateDiscoveredOffsetPlusFourThenStoreAtConstOffset(A a) { long o = lateOffsetMinusFour(); int val = UNSAFE.getInt(a, o + 4); @@ -115,6 +126,11 @@ public static void main(String[] args) { int result = testLoadFromLateDiscoveredOffsetThenStoreAtConstOffset(a); Asserts.assertEquals(0, result); } + { + A a = new A(); + int result = testLoadFromLateDiscoveredOffsetThenLoadFromConstOffset(a); + Asserts.assertEquals(0, result); + } { A a = new A(); int result = testLoadFromLateDiscoveredOffsetPlusFourThenStoreAtConstOffset(a); From f4af3e8956aeba264d16d74d515b4cf071d27f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Thu, 11 Jun 2026 12:50:01 +0000 Subject: [PATCH 05/10] Comment test cases --- .../TestLateInliningWithSliceNarrowing.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java index 0c2db9c36f265..3f02fe1ccbd86 100644 --- a/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java +++ b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java @@ -30,7 +30,11 @@ /** * @test * @bug 8374783 - * @summary TBD + * @summary Test that address type refinements after an incremental inlining + * step are propagated by IGVN before the next step. Failing to + * propagate such refinements could lead to slice mismatches between + * field-derived and IGVN-recorded address types when parsing bytecode + * in subsequent inlining steps. * @library /test/lib * @modules java.base/jdk.internal.misc * @run main ${test.main.class} @@ -83,6 +87,10 @@ static int lateLoad(A a) { return a.f; } + // Test that when lateStore() is inlined, the IGVN-recorded type of the + // accessed memory address (captured by an AddP) has been updated to reflect + // the compiler-known offset discovered by inlining lateOffset(). Failure to + // do so leads to a slice mismatch when parsing the inlined store. static int testLoadFromLateDiscoveredOffsetThenStoreAtConstOffset(A a) { long o = lateOffset(); int val = UNSAFE.getInt(a, o); @@ -90,6 +98,10 @@ static int testLoadFromLateDiscoveredOffsetThenStoreAtConstOffset(A a) { return val; } + // Test that when lateLoad() is inlined, the IGVN-recorded type of the + // accessed memory address (captured by an AddP) has been updated to reflect + // the compiler-known offset discovered by inlining lateOffset(). Failure to + // do so leads to a slice mismatch when parsing the inlined load. static int testLoadFromLateDiscoveredOffsetThenLoadFromConstOffset(A a) { long o = lateOffset(); int val = UNSAFE.getInt(a, o); @@ -97,6 +109,10 @@ static int testLoadFromLateDiscoveredOffsetThenLoadFromConstOffset(A a) { return val; } + // Test a variation of the above where lateOffsetMinusFour() is not used + // directly by an AddP node. This test does not require updating the + // IGVN-recorded type of the accessed memory address for correctness, + // because lateStore() does not reuse the corresponding AddP node. static int testLoadFromLateDiscoveredOffsetPlusFourThenStoreAtConstOffset(A a) { long o = lateOffsetMinusFour(); int val = UNSAFE.getInt(a, o + 4); @@ -104,6 +120,8 @@ static int testLoadFromLateDiscoveredOffsetPlusFourThenStoreAtConstOffset(A a) { return val; } + // Test a variation of the above using a different arithmetic operation, + // with the same expectations. static int testLoadFromLateDiscoveredOffsetTimesTwoThenStoreAtConstOffset(A a) { long o = lateOffsetDividedByTwo(); int val = UNSAFE.getInt(a, o * 2); @@ -111,6 +129,10 @@ static int testLoadFromLateDiscoveredOffsetTimesTwoThenStoreAtConstOffset(A a) { return val; } + // Test a variation of the first test where failing to update the + // IGVN-recorded type of the accessed memory address would result in a slice + // mismatch that will lead to an incorrect memory graph (the memory input of + // the last load would bypass the memory output of the store). static int testLoadFromLateDiscoveredOffsetThenStoreAtConstOffsetThenReloadFromConstOffset(A a) { A a2 = notInlinedId(a); long o = lateOffset(); From d0e2759ad1d45310f6edb5841815a9919c322da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Fri, 12 Jun 2026 08:51:28 +0000 Subject: [PATCH 06/10] Add comment, reduce amount of cleanup --- src/hotspot/share/opto/callGenerator.cpp | 26 +++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 75965da29daea..7f666bbfecb61 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -729,13 +729,25 @@ void CallGenerator::do_late_inline_helper() { } C->set_inlining_progress(true); C->set_do_cleanup(kit.stopped()); // path is dead; needs cleanup - Node* result_proj = call->proj_out_or_null(TypeFunc::Parms); - if (C->inlining_incrementally() && result_proj != nullptr && UseNewCode) { - for (DUIterator_Fast imax, i = result_proj->fast_outs(imax); i < imax; i++) { - Node* use = result_proj->fast_out(i); - if (use->is_AddP() && use->in(AddPNode::Offset) == result_proj) { - C->set_do_cleanup(true); - break; + // If the specific field accessed by a memory operation is discovered after + // inlining a method incrementally, request a cleanup so that the + // corresponding IGVN-recorded address type is updated. This is not just an + // optimization: failure update the address type can lead to a slice + // mismatch when parsing subsequent accesses to the address, because the + // memory slice corresponding to *any* field of a class C is not the same as + // the slice corresponding to a specific field of C. This mismatch can in + // its turn lead to e.g. incorrect memory graphs. + if (C->inlining_incrementally() && + !result->is_top() && result->is_Con() && result->bottom_type()->isa_intptr_t() && + UseNewCode) { + Node* result_proj = call->proj_out_or_null(TypeFunc::Parms); + if (result_proj != nullptr) { + for (DUIterator_Fast imax, i = result_proj->fast_outs(imax); i < imax; i++) { + Node* use = result_proj->fast_out(i); + if (use->is_AddP() && use->in(AddPNode::Offset) == result_proj) { + C->set_do_cleanup(true); + break; + } } } } From 60587fc8e97501a4555722d4b83427dcc54c65d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Fri, 12 Jun 2026 11:26:04 +0000 Subject: [PATCH 07/10] Remove temporary guard --- src/hotspot/share/opto/callGenerator.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 7f666bbfecb61..49df03ea982c0 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -738,8 +738,7 @@ void CallGenerator::do_late_inline_helper() { // the slice corresponding to a specific field of C. This mismatch can in // its turn lead to e.g. incorrect memory graphs. if (C->inlining_incrementally() && - !result->is_top() && result->is_Con() && result->bottom_type()->isa_intptr_t() && - UseNewCode) { + !result->is_top() && result->is_Con() && result->bottom_type()->isa_intptr_t()) { Node* result_proj = call->proj_out_or_null(TypeFunc::Parms); if (result_proj != nullptr) { for (DUIterator_Fast imax, i = result_proj->fast_outs(imax); i < imax; i++) { From aca441c35b58ef926bfb26dd91d52534f909e6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Fri, 12 Jun 2026 11:47:46 +0000 Subject: [PATCH 08/10] Fix grammar glitch --- src/hotspot/share/opto/callGenerator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 49df03ea982c0..55fb931ee6ff8 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -732,10 +732,10 @@ void CallGenerator::do_late_inline_helper() { // If the specific field accessed by a memory operation is discovered after // inlining a method incrementally, request a cleanup so that the // corresponding IGVN-recorded address type is updated. This is not just an - // optimization: failure update the address type can lead to a slice + // optimization: failure to update the address type can lead to a slice // mismatch when parsing subsequent accesses to the address, because the - // memory slice corresponding to *any* field of a class C is not the same as - // the slice corresponding to a specific field of C. This mismatch can in + // memory slice corresponding to *any* field of a class K is not the same as + // the slice corresponding to a specific field of K. This mismatch can in // its turn lead to e.g. incorrect memory graphs. if (C->inlining_incrementally() && !result->is_top() && result->is_Con() && result->bottom_type()->isa_intptr_t()) { From e6bde69d8baca843019d9d0ab05b109d09a154dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Mon, 15 Jun 2026 07:19:49 +0000 Subject: [PATCH 09/10] Add test case where the base address type, rather than the offset, is discovered late --- .../TestLateInliningWithSliceNarrowing.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java index 3f02fe1ccbd86..cf044c2a04325 100644 --- a/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java +++ b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java @@ -87,6 +87,10 @@ static int lateLoad(A a) { return a.f; } + static Object lateBase(A a) { + return a; + } + // Test that when lateStore() is inlined, the IGVN-recorded type of the // accessed memory address (captured by an AddP) has been updated to reflect // the compiler-known offset discovered by inlining lateOffset(). Failure to @@ -141,6 +145,23 @@ static int testLoadFromLateDiscoveredOffsetThenStoreAtConstOffsetThenReloadFromC return a2.f + val; } + // Test a variation of the first test where the offset is compiler-known + // from the beginning, but the unsafe base address is only discovered by + // inlining lateBase(). This variation does not require a cleanup between + // the late inlining of lateBase() and lateLoad() for correctness: a slice + // mismatch cannot occur because the memory access within lateLoad() does + // not reuse the same address node (AddP) as the unsafe load. The unsafe + // load address node is not reusable by the lateLoad() access because it is + // obscured by casts by the time lateLoad() is late inlined. Making the + // address node reusable by both loads would require a cleanup round, which + // would prevent the mismatch from happening in the first place. + static int testLoadFromLateDiscoveredBaseThenLoadFromKnownBase(A a) { + Object obj = lateBase(a); + int val = UNSAFE.getInt(obj, F_OFFSET); + lateLoad(a); + return val; + } + public static void main(String[] args) { for (int i = 0; i < 10_000; i++) { { @@ -168,6 +189,11 @@ public static void main(String[] args) { int result = testLoadFromLateDiscoveredOffsetThenStoreAtConstOffsetThenReloadFromConstOffset(a); Asserts.assertEquals(42, result); } + { + A a = new A(); + int result = testLoadFromLateDiscoveredBaseThenLoadFromKnownBase(a); + Asserts.assertEquals(0, result); + } } } } From c605fa29352040739700575b24e84d5694f2eb13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Mon, 15 Jun 2026 12:48:40 +0000 Subject: [PATCH 10/10] Add test case using an array rather than a class instance --- .../TestLateInliningWithSliceNarrowing.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java index cf044c2a04325..fbae0454d0781 100644 --- a/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java +++ b/test/hotspot/jtreg/compiler/inlining/TestLateInliningWithSliceNarrowing.java @@ -53,6 +53,7 @@ public class TestLateInliningWithSliceNarrowing { private static Unsafe UNSAFE = Unsafe.getUnsafe(); private static final long F_OFFSET; + private static final long INT_ARRAY_OFFSET; static { try { @@ -61,6 +62,7 @@ public class TestLateInliningWithSliceNarrowing { } catch (Exception e) { throw new RuntimeException(e); } + INT_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(int[].class); } static A notInlinedId(A a) { @@ -79,10 +81,18 @@ static long lateOffsetDividedByTwo() { return F_OFFSET / 2; } + static long lateArrayOffset() { + return INT_ARRAY_OFFSET; + } + static void lateStore(A a) { a.f = 42; } + static void lateArrayStore(int[] a) { + a[0] = 42; + } + static int lateLoad(A a) { return a.f; } @@ -162,6 +172,17 @@ static int testLoadFromLateDiscoveredBaseThenLoadFromKnownBase(A a) { return val; } + // Test a variation of the first test using an array instead of a class + // instance. No slice mismatch occurs because the address types for both + // memory accesses lead to the same slice, regardless of whether the offset + // is compiler-known. + static int testArrayLoadFromLateDiscoveredOffsetThenStoreAtConstOffset(int[] a) { + long o = lateArrayOffset(); + int val = UNSAFE.getInt(a, o); + lateArrayStore(a); + return val; + } + public static void main(String[] args) { for (int i = 0; i < 10_000; i++) { { @@ -194,6 +215,11 @@ public static void main(String[] args) { int result = testLoadFromLateDiscoveredBaseThenLoadFromKnownBase(a); Asserts.assertEquals(0, result); } + { + int[] a = new int[1]; + int result = testArrayLoadFromLateDiscoveredOffsetThenStoreAtConstOffset(a); + Asserts.assertEquals(0, result); + } } } }