From 62b3ad290c0d29e9534423831db3482a7d8f234e Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 30 Apr 2024 21:56:16 +0200 Subject: [PATCH 1/5] emit nmethod entry barriers in JVMCI assembler tests --- .../share/jvmci/jvmciCodeInstaller.cpp | 2 +- .../vm/ci/code/test/SimpleDebugInfoTest.java | 1 + .../jdk/vm/ci/code/test/TestAssembler.java | 77 +++++++++++++ .../vm/ci/code/test/TestHotSpotVMConfig.java | 28 +++++ .../test/aarch64/AArch64TestAssembler.java | 107 +++++++++++++++++- .../code/test/amd64/AMD64TestAssembler.java | 91 +++++++++++++++ 6 files changed, 301 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 7dd2840656dc7..07c48ae9af3e4 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -775,7 +775,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, // configurations which generate assembly without being a full compiler. So for now we enforce // that JIT compiled methods must have an nmethod barrier. bool install_default = JVMCIENV->get_HotSpotNmethod_isDefault(installed_code) != 0; - if (_nmethod_entry_patch_offset == -1 && install_default) { + if (_nmethod_entry_patch_offset == -1) { JVMCI_THROW_MSG_(IllegalArgumentException, "nmethod entry barrier is missing", JVMCI::ok); } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java index c7d8d2cf83064..1c88fd1db0836 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java @@ -27,6 +27,7 @@ * @requires vm.simpleArch == "x64" | vm.simpleArch == "aarch64" | vm.simpleArch == "riscv64" * @library / * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot + * jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64 * jdk.internal.vm.ci/jdk.vm.ci.meta * jdk.internal.vm.ci/jdk.vm.ci.code * jdk.internal.vm.ci/jdk.vm.ci.code.site diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java index f1afef3bae2d0..6a4f6addd0d07 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java @@ -243,6 +243,27 @@ protected TestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config, this.curStackSlot = initialFrameSize; } + public class Bookmark implements AutoCloseable { + private final int registerMark = nextRegister; + private final int codePos = code.position(); + private final int dataPos = data.position(); + + @Override + public void close() { + nextRegister = registerMark; + code.data.position(codePos); + data.data.position(dataPos); + } + } + + /** + * Enters a scope in which the current register, code and data emitting state + * is restored upon leaving the scope. + */ + public Bookmark bookmark() { + return new Bookmark(); + } + public ValueKind getValueKind(JavaKind kind) { return new TestValueKind(codeCache.getTarget().arch.getPlatformKind(kind)); } @@ -296,6 +317,18 @@ protected void recordDataPatchInData(Reference ref) { dataPatches.add(new DataPatch(data.position(), ref)); } + /** + * Emits the 32 bit constant `c` into the data section. + */ + public DataSectionReference emitDataItem(int c) { + DataSectionReference ref = new DataSectionReference(); + ref.setOffset(data.position()); + + recordDataPatchInCode(ref); + data.emitInt(c); + return ref; + } + public DataSectionReference emitDataItem(HotSpotConstant c) { DataSectionReference ref = new DataSectionReference(); ref.setOffset(data.position()); @@ -321,6 +354,50 @@ public HotSpotCompiledCode finish(HotSpotResolvedJavaMethod method) { finishedDataPatches, false, frameSize, deoptRescue, method, -1, id, 0L, false); } + /** + * @param n Number of bits that should be set to 1. Must be between 0 and 32 (inclusive). + * @return A number with n bits set to 1. + */ + public static int getNbitNumberInt(int n) { + assert n >= 0 && n <= 32 : "0 <= n <= 32; instead: " + n; + if (n < 32) { + return (1 << n) - 1; + } else { + return 0xFFFFFFFF; + } + } + + public static boolean isSignedNbit(int n, int value) { + assert n > 0 && n < 32 : n; + int min = -(1 << (n - 1)); + int max = (1 << (n - 1)) - 1; + return value >= min && value <= max; + } + + public static boolean isUnsignedNbit(int n, int value) { + assert n > 0 && n < 32 : n; + return 32 - Integer.numberOfLeadingZeros(value) <= n; + } + + /** + * Determines if `x` is in the range of signed byte values. + */ + public static boolean isByte(int x) { + return (byte) x == x; + } + + /** + * Determines if `l` is in the range of signed int values. + */ + public static boolean isInt(long l) { + return (int) l == l; + } + + public static void check(boolean condition, String errorMessage, Object... args) { + if (!condition) { + throw new AssertionError(errorMessage.formatted(args)); + } + } protected static class Buffer { private ByteBuffer data = ByteBuffer.allocate(32).order(ByteOrder.nativeOrder()); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java index 9468027bc85b0..12664bd433f3d 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java @@ -32,6 +32,7 @@ public class TestHotSpotVMConfig extends HotSpotVMConfigAccess { public TestHotSpotVMConfig(HotSpotVMConfigStore config, Architecture arch) { super(config); ropProtection = (arch instanceof AArch64) ? getFieldValue("VM_Version::_rop_protection", Boolean.class) : false; + nmethodEntryBarrierConcurrentPatch = initNmethodEntryBarrierConcurrentPatch(arch); } public final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); @@ -47,10 +48,37 @@ public TestHotSpotVMConfig(HotSpotVMConfigStore config, Architecture arch) { // Checkstyle: stop public final int MARKID_DEOPT_HANDLER_ENTRY = getConstant("CodeInstaller::DEOPT_HANDLER_ENTRY", Integer.class); + public final int MARKID_FRAME_COMPLETE = getConstant("CodeInstaller::FRAME_COMPLETE", Integer.class); + public final int MARKID_ENTRY_BARRIER_PATCH = getConstant("CodeInstaller::ENTRY_BARRIER_PATCH", Integer.class); public final long handleDeoptStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", Long.class, "address"); public final int maxOopMapStackOffset = getFieldValue("CompilerToVM::Data::_max_oop_map_stack_offset", Integer.class, "int"); public final int heapWordSize = getConstant("HeapWordSize", Integer.class); public final boolean ropProtection; + + private Boolean initNmethodEntryBarrierConcurrentPatch(Architecture arch) { + Boolean patchConcurrent = null; + if (arch instanceof AArch64 && nmethodEntryBarrier != 0) { + Integer patchingType = getFieldValue("CompilerToVM::Data::BarrierSetAssembler_nmethod_patching_type", Integer.class, "int"); + if (patchingType != null) { + // There currently only 2 variants in use that differ only by the presence of a + // dmb instruction + int stw = getConstant("NMethodPatchingType::stw_instruction_and_data_patch", Integer.class); + int conc = getConstant("NMethodPatchingType::conc_data_patch", Integer.class); + if (patchingType == stw) { + patchConcurrent = false; + } else if (patchingType == conc) { + patchConcurrent = true; + } else { + throw new IllegalArgumentException("unsupported barrier sequence " + patchingType); + } + } + } + return patchConcurrent; + } + + public final int threadDisarmedOffset = getFieldValue("CompilerToVM::Data::thread_disarmed_guard_value_offset", Integer.class, "int"); + public final long nmethodEntryBarrier = getFieldValue("CompilerToVM::Data::nmethod_entry_barrier", Long.class, "address"); + public final Boolean nmethodEntryBarrierConcurrentPatch; } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java index e87944f3ca9ec..2ba1188989035 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java @@ -36,6 +36,7 @@ import jdk.vm.ci.code.site.DataSectionReference; import jdk.vm.ci.code.test.TestAssembler; import jdk.vm.ci.code.test.TestHotSpotVMConfig; +import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig; import jdk.vm.ci.hotspot.HotSpotCallingConventionType; import jdk.vm.ci.hotspot.HotSpotConstant; import jdk.vm.ci.hotspot.HotSpotForeignCallTarget; @@ -46,8 +47,69 @@ public class AArch64TestAssembler extends TestAssembler { private static final Register scratchRegister = AArch64.rscratch1; + private static final Register scratchRegister2 = AArch64.rscratch2; private static final Register doubleScratch = AArch64.v9; + /** + * Condition Flags for branches. See C1.2.4 + */ + public enum ConditionFlag { + // Integer | Floating-point meanings + /** Equal | Equal. */ + EQ(0x0), + + /** Not Equal | Not equal or unordered. */ + NE(0x1), + + /** Unsigned Higher or Same | Greater than, equal or unordered. */ + HS(0x2), + + /** Unsigned lower | less than. */ + LO(0x3), + + /** Minus (negative) | less than. */ + MI(0x4), + + /** Plus (positive or zero) | greater than, equal or unordered. */ + PL(0x5), + + /** Overflow set | unordered. */ + VS(0x6), + + /** Overflow clear | ordered. */ + VC(0x7), + + /** Unsigned higher | greater than or unordered. */ + HI(0x8), + + /** Unsigned lower or same | less than or equal. */ + LS(0x9), + + /** Signed greater than or equal | greater than or equal. */ + GE(0xA), + + /** Signed less than | less than or unordered. */ + LT(0xB), + + /** Signed greater than | greater than. */ + GT(0xC), + + /** Signed less than or equal | less than, equal or unordered. */ + LE(0xD), + + /** Always | always. */ + AL(0xE), + + /** Always | always (identical to AL, just to have valid 0b1111 encoding). */ + NV(0xF); + + public final int encoding; + + ConditionFlag(int encoding) { + this.encoding = encoding; + } + } + public AArch64TestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config) { super(codeCache, config, 16 /* initialFrameSize */, 16 /* stackAlignment */, @@ -215,6 +277,22 @@ private void emitBlr(Register Rn) { | f(0, 4, 0)); } + /** + * C6.2.25 Branch conditionally. + * + * @param condition may not be null. + * @param imm21 Signed 21-bit offset, has to be 4-byte aligned. + */ + protected void emitBranch(ConditionFlag condition, int imm21) { + // B.cond + check(isSignedNbit(21, imm21) && (imm21 & 0b11) == 0, + "0x%x must be a 21-bit signed number and 4-byte aligned", imm21); + int imm19 = (imm21 & getNbitNumberInt(21)) >> 2; + code.emitInt(f(0b001010100, 31, 24) + | f(imm19, 23, 4) + | f(condition.encoding, 3, 0)); + } + private void emitFmov(Register Rd, AArch64Kind kind, Register Rn) { // FMOV (general) int ftype = 0, sf = 0; @@ -261,9 +339,24 @@ public void emitPrologue() { code.emitInt(0xa9bf7bfd); // stp x29, x30, [sp, #-16]! code.emitInt(0x910003fd); // mov x29, sp + emitNMethodEntryBarrier(); + setDeoptRescueSlot(newStackSlot(AArch64Kind.QWORD)); } + private void emitNMethodEntryBarrier() { + recordMark(config.MARKID_ENTRY_BARRIER_PATCH); + DataSectionReference ref = emitDataItem(0); + emitLoadPointer(scratchRegister, AArch64Kind.DWORD, ref); + if (config.nmethodEntryBarrierConcurrentPatch) { + code.emitInt(0xd50339bf); // dmb ishld + } + emitLoadPointer(scratchRegister2, AArch64Kind.DWORD, AArch64HotSpotRegisterConfig.threadRegister, config.threadDisarmedOffset); + code.emitInt(0x6b09011f); // cmp w8, w9 + emitBranch(ConditionFlag.EQ, 8); // jump over slow path, runtime call + emitCall(config.nmethodEntryBarrier); + } + @Override public void emitEpilogue() { recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); @@ -361,8 +454,11 @@ public Register emitLoadPointer(HotSpotConstant c) { @Override public Register emitLoadPointer(Register b, int offset) { - Register ret = newRegister(); - emitLoadRegister(ret, AArch64Kind.QWORD, b, offset); + return emitLoadPointer(newRegister(), AArch64Kind.QWORD, b, offset); + } + + public Register emitLoadPointer(Register ret, AArch64Kind kind, Register b, int offset) { + emitLoadRegister(ret, kind, b, offset); return ret; } @@ -377,10 +473,13 @@ public Register emitLoadNarrowPointer(DataSectionReference ref) { @Override public Register emitLoadPointer(DataSectionReference ref) { + return emitLoadPointer(newRegister(), AArch64Kind.QWORD, ref); + } + + public Register emitLoadPointer(Register ret, AArch64Kind kind, DataSectionReference ref) { recordDataPatchInCode(ref); - Register ret = newRegister(); - emitLoadRegister(ret, AArch64Kind.QWORD, 0xdead); + emitLoadRegister(ret, kind, 0xdead); return ret; } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java index a0fcdd2b0a988..4902719453290 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java @@ -49,6 +49,40 @@ public class AMD64TestAssembler extends TestAssembler { private static final Register scratchRegister = AMD64.r12; private static final Register doubleScratch = AMD64.xmm15; + /** + * The x86 condition codes used for conditional jumps/moves. + */ + public enum ConditionFlag { + Zero(0x4, "|zero|"), + NotZero(0x5, "|nzero|"), + Equal(0x4, "="), + NotEqual(0x5, "!="), + Less(0xc, "<"), + LessEqual(0xe, "<="), + Greater(0xf, ">"), + GreaterEqual(0xd, ">="), + Below(0x2, "|<|"), + BelowEqual(0x6, "|<=|"), + Above(0x7, "|>|"), + AboveEqual(0x3, "|>=|"), + Overflow(0x0, "|of|"), + NoOverflow(0x1, "|nof|"), + CarrySet(0x2, "|carry|"), + CarryClear(0x3, "|ncarry|"), + Negative(0x8, "|neg|"), + Positive(0x9, "|pos|"), + Parity(0xa, "|par|"), + NoParity(0xb, "|npar|"); + + public final int value; + public final String operator; + + ConditionFlag(int value, String operator) { + this.value = value; + this.operator = operator; + } + } + public AMD64TestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config) { super(codeCache, config, 16, 16, AMD64Kind.DWORD, AMD64.rax, AMD64.rcx, AMD64.rdi, AMD64.r8, AMD64.r9, AMD64.r10); } @@ -63,6 +97,62 @@ private void emitFatNop() { code.emitByte(0x00); } + /** + * Emit the expected patchable code sequence for the nmethod entry barrier. The int sized + * payload must be naturally aligned so it can be patched atomically. + */ + private void emitNMethodEntryCompare(int displacement) { + // cmp dword ptr [r15 + ], 0x00000000 + // 41 81 7f 00 00 00 00 + code.emitByte(0x41); + code.emitByte(0x81); + code.emitByte(0x7f); + check(isByte(displacement), "expected byte sized displacement: 0x%x", displacement); + code.emitByte(displacement & 0xff); + check(code.position() % 4 == 0, "must be aligned"); + code.emitInt(0); + } + + /** + * Emits a long (i.e. 6 byte) format conditional branch. + * + * @param offset the offset of the branch target wrt the start of the branch instruction + */ + private void emitBranch(ConditionFlag condition, int offset) { + final int longSize = 6; + int disp32 = offset - longSize; + + // 0000 1111 1000 tttn #32-bit disp + check(isInt(disp32), "must be 32bit disp: %d", disp32); + code.emitByte(0x0F); + code.emitByte(0x80 | condition.value); + code.emitInt(disp32); + } + + public void emitAlign(int modulus) { + while (code.position() % modulus != 0) { + code.emitByte(0x90); + } + } + + private void emitNMethodEntryBarrier() { + // The following code sequence must be emitted in exactly this fashion as HotSpot + // will check that the barrier is the expected code sequence. + emitAlign(4); + recordMark(config.MARKID_FRAME_COMPLETE); + recordMark(config.MARKID_ENTRY_BARRIER_PATCH); + emitNMethodEntryCompare(config.threadDisarmedOffset); + int branchOffset; + try (Bookmark bm = bookmark()) { + int pos = code.position(); + emitBranch(ConditionFlag.Equal, 0); + emitCall(config.nmethodEntryBarrier); + branchOffset = code.position() - pos; + } + emitBranch(ConditionFlag.Equal, branchOffset); + emitCall(config.nmethodEntryBarrier); + } + @Override public void emitPrologue() { // WARNING: Initial instruction MUST be 5 bytes or longer so that @@ -71,6 +161,7 @@ public void emitPrologue() { emitFatNop(); code.emitByte(0x50 | AMD64.rbp.encoding); // PUSH rbp emitMove(true, AMD64.rbp, AMD64.rsp); // MOV rbp, rsp + emitNMethodEntryBarrier(); setDeoptRescueSlot(newStackSlot(AMD64Kind.QWORD)); } From ab3a8acbff9c480db4306588ffc67776974bb586 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Wed, 1 May 2024 22:42:02 +0200 Subject: [PATCH 2/5] fixed failing tests and removed tests that install no longer valid code --- .../InvalidateInstalledCodeTest.java | 108 ----------- .../events/JvmciNotifyInstallEventTest.config | 2 - .../events/JvmciNotifyInstallEventTest.java | 179 ------------------ .../vm/ci/code/test/CodeInstallationTest.java | 7 +- .../code/test/RuntimeStubAllocFailTest.java | 86 +++++++++ .../code/test/SimpleCodeInstallationTest.java | 23 ++- .../vm/ci/code/test/SimpleDebugInfoTest.java | 1 - .../test/aarch64/AArch64TestAssembler.java | 4 +- 8 files changed, 113 insertions(+), 297 deletions(-) delete mode 100644 test/hotspot/jtreg/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java delete mode 100644 test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.config delete mode 100644 test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java create mode 100644 test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/RuntimeStubAllocFailTest.java diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java deleted file mode 100644 index 9307ab8250a35..0000000000000 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2015, 2021, 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. - */ - -/* - * @test - * @bug 8136421 - * @requires vm.jvmci - * @library /test/lib / - * @library ../common/patches - * @modules java.base/jdk.internal.misc - * @modules java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.org.objectweb.asm.tree - * jdk.internal.vm.ci/jdk.vm.ci.hotspot - * jdk.internal.vm.ci/jdk.vm.ci.code - * jdk.internal.vm.ci/jdk.vm.ci.code.site - * jdk.internal.vm.ci/jdk.vm.ci.meta - * jdk.internal.vm.ci/jdk.vm.ci.runtime - * - * @build jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper - * jdk.test.whitebox.WhiteBox jdk.test.whitebox.parser.DiagnosticCommand - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * jdk.test.whitebox.parser.DiagnosticCommand - * @run junit/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * compiler.jvmci.compilerToVM.InvalidateInstalledCodeTest - */ - -package compiler.jvmci.compilerToVM; - -import compiler.jvmci.common.CodeInstallerTest; -import compiler.jvmci.common.CTVMUtilities; -import jdk.test.lib.Asserts; -import jdk.test.lib.Utils; -import jdk.vm.ci.code.InstalledCode; -import jdk.vm.ci.code.site.Site; -import jdk.vm.ci.code.site.DataPatch; -import jdk.vm.ci.hotspot.CompilerToVMHelper; -import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; -import jdk.vm.ci.hotspot.HotSpotNmethod; -import jdk.vm.ci.meta.Assumptions.Assumption; - -import java.util.List; -import org.junit.Test; - -public class InvalidateInstalledCodeTest extends CodeInstallerTest { - - @Test - public void testInvalidation() { - List testCases - = CompileCodeTestCase.generate(/* bci = */ 0); - testCases.addAll(CompileCodeTestCase.generate(/* bci = */ -1)); - testCases.forEach(t -> check(t)); - checkNull(); - } - - private void checkNull() { - Utils.runAndCheckException( - () -> CompilerToVMHelper.invalidateHotSpotNmethod(null, true), - NullPointerException.class); - } - - private void check(CompileCodeTestCase testCase) { - HotSpotResolvedJavaMethod javaMethod = CTVMUtilities.getResolvedMethod(testCase.executable); - HotSpotNmethod nmethod = (HotSpotNmethod) installEmptyCode(new Site[0], new Assumption[0], - new Comment[0], 8, new DataPatch[0], null); - - Asserts.assertTrue(nmethod.isValid(), testCase + " : code is invalid even before invalidation"); - - Asserts.assertTrue(nmethod.isValid(), testCase + " : code is not valid, i = " + nmethod); - Asserts.assertTrue(nmethod.isAlive(), testCase + " : code is not alive, i = " + nmethod); - Asserts.assertNotEquals(nmethod.getStart(), 0L); - - // Make nmethod non-entrant but still alive - CompilerToVMHelper.invalidateHotSpotNmethod(nmethod, false); - Asserts.assertFalse(nmethod.isValid(), testCase + " : code is valid, i = " + nmethod); - Asserts.assertTrue(nmethod.isAlive(), testCase + " : code is not alive, i = " + nmethod); - Asserts.assertEquals(nmethod.getStart(), 0L); - - // Deoptimize the nmethod and cut the link to it from the HotSpotNmethod - CompilerToVMHelper.invalidateHotSpotNmethod(nmethod, true); - Asserts.assertFalse(nmethod.isValid(), testCase + " : code is valid, i = " + nmethod); - Asserts.assertFalse(nmethod.isAlive(), testCase + " : code is alive, i = " + nmethod); - Asserts.assertEquals(nmethod.getStart(), 0L); - } -} diff --git a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.config b/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.config deleted file mode 100644 index 9e2866167c1f7..0000000000000 --- a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.config +++ /dev/null @@ -1,2 +0,0 @@ -compiler.jvmci.events.JvmciNotifyInstallEventTest -compiler.jvmci.common.JVMCIHelpers diff --git a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java b/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java deleted file mode 100644 index c5d1b99235a07..0000000000000 --- a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2015, 2019, 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. - */ - -/* - * @test - * @bug 8136421 - * @requires vm.jvmci & !vm.graal.enabled & vm.compMode == "Xmixed" - * @library / /test/lib - * @library ../common/patches - * @modules java.base/jdk.internal.misc - * @modules java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.org.objectweb.asm.tree - * jdk.internal.vm.ci/jdk.vm.ci.hotspot - * jdk.internal.vm.ci/jdk.vm.ci.code - * jdk.internal.vm.ci/jdk.vm.ci.code.site - * jdk.internal.vm.ci/jdk.vm.ci.meta - * jdk.internal.vm.ci/jdk.vm.ci.runtime - * jdk.internal.vm.ci/jdk.vm.ci.services - * - * @build jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper - * @build compiler.jvmci.common.JVMCIHelpers - * @run driver jdk.test.lib.FileInstaller ./JvmciNotifyInstallEventTest.config - * ./META-INF/services/jdk.vm.ci.services.JVMCIServiceLocator - * @run driver jdk.test.lib.helpers.ClassFileInstaller - * compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler - * compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory - * compiler.jvmci.common.JVMCIHelpers$EmptyCompilationRequestResult - * compiler.jvmci.common.JVMCIHelpers$EmptyVMEventListener - * @run main/othervm -XX:+UnlockExperimentalVMOptions - * -Djvmci.Compiler=EmptyCompiler -Xbootclasspath/a:. - * -XX:+UseJVMCICompiler -XX:-BootstrapJVMCI - * -XX:-UseJVMCINativeLibrary -XX:JVMCITraceLevel=1 - * -Dtest.jvmci.forceRuntimeStubAllocFail=test_stub_that_fails_to_be_allocated - * compiler.jvmci.events.JvmciNotifyInstallEventTest - * @run main/othervm -XX:+UnlockExperimentalVMOptions - * -Djvmci.Compiler=EmptyCompiler -Xbootclasspath/a:. - * -XX:+UseJVMCICompiler -XX:-BootstrapJVMCI -XX:JVMCINMethodSizeLimit=0 - * -XX:-UseJVMCINativeLibrary - * compiler.jvmci.events.JvmciNotifyInstallEventTest - */ - -package compiler.jvmci.events; - -import compiler.jvmci.common.CTVMUtilities; -import compiler.jvmci.common.testcases.SimpleClass; -import jdk.test.lib.Asserts; -import jdk.test.lib.Platform; -import jdk.test.lib.Utils; -import jdk.vm.ci.services.JVMCIServiceLocator; -import jdk.vm.ci.code.BailoutException; -import jdk.vm.ci.code.CompiledCode; -import jdk.vm.ci.code.InstalledCode; -import jdk.vm.ci.code.site.DataPatch; -import jdk.vm.ci.code.site.Site; -import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; -import jdk.vm.ci.hotspot.HotSpotCompiledCode; -import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; -import jdk.vm.ci.hotspot.HotSpotCompiledNmethod; -import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -import jdk.vm.ci.hotspot.HotSpotVMEventListener; -import jdk.vm.ci.meta.Assumptions.Assumption; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -import java.lang.reflect.Method; - -public class JvmciNotifyInstallEventTest extends JVMCIServiceLocator implements HotSpotVMEventListener { - private static final String METHOD_NAME = "testMethod"; - private static volatile int gotInstallNotification = 0; - - public static void main(String args[]) { - new JvmciNotifyInstallEventTest().runTest(); - } - - @Override - public S getProvider(Class service) { - if (service == HotSpotVMEventListener.class) { - return service.cast(this); - } - return null; - } - - private void runTest() { - if (gotInstallNotification != 0) { - throw new Error("Got install notification before test actions"); - } - HotSpotCodeCacheProvider codeCache; - try { - codeCache = (HotSpotCodeCacheProvider) HotSpotJVMCIRuntime.runtime() - .getHostJVMCIBackend().getCodeCache(); - } catch (InternalError ie) { - // passed - return; - } - Method testMethod; - try { - testMethod = SimpleClass.class.getDeclaredMethod(METHOD_NAME); - } catch (NoSuchMethodException e) { - throw new Error("TEST BUG: Can't find " + METHOD_NAME, e); - } - HotSpotResolvedJavaMethod method = CTVMUtilities - .getResolvedMethod(SimpleClass.class, testMethod); - int dataSectionAlignment = 8; // CodeBuffer::SECT_CONSTS code section alignment - HotSpotCompiledCode compiledCode = new HotSpotCompiledNmethod(METHOD_NAME, - new byte[0], 0, new Site[0], new Assumption[0], - new ResolvedJavaMethod[]{method}, new Comment[0], new byte[0], - dataSectionAlignment, new DataPatch[0], false, 0, null, - method, 0, 1, 0L, false); - codeCache.installCode(method, compiledCode, /* installedCode = */ null, - /* speculationLog = */ null, /* isDefault = */ false); - Asserts.assertEQ(gotInstallNotification, 1, - "Got unexpected event count after 1st install attempt"); - // since "empty" compilation result is ok, a second attempt should be ok - codeCache.installCode(method, compiledCode, /* installedCode = */ null, - /* speculationLog = */ null, /* isDefault = */ false); - Asserts.assertEQ(gotInstallNotification, 2, - "Got unexpected event count after 2nd install attempt"); - // and an incorrect cases - Utils.runAndCheckException(() -> { - codeCache.installCode(method, null, null, null, true); - }, NullPointerException.class); - Asserts.assertEQ(gotInstallNotification, 2, - "Got unexpected event count after 3rd install attempt"); - Utils.runAndCheckException(() -> { - codeCache.installCode(null, null, null, null, true); - }, NullPointerException.class); - Asserts.assertEQ(gotInstallNotification, 2, - "Got unexpected event count after 4th install attempt"); - - String stubToFail = System.getProperty("test.jvmci.forceRuntimeStubAllocFail"); - if (Platform.isDebugBuild() && stubToFail != null) { - HotSpotCompiledCode stub = new HotSpotCompiledCode(stubToFail, - /* targetCode */ new byte[0], - /* targetCodeSize */ 0, - /* sites */ new Site[0], - /* assumptions */ new Assumption[0], - /* methods */ new ResolvedJavaMethod[0], - /* comments */ new Comment[0], - /* dataSection */ new byte[0], - dataSectionAlignment, - /* dataSectionPatches */ new DataPatch[0], - /* isImmutablePIC */ false, - /* totalFrameSize */ 0, - /* deoptRescueSlot */ null); - try { - codeCache.installCode(null, stub, null, null, true); - throw new AssertionError("Didn't get expected " + BailoutException.class.getName()); - } catch (BailoutException e) { - Asserts.assertEQ(e.getMessage(), "Error installing " + stubToFail + ": code cache is full"); - } - } - } - - @Override - public void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, - InstalledCode installedCode, CompiledCode compiledCode) { - gotInstallNotification++; - } -} diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java index 7483c45a654f0..97583b45458d8 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java @@ -35,6 +35,7 @@ import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotNmethod; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.MetaAccessProvider; @@ -95,7 +96,7 @@ protected Method getMethod(String name, Class... args) { } } - protected void test(TestCompiler compiler, Method method, Object... args) { + protected HotSpotNmethod test(TestCompiler compiler, Method method, Object... args) { try { HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(method); TestAssembler asm = createAssembler(); @@ -115,9 +116,9 @@ protected void test(TestCompiler compiler, Method method, Object... args) { Object expected = method.invoke(null, args); Object actual = installed.executeVarargs(args); Assert.assertEquals(expected, actual); + return (HotSpotNmethod) installed; } catch (Exception e) { - e.printStackTrace(); - Assert.fail(e.toString()); + throw new AssertionError(e); } } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/RuntimeStubAllocFailTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/RuntimeStubAllocFailTest.java new file mode 100644 index 0000000000000..dea523af1668e --- /dev/null +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/RuntimeStubAllocFailTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024, 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. + */ + +/* + * @test + * @requires vm.jvmci & !vm.graal.enabled & vm.compMode == "Xmixed" + * @library / /test/lib + * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot + * jdk.internal.vm.ci/jdk.vm.ci.code + * jdk.internal.vm.ci/jdk.vm.ci.code.site + * jdk.internal.vm.ci/jdk.vm.ci.meta + * jdk.internal.vm.ci/jdk.vm.ci.runtime + * + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Xbootclasspath/a:. + * -XX:+EnableJVMCI -XX:JVMCITraceLevel=1 + * -Dtest.jvmci.forceRuntimeStubAllocFail=test_stub_that_fails_to_be_allocated + * jdk.vm.ci.code.test.RuntimeStubAllocFailTest + */ + +package jdk.vm.ci.code.test; + +import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.code.site.DataPatch; +import jdk.vm.ci.code.site.Site; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotCompiledCode; +import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; +import jdk.vm.ci.meta.Assumptions.Assumption; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.runtime.JVMCI; +import jdk.vm.ci.runtime.JVMCIRuntime; +import jdk.vm.ci.runtime.JVMCIBackend; + +public class RuntimeStubAllocFailTest { + + public static void main(String args[]) { + JVMCIBackend backend = JVMCI.getRuntime().getHostJVMCIBackend(); + HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) backend.getCodeCache(); + int dataSectionAlignment = 8; // CodeBuffer::SECT_CONSTS code section alignment + String stubToFail = System.getProperty("test.jvmci.forceRuntimeStubAllocFail"); + if (Platform.isDebugBuild() && stubToFail != null) { + HotSpotCompiledCode stub = new HotSpotCompiledCode(stubToFail, + /* targetCode */ new byte[0], + /* targetCodeSize */ 0, + /* sites */ new Site[0], + /* assumptions */ new Assumption[0], + /* methods */ new ResolvedJavaMethod[0], + /* comments */ new Comment[0], + /* dataSection */ new byte[0], + dataSectionAlignment, + /* dataSectionPatches */ new DataPatch[0], + /* isImmutablePIC */ false, + /* totalFrameSize */ 0, + /* deoptRescueSlot */ null); + try { + codeCache.installCode(null, stub, null, null, true); + throw new AssertionError("Didn't get expected " + BailoutException.class.getName()); + } catch (BailoutException e) { + Asserts.assertEQ(e.getMessage(), "Error installing " + stubToFail + ": code cache is full"); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java index 80c63392b6e39..82058ec02cf30 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java @@ -25,7 +25,7 @@ * @test * @requires vm.jvmci * @requires vm.simpleArch == "x64" | vm.simpleArch == "aarch64" | vm.simpleArch == "riscv64" - * @library / + * @library /test/lib / * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot * jdk.internal.vm.ci/jdk.vm.ci.meta * jdk.internal.vm.ci/jdk.vm.ci.code @@ -39,8 +39,10 @@ */ package jdk.vm.ci.code.test; +import jdk.test.lib.Asserts; import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotNmethod; import org.junit.Test; /** @@ -61,6 +63,23 @@ private static void compileAdd(TestAssembler asm) { @Test public void test() { - test(SimpleCodeInstallationTest::compileAdd, getMethod("add", int.class, int.class), 5, 7); + HotSpotNmethod nmethod = test(SimpleCodeInstallationTest::compileAdd, getMethod("add", int.class, int.class), 5, 7); + + // Test code invalidation + Asserts.assertTrue(nmethod.isValid(), "code is not valid, i = " + nmethod); + Asserts.assertTrue(nmethod.isAlive(), "code is not alive, i = " + nmethod); + Asserts.assertNotEquals(nmethod.getStart(), 0L); + + // Make nmethod non-entrant but still alive + nmethod.invalidate(false); + Asserts.assertFalse(nmethod.isValid(), "code is valid, i = " + nmethod); + Asserts.assertTrue(nmethod.isAlive(), "code is not alive, i = " + nmethod); + Asserts.assertEquals(nmethod.getStart(), 0L); + + // Deoptimize the nmethod and cut the link to it from the HotSpotNmethod + nmethod.invalidate(true); + Asserts.assertFalse(nmethod.isValid(), "code is valid, i = " + nmethod); + Asserts.assertFalse(nmethod.isAlive(), "code is alive, i = " + nmethod); + Asserts.assertEquals(nmethod.getStart(), 0L); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java index 1c88fd1db0836..c7d8d2cf83064 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java @@ -27,7 +27,6 @@ * @requires vm.simpleArch == "x64" | vm.simpleArch == "aarch64" | vm.simpleArch == "riscv64" * @library / * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot - * jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64 * jdk.internal.vm.ci/jdk.vm.ci.meta * jdk.internal.vm.ci/jdk.vm.ci.code * jdk.internal.vm.ci/jdk.vm.ci.code.site diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java index 2ba1188989035..8d6814c543548 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java @@ -36,7 +36,6 @@ import jdk.vm.ci.code.site.DataSectionReference; import jdk.vm.ci.code.test.TestAssembler; import jdk.vm.ci.code.test.TestHotSpotVMConfig; -import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig; import jdk.vm.ci.hotspot.HotSpotCallingConventionType; import jdk.vm.ci.hotspot.HotSpotConstant; import jdk.vm.ci.hotspot.HotSpotForeignCallTarget; @@ -351,7 +350,8 @@ private void emitNMethodEntryBarrier() { if (config.nmethodEntryBarrierConcurrentPatch) { code.emitInt(0xd50339bf); // dmb ishld } - emitLoadPointer(scratchRegister2, AArch64Kind.DWORD, AArch64HotSpotRegisterConfig.threadRegister, config.threadDisarmedOffset); + Register thread = AArch64.r28; + emitLoadPointer(scratchRegister2, AArch64Kind.DWORD, thread, config.threadDisarmedOffset); code.emitInt(0x6b09011f); // cmp w8, w9 emitBranch(ConditionFlag.EQ, 8); // jump over slow path, runtime call emitCall(config.nmethodEntryBarrier); From be4bf630af69e7bfe2a73fa1f47c4ba55545192c Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Wed, 1 May 2024 22:43:41 +0200 Subject: [PATCH 3/5] remove vestiges of optional JVMCI nmethod support for entry barriers --- src/hotspot/share/gc/shared/barrierSetNMethod.cpp | 8 +------- src/hotspot/share/jvmci/jvmciCodeInstaller.cpp | 5 +---- src/hotspot/share/jvmci/jvmciRuntime.cpp | 1 + src/hotspot/share/jvmci/jvmciRuntime.hpp | 11 ++--------- 4 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index adf0527681b5e..548e6b671eff0 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -65,16 +65,10 @@ bool BarrierSetNMethod::supports_entry_barrier(nmethod* nm) { return false; } - if (nm->is_native_method() || nm->is_compiled_by_c2() || nm->is_compiled_by_c1()) { + if (nm->is_native_method() || nm->is_compiled_by_c2() || nm->is_compiled_by_c1() || nm->is_compiled_by_jvmci()) { return true; } -#if INCLUDE_JVMCI - if (nm->is_compiled_by_jvmci() && nm->jvmci_nmethod_data()->has_entry_barrier()) { - return true; - } -#endif - return false; } diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 07c48ae9af3e4..3171e586268b8 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -771,10 +771,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, JVMCI_THROW_MSG_(IllegalArgumentException, "InstalledCode object must be a HotSpotNmethod when installing a HotSpotCompiledNmethod", JVMCI::ok); } - // We would like to be strict about the nmethod entry barrier but there are various test - // configurations which generate assembly without being a full compiler. So for now we enforce - // that JIT compiled methods must have an nmethod barrier. - bool install_default = JVMCIENV->get_HotSpotNmethod_isDefault(installed_code) != 0; + // Enforce that compiled methods have an nmethod barrier. if (_nmethod_entry_patch_offset == -1) { JVMCI_THROW_MSG_(IllegalArgumentException, "nmethod entry barrier is missing", JVMCI::ok); } diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 2e588373cdf1d..3a8a040db4616 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -787,6 +787,7 @@ void JVMCINMethodData::initialize(int nmethod_mirror_index, { _failed_speculations = failed_speculations; _nmethod_mirror_index = nmethod_mirror_index; + guarantee(nmethod_entry_patch_offset != -1, "missing entry barrier"); _nmethod_entry_patch_offset = nmethod_entry_patch_offset; if (nmethod_mirror_name != nullptr) { _has_name = true; diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index c12c18abd7836..6a920eb8c7018 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -54,10 +54,8 @@ class JVMCINMethodData : public ResourceObj { // This is -1 if there is no mirror in the oops table. int _nmethod_mirror_index; - // This is the offset of the patchable part of the nmethod entry barrier sequence. The meaning is - // somewhat platform dependent as the way patching is done varies by architecture. Older JVMCI - // based compilers didn't emit the entry barrier so having a positive value for this offset - // confirms that the installed code supports the entry barrier. + // This is the offset of the patchable part of the nmethod entry barrier sequence. The meaning is + // somewhat platform dependent as the way patching is done varies by architecture. int _nmethod_entry_patch_offset; // Address of the failed speculations list to which a speculation @@ -129,12 +127,7 @@ class JVMCINMethodData : public ResourceObj { // Sets the mirror in nm's oops table. void set_nmethod_mirror(nmethod* nm, oop mirror); - bool has_entry_barrier() { - return _nmethod_entry_patch_offset != -1; - } - int nmethod_entry_patch_offset() { - guarantee(_nmethod_entry_patch_offset != -1, "missing entry barrier"); return _nmethod_entry_patch_offset; } }; From 606957c73c96b31b1e52763b23a4c58a5c134057 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 2 May 2024 23:31:17 +0200 Subject: [PATCH 4/5] remove more vestiges of optional JVMCI nmethod support for entry barriers --- src/hotspot/share/jvmci/jvmciCodeInstaller.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 3171e586268b8..52a060427d5d4 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -813,14 +813,12 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, DirectivesStack::release(directive); } - if (_nmethod_entry_patch_offset != -1) { - BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); - // an empty error buffer for use by the verify_barrier code - err_msg msg(""); - if (!bs_nm->verify_barrier(nm, msg)) { - JVMCI_THROW_MSG_(IllegalArgumentException, err_msg("nmethod entry barrier is malformed: %s", msg.buffer()), JVMCI::ok); - } + // an empty error buffer for use by the verify_barrier code + err_msg msg(""); + if (!bs_nm->verify_barrier(nm, msg)) { + JVMCI_THROW_MSG_(IllegalArgumentException, err_msg("nmethod entry barrier is malformed: %s", msg.buffer()), JVMCI::ok); } } } From 1b30b67ee4c0efc0ebace565f0c41655cdfcb243 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 2 May 2024 23:31:41 +0200 Subject: [PATCH 5/5] fix NativeCallTest on x64 --- .../src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java index 4902719453290..32b0e66df33d7 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java @@ -505,7 +505,7 @@ public void emitCallPrologue(CallingConvention cc, Object... prim) { @Override public void emitCall(long addr) { - Register target = emitLoadLong(addr); + Register target = emitLoadLong(AMD64.rax, addr); code.emitByte(0xFF); // CALL r/m64 int enc = target.encoding; if (enc >= 8) {