changeset 59483:91e1055c565e

8245505: Prelink j.l.ref.Reference when loading AOT library Reviewed-by: dlong, kvn
author iveresov
date Thu, 28 May 2020 11:36:39 -0700
parents ba5a3bb0a027
children 8e28aae50680
files src/hotspot/share/aot/aotCodeHeap.cpp src/hotspot/share/aot/aotCodeHeap.hpp src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReplaceConstantNodesPhaseTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java
diffstat 5 files changed, 141 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/aot/aotCodeHeap.cpp	Thu May 28 18:50:58 2020 +0200
+++ b/src/hotspot/share/aot/aotCodeHeap.cpp	Thu May 28 11:36:39 2020 -0700
@@ -366,24 +366,30 @@
   }
 }
 
-void AOTCodeHeap::link_primitive_array_klasses() {
+void AOTCodeHeap::link_klass(const Klass* klass) {
   ResourceMark rm;
+  assert(klass != NULL, "Should be given a klass");
+  AOTKlassData* klass_data = (AOTKlassData*) os::dll_lookup(_lib->dl_handle(), klass->signature_name());
+  if (klass_data != NULL) {
+    // Set both GOT cells, resolved and initialized klass pointers.
+    // _got_index points to second cell - resolved klass pointer.
+    _klasses_got[klass_data->_got_index-1] = (Metadata*)klass; // Initialized
+    _klasses_got[klass_data->_got_index  ] = (Metadata*)klass; // Resolved
+    if (PrintAOT) {
+      tty->print_cr("[Found  %s  in  %s]", klass->internal_name(), _lib->name());
+    }
+  }
+}
+
+void AOTCodeHeap::link_known_klasses() {
   for (int i = T_BOOLEAN; i <= T_CONFLICT; i++) {
     BasicType t = (BasicType)i;
     if (is_java_primitive(t)) {
       const Klass* arr_klass = Universe::typeArrayKlassObj(t);
-      AOTKlassData* klass_data = (AOTKlassData*) os::dll_lookup(_lib->dl_handle(), arr_klass->signature_name());
-      if (klass_data != NULL) {
-        // Set both GOT cells, resolved and initialized klass pointers.
-        // _got_index points to second cell - resolved klass pointer.
-        _klasses_got[klass_data->_got_index-1] = (Metadata*)arr_klass; // Initialized
-        _klasses_got[klass_data->_got_index  ] = (Metadata*)arr_klass; // Resolved
-        if (PrintAOT) {
-          tty->print_cr("[Found  %s  in  %s]", arr_klass->internal_name(), _lib->name());
-        }
-      }
+      link_klass(arr_klass);
     }
   }
+  link_klass(SystemDictionary::Reference_klass());
 }
 
 void AOTCodeHeap::register_stubs() {
@@ -590,9 +596,7 @@
     link_stub_routines_symbols();
     link_os_symbols();
     link_graal_runtime_symbols();
-
-    // Link primitive array klasses.
-    link_primitive_array_klasses();
+    link_known_klasses();
   }
 }
 
--- a/src/hotspot/share/aot/aotCodeHeap.hpp	Thu May 28 18:50:58 2020 +0200
+++ b/src/hotspot/share/aot/aotCodeHeap.hpp	Thu May 28 11:36:39 2020 -0700
@@ -217,7 +217,8 @@
   void link_graal_runtime_symbols();
 
   void link_global_lib_symbols();
-  void link_primitive_array_klasses();
+  void link_klass(const Klass* klass);
+  void link_known_klasses();
   void publish_aot(const methodHandle& mh, AOTMethodData* method_data, int code_id);
 
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReplaceConstantNodesPhaseTest.java	Thu May 28 18:50:58 2020 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReplaceConstantNodesPhaseTest.java	Thu May 28 11:36:39 2020 -0700
@@ -121,7 +121,7 @@
         new EliminateRedundantInitializationPhase().apply(graph, highTierContext);
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
         new LoadJavaMirrorWithKlassPhase(config).apply(graph, highTierContext);
-        new ReplaceConstantNodesPhase(false).apply(graph, highTierContext);
+        new ReplaceConstantNodesPhase(true, false).apply(graph, highTierContext);
         Assert.assertEquals(expectedInits, graph.getNodes().filter(InitializeKlassNode.class).count());
         Assert.assertEquals(expectedResolves, graph.getNodes().filter(ResolveConstantNode.class).count());
         Assert.assertEquals(expectedLoads, graph.getNodes().filter(LoadConstantIndirectlyNode.class).count());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Thu May 28 18:50:58 2020 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Thu May 28 11:36:39 2020 -0700
@@ -59,6 +59,7 @@
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.LowTierContext;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
 import org.graalvm.compiler.phases.tiers.Suites;
 import org.graalvm.compiler.phases.tiers.SuitesCreator;
@@ -100,7 +101,11 @@
                     highTierLowering.add(new FinalizeProfileNodesPhase(HotSpotAOTProfilingPlugin.Options.TierAInvokeInlineeNotifyFreqLog.getValue(options)));
                 }
                 ListIterator<BasePhase<? super MidTierContext>> midTierLowering = ret.getMidTier().findPhase(LoweringPhase.class);
-                midTierLowering.add(new ReplaceConstantNodesPhase());
+                midTierLowering.add(new ReplaceConstantNodesPhase(true));
+
+                // Replace possible constants after GC barrier expansion.
+                ListIterator<BasePhase<? super LowTierContext>> lowTierLowering = ret.getLowTier().findPhase(LoweringPhase.class);
+                lowTierLowering.add(new ReplaceConstantNodesPhase(false));
 
                 // Replace inlining policy
                 if (Inline.getValue(options)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java	Thu May 28 18:50:58 2020 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java	Thu May 28 11:36:39 2020 -0700
@@ -28,6 +28,7 @@
 import static org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode.getLoadMethodCountersNodes;
 import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
 
+import java.lang.ref.Reference;
 import java.util.HashSet;
 import java.util.List;
 
@@ -82,6 +83,7 @@
 public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
 
     private final boolean verifyFingerprints;
+    private final boolean allowResolution;
 
     static Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0];
     static Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0];
@@ -92,6 +94,7 @@
     static class ClassInfo {
 
         private ResolvedJavaType stringType;
+        private ResolvedJavaType referenceType;
         private final HashSet<ResolvedJavaType> builtIns = new HashSet<>();
 
         ClassInfo(MetaAccessProvider metaAccessProvider) {
@@ -113,6 +116,7 @@
             builtIns.add(metaAccessProvider.lookupJavaType(longCacheClass));
 
             stringType = metaAccessProvider.lookupJavaType(String.class);
+            referenceType = metaAccessProvider.lookupJavaType(Reference.class);
         }
     }
 
@@ -313,8 +317,10 @@
      * @param graph
      * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
      *            resolution.
+     * @return return true if all usages of the node have been replaced
      */
-    private static void tryToReplaceWithExisting(StructuredGraph graph, ConstantNode node) {
+    private static boolean tryToReplaceWithExisting(StructuredGraph graph, ConstantNode node) {
+        boolean allUsagesReplaced = true;
         ScheduleResult schedule = graph.getLastSchedule();
         NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
         BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap();
@@ -347,16 +353,20 @@
                 for (Block d : blockToExisting.getKeys()) {
                     if (strictlyDominates(d, b)) {
                         use.replaceFirstInput(node, blockToExisting.get(d));
+                        replaced = true;
                         break;
                     }
                 }
             }
+            if (!replaced && allUsagesReplaced) {
+                allUsagesReplaced = false;
+            }
         }
+        return allUsagesReplaced;
     }
 
     /**
-     * Replace the uses of a constant with either {@link LoadConstantIndirectlyNode} or
-     * {@link ResolveConstantNode}.
+     * Replace the uses of a constant with {@link ResolveConstantNode}.
      *
      * @param graph
      * @param stateMapper
@@ -366,30 +376,63 @@
     private static void replaceWithResolution(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node, ClassInfo classInfo) {
         HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
         HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
+
+        FixedWithNextNode fixedReplacement;
+        if (classInfo.builtIns.contains(type)) {
+            // Special case of klass constants that come from {@link BoxingSnippets}.
+            fixedReplacement = graph.add(new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE));
+        } else {
+            fixedReplacement = graph.add(new ResolveConstantNode(node));
+        }
+        insertReplacement(graph, stateMapper, node, fixedReplacement);
+        node.replaceAtUsages(fixedReplacement, n -> !isReplacementNode(n));
+    }
+
+    /**
+     * Replace the uses of a constant with either {@link LoadConstantIndirectlyNode} if possible.
+     *
+     * @param graph
+     * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
+     *            resolution.
+     * @return return true if all usages of the node have been replaced
+     */
+    private static boolean replaceWithLoad(StructuredGraph graph, ConstantNode node, ClassInfo classInfo) {
+        HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
+        HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
         ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass();
-        ValueNode replacement;
-
-        if (type.isArray() && type.getComponentType().isPrimitive()) {
-            // Special case for primitive arrays. The AOT runtime pre-resolves them, so we may
-            // omit the resolution call.
+        ValueNode replacement = null;
+        if ((type.isArray() && type.getComponentType().isPrimitive()) || type.equals(classInfo.referenceType)) {
+            // Special case for primitive arrays and j.l.ref.Reference.
+            // The AOT runtime pre-resolves them, so we may omit the resolution call.
             replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node));
         } else if (type.equals(topMethodHolder) || (type.isAssignableFrom(topMethodHolder) && !type.isInterface())) {
             // If it's a supertype of or the same class that declares the top method, we are
             // guaranteed to have it resolved already. If it's an interface, we just test for
             // equality.
             replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node));
-        } else {
-            FixedWithNextNode fixedReplacement;
-            if (classInfo.builtIns.contains(type)) {
-                // Special case of klass constants that come from {@link BoxingSnippets}.
-                fixedReplacement = graph.add(new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE));
-            } else {
-                fixedReplacement = graph.add(new ResolveConstantNode(node));
+        }
+        if (replacement != null) {
+            node.replaceAtUsages(replacement, n -> !isReplacementNode(n));
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Verify that {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} has a valid
+     * fingerprint.
+     *
+     * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType}.
+     */
+    private void verifyFingerprint(ConstantNode node) {
+        HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
+        HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
+        if (type != null) {
+            assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants";
+            if (verifyFingerprints && checkForBadFingerprint(type)) {
+                throw new GraalError("Type with bad fingerprint: " + type);
             }
-            insertReplacement(graph, stateMapper, node, fixedReplacement);
-            replacement = fixedReplacement;
         }
-        node.replaceAtUsages(replacement, n -> !isReplacementNode(n));
     }
 
     /**
@@ -400,17 +443,11 @@
      * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
      *            resolution.
      */
-    private void handleHotSpotMetaspaceConstant(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node, ClassInfo classInfo) {
+    private static void handleHotSpotMetaspaceConstant(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node, ClassInfo classInfo) {
         HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
         HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
-
         if (type != null) {
-            if (verifyFingerprints && checkForBadFingerprint(type)) {
-                throw new GraalError("Type with bad fingerprint: " + type);
-            }
-            assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants";
-            tryToReplaceWithExisting(graph, node);
-            if (anyUsagesNeedReplacement(node)) {
+            if (!tryToReplaceWithExisting(graph, node) && !replaceWithLoad(graph, node, classInfo)) {
                 replaceWithResolution(graph, stateMapper, node, classInfo);
             }
         } else {
@@ -419,6 +456,24 @@
     }
 
     /**
+     * Replace {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} with a load. This
+     * variant handles only constants that don't require resolution.
+     *
+     * @param graph
+     * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
+     *            resolution.
+     */
+    private static void handleHotSpotMetaspaceConstantWithoutResolution(StructuredGraph graph, ConstantNode node, ClassInfo classInfo) {
+        HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
+        HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
+        if (type != null) {
+            replaceWithLoad(graph, node, classInfo);
+        } else {
+            throw new GraalError("Unsupported metaspace constant type: " + type);
+        }
+    }
+
+    /**
      * Replace an object constant with an indirect load {@link ResolveConstantNode}. Currently we
      * support only strings.
      *
@@ -482,6 +537,7 @@
      *
      * @param graph
      * @param stateMapper
+     * @param classInfo
      */
     private void replaceKlassesAndObjects(StructuredGraph graph, FrameStateMapperClosure stateMapper, ClassInfo classInfo) {
         new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false);
@@ -489,6 +545,7 @@
         for (ConstantNode node : getConstantNodes(graph)) {
             Constant constant = node.asConstant();
             if (constant instanceof HotSpotMetaspaceConstant && anyUsagesNeedReplacement(node)) {
+                verifyFingerprint(node);
                 handleHotSpotMetaspaceConstant(graph, stateMapper, node, classInfo);
             } else if (constant instanceof HotSpotObjectConstant && anyUsagesNeedReplacement(node)) {
                 handleHotSpotObjectConstant(graph, stateMapper, node, classInfo);
@@ -496,18 +553,37 @@
         }
     }
 
+    /**
+     * Replace well-known klass constants with indirect loads.
+     *
+     * @param graph
+     * @param classInfo
+     */
+    private static void replaceKlassesWithoutResolution(StructuredGraph graph, ClassInfo classInfo) {
+        for (ConstantNode node : getConstantNodes(graph)) {
+            Constant constant = node.asConstant();
+            if (constant instanceof HotSpotMetaspaceConstant && anyUsagesNeedReplacement(node)) {
+                handleHotSpotMetaspaceConstantWithoutResolution(graph, node, classInfo);
+            }
+        }
+    }
+
     @Override
     protected void run(StructuredGraph graph, CoreProviders context) {
-        FrameStateMapperClosure stateMapper = new FrameStateMapperClosure(graph);
-        ReentrantNodeIterator.apply(stateMapper, graph.start(), null);
+        if (allowResolution) {
+            FrameStateMapperClosure stateMapper = new FrameStateMapperClosure(graph);
+            ReentrantNodeIterator.apply(stateMapper, graph.start(), null);
 
-        // Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass
-        // constants.
-        replaceLoadMethodCounters(graph, stateMapper, context);
+            // Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass
+            // constants.
+            replaceLoadMethodCounters(graph, stateMapper, context);
 
-        // Replace object and klass constants (including the ones added in the previous pass) with
-        // resolution nodes.
-        replaceKlassesAndObjects(graph, stateMapper, new ClassInfo(context.getMetaAccess()));
+            // Replace object and klass constants (including the ones added in the previous pass)
+            // with resolution nodes.
+            replaceKlassesAndObjects(graph, stateMapper, new ClassInfo(context.getMetaAccess()));
+        } else {
+            replaceKlassesWithoutResolution(graph, new ClassInfo(context.getMetaAccess()));
+        }
     }
 
     @Override
@@ -515,11 +591,12 @@
         return false;
     }
 
-    public ReplaceConstantNodesPhase() {
-        this(true);
+    public ReplaceConstantNodesPhase(boolean allowResolution) {
+        this(allowResolution, true);
     }
 
-    public ReplaceConstantNodesPhase(boolean verifyFingerprints) {
+    public ReplaceConstantNodesPhase(boolean allowResolution, boolean verifyFingerprints) {
+        this.allowResolution = allowResolution;
         this.verifyFingerprints = verifyFingerprints;
     }
 }