src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java
changeset 54669 ad45b3802d4e
parent 47794 e84aa2c71241
--- 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