/*
* 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package 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;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.ResolvedJavaMethod;
Implementation of InstalledCode
for code installed as an nmethod
. The address of the nmethod
is stored in InstalledCode.address
and the value of nmethod::verified_entry_point()
is in InstalledCode.entryPoint
. /**
* 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 HotSpotResolvedJavaMethodImpl method;
Specifies whether the nmethod
associated with this object is the code executed by default HotSpot linkage when a normal Java call to method
is made. That is, does this.method.metadataHandle->_code
== this.address
. If not, then the 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. /**
* 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;
Determines whether this object is in the oops table of the nmethod.
If this object is in the oops table, the VM uses the oops table entry to update this object's InstalledCode.address
and InstalledCode.entryPoint
fields when the state of the nmethod changes. The nmethod will be unloadable when this object dies.
Otherwise, the nmethod's unloadability is not changed when this object dies.
/**
* 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 InstalledCode.address
is indeed the nmethod represented by this object. See Also:
/**
* 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 getMethod()
. /**
* Determines if the nmethod associated with this object is the compiled entry point for
* {@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().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("HotSpotNmethod[method=%s, codeBlob=0x%x, isDefault=%b, name=%s, inOopsTable=%s]",
method, getAddress(), isDefault, name, inOopsTable());
}
private boolean checkArgs(Object... args) {
JavaType[] sig = method.toParameterTypes();
assert args.length == sig.length : method.format("%H.%n(%p): expected ") + sig.length + " args, got " + args.length;
for (int i = 0; i < sig.length; i++) {
Object arg = args[i];
if (arg == null) {
assert sig[i].getJavaKind() == JavaKind.Object : method.format("%H.%n(%p): expected arg ") + i + " to be Object, not " + sig[i];
} else if (sig[i].getJavaKind() != JavaKind.Object) {
assert sig[i].getJavaKind().toBoxedJavaClass() == arg.getClass() : method.format("%H.%n(%p): expected arg ") + i + " to be " + sig[i] + ", not " + arg.getClass();
}
}
return true;
}
@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().executeHotSpotNmethod(args, this);
}
@Override
public long getStart() {
return isValid() ? super.getStart() : 0;
}
}