8329982: compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java failed assert(oopDesc::is_oop_or_null(val)) failed: bad oop found
Reviewed-by: never
This commit is contained in:
parent
c1a164528a
commit
b20fa7b48b
src/hotspot/share
test/hotspot/jtreg/compiler/jvmci
compilerToVM
events
jdk.vm.ci.code.test/src/jdk/vm/ci/code/test
@ -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;
|
||||
}
|
||||
|
||||
|
@ -771,11 +771,8 @@ 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;
|
||||
if (_nmethod_entry_patch_offset == -1 && install_default) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -816,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 @@ public:
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
|
@ -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<CompileCodeTestCase> 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);
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
compiler.jvmci.events.JvmciNotifyInstallEventTest
|
||||
compiler.jvmci.common.JVMCIHelpers
|
@ -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> S getProvider(Class<S> 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++;
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@ import jdk.vm.ci.code.test.riscv64.RISCV64TestAssembler;
|
||||
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 @@ public class CodeInstallationTest {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class CodeInstallationTest {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
86
test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/RuntimeStubAllocFailTest.java
Normal file
86
test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/RuntimeStubAllocFailTest.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 @@ public class SimpleCodeInstallationTest extends CodeInstallationTest {
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
@ -243,6 +243,27 @@ public abstract class TestAssembler {
|
||||
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 @@ public abstract class TestAssembler {
|
||||
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 abstract class TestAssembler {
|
||||
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());
|
||||
|
@ -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 class TestHotSpotVMConfig extends HotSpotVMConfigAccess {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
@ -46,8 +46,69 @@ import jdk.vm.ci.meta.VMConstant;
|
||||
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 +276,22 @@ public class AArch64TestAssembler extends TestAssembler {
|
||||
| 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 +338,25 @@ public class AArch64TestAssembler extends TestAssembler {
|
||||
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
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitEpilogue() {
|
||||
recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
|
||||
@ -361,8 +454,11 @@ public class AArch64TestAssembler extends TestAssembler {
|
||||
|
||||
@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 class AArch64TestAssembler extends TestAssembler {
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
|
@ -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 @@ public class AMD64TestAssembler extends TestAssembler {
|
||||
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 + <displacement>], 0x00000000
|
||||
// 41 81 7f <db> 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 class AMD64TestAssembler extends TestAssembler {
|
||||
emitFatNop();
|
||||
code.emitByte(0x50 | AMD64.rbp.encoding); // PUSH rbp
|
||||
emitMove(true, AMD64.rbp, AMD64.rsp); // MOV rbp, rsp
|
||||
emitNMethodEntryBarrier();
|
||||
setDeoptRescueSlot(newStackSlot(AMD64Kind.QWORD));
|
||||
}
|
||||
|
||||
@ -414,7 +505,7 @@ public class AMD64TestAssembler extends TestAssembler {
|
||||
|
||||
@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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user