src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java Wed May 01 12:41:26 2019 -0400
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java Wed May 01 12:31:29 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,6 +23,8 @@
package jdk.vm.ci.hotspot;
import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
+import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
+
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.code.InvalidInstalledCodeException;
import jdk.vm.ci.meta.JavaKind;
@@ -30,56 +32,104 @@
import jdk.vm.ci.meta.ResolvedJavaMethod;
/**
- * Implementation of {@link InstalledCode} for code installed as an nmethod.
- *
- * When a {@link HotSpotNmethod} dies, it triggers unloading of the nmethod unless
- * {@link #isDefault() == true}.
+ * Implementation of {@link InstalledCode} for code installed as an {@code nmethod}. The address of
+ * the {@code nmethod} is stored in {@link InstalledCode#address} and the value of
+ * {@code nmethod::verified_entry_point()} is in {@link InstalledCode#entryPoint}.
*/
public class HotSpotNmethod extends HotSpotInstalledCode {
/**
- * This (indirect) Method* reference is safe since class redefinition preserves all methods
- * associated with nmethods in the code cache.
+ * This (indirect) {@code Method*} reference is safe since class redefinition preserves all
+ * methods associated with nmethods in the code cache.
*/
- private final HotSpotResolvedJavaMethod method;
+ private final HotSpotResolvedJavaMethodImpl method;
+ /**
+ * Specifies whether the {@code nmethod} associated with this object is the code executed by
+ * default HotSpot linkage when a normal Java call to {@link #method} is made. That is, does
+ * {@code this.method.metadataHandle->_code} == {@code this.address}. If not, then the
+ * {@code nmethod} can only be invoked via a reference to this object. An example of this is the
+ * trampoline mechanism used by Truffle: https://goo.gl/LX88rZ.
+ */
private final boolean isDefault;
- public HotSpotNmethod(HotSpotResolvedJavaMethod method, String name, boolean isDefault) {
+ /**
+ * Determines whether this object is in the oops table of the nmethod.
+ * <p>
+ * If this object is in the oops table, the VM uses the oops table entry to update this object's
+ * {@link #address} and {@link #entryPoint} fields when the state of the nmethod changes. The
+ * nmethod will be unloadable when this object dies.
+ * <p>
+ * Otherwise, the nmethod's unloadability is not changed when this object dies.
+ */
+ boolean inOopsTable() {
+ return compileIdSnapshot != 0;
+ }
+
+ /**
+ * If this field is 0, this object is in the oops table of the nmethod. Otherwise, the value of
+ * the field records the nmethod's compile identifier. This value is used to confirm an entry in
+ * the code cache retrieved by {@link #address} is indeed the nmethod represented by this
+ * object.
+ *
+ * @see #inOopsTable
+ */
+ private final long compileIdSnapshot;
+
+ HotSpotNmethod(HotSpotResolvedJavaMethodImpl method, String name, boolean isDefault, long compileId) {
super(name);
this.method = method;
this.isDefault = isDefault;
+ boolean inOopsTable = !IS_IN_NATIVE_IMAGE && !isDefault;
+ this.compileIdSnapshot = inOopsTable ? 0L : compileId;
+ assert inOopsTable || compileId != 0L : this;
}
/**
* Determines if the nmethod associated with this object is the compiled entry point for
- * {@link #getMethod()}. If {@code false}, then the nmethod is unloaded when the VM determines
- * this object has died.
+ * {@link #getMethod()}.
*/
public boolean isDefault() {
return isDefault;
}
+ @Override
+ public boolean isValid() {
+ if (compileIdSnapshot != 0L) {
+ compilerToVM().updateHotSpotNmethod(this);
+ }
+ return super.isValid();
+ }
+
public ResolvedJavaMethod getMethod() {
return method;
}
@Override
public void invalidate() {
- compilerToVM().invalidateInstalledCode(this);
+ compilerToVM().invalidateHotSpotNmethod(this);
+ }
+
+ @Override
+ public long getAddress() {
+ if (compileIdSnapshot != 0L) {
+ compilerToVM().updateHotSpotNmethod(this);
+ }
+ return super.getAddress();
+ }
+
+ @Override
+ public long getEntryPoint() {
+ if (compileIdSnapshot != 0L) {
+ return 0;
+ }
+ return super.getEntryPoint();
}
@Override
public String toString() {
- return String.format("InstalledNmethod[method=%s, codeBlob=0x%x, isDefault=%b, name=%s]", method, getAddress(), isDefault, name);
- }
-
- protected boolean checkThreeObjectArgs() {
- assert method.getSignature().getParameterCount(!method.isStatic()) == 3;
- assert method.getSignature().getParameterKind(0) == JavaKind.Object;
- assert method.getSignature().getParameterKind(1) == JavaKind.Object;
- assert !method.isStatic() || method.getSignature().getParameterKind(2) == JavaKind.Object;
- return true;
+ return String.format("HotSpotNmethod[method=%s, codeBlob=0x%x, isDefault=%b, name=%s, inOopsTable=%s]",
+ method, getAddress(), isDefault, name, inOopsTable());
}
private boolean checkArgs(Object... args) {
@@ -98,8 +148,11 @@
@Override
public Object executeVarargs(Object... args) throws InvalidInstalledCodeException {
+ if (IS_IN_NATIVE_IMAGE) {
+ throw new HotSpotJVMCIUnsupportedOperationError("Cannot execute nmethod via mirror in native image");
+ }
assert checkArgs(args);
- return compilerToVM().executeInstalledCode(args, this);
+ return compilerToVM().executeHotSpotNmethod(args, this);
}
@Override