--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java Fri Jul 07 10:37:52 2017 +0200
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java Fri Jul 07 09:40:47 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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
@@ -29,14 +29,6 @@
import java.util.HashSet;
import java.util.List;
-import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
-import jdk.vm.ci.hotspot.HotSpotObjectConstant;
-import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
-import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.ResolvedJavaType;
-
import org.graalvm.compiler.core.common.cfg.BlockMap;
import org.graalvm.compiler.core.common.type.ObjectStamp;
import org.graalvm.compiler.core.common.type.Stamp;
@@ -44,7 +36,6 @@
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeMap;
-import org.graalvm.compiler.hotspot.FingerprintUtil;
import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode;
@@ -52,18 +43,37 @@
import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedNode;
import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.StateSplit;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.cfg.Block;
import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.graph.ReentrantNodeIterator;
+import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
import org.graalvm.compiler.phases.schedule.SchedulePhase;
import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
import org.graalvm.compiler.phases.tiers.PhaseContext;
import org.graalvm.util.EconomicMap;
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
public class ReplaceConstantNodesPhase extends BasePhase<PhaseContext> {
private static final HashSet<Class<?>> builtIns = new HashSet<>();
@@ -115,63 +125,175 @@
if (type.getElementalType().isPrimitive()) {
return false;
}
- return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) (type.getElementalType())) == 0;
+ return ((HotSpotResolvedObjectType) (type.getElementalType())).getFingerprint() == 0;
}
- return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) type) == 0;
+ return ((HotSpotResolvedObjectType) type).getFingerprint() == 0;
+ }
+
+ /**
+ * Insert the replacement node into the graph. We may need to insert it into a place different
+ * than the original {@link FloatingNode} since we need to make sure that replacement will have
+ * a valid state assigned.
+ *
+ * @param graph
+ * @param stateMapper
+ * @param node
+ * @param replacement
+ */
+ private static void insertReplacement(StructuredGraph graph, FrameStateMapperClosure stateMapper, FloatingNode node, FixedWithNextNode replacement) {
+ FixedWithNextNode insertionPoint = findInsertionPoint(graph, stateMapper, node);
+ graph.addAfterFixed(insertionPoint, replacement);
+ stateMapper.addState(replacement, stateMapper.getState(insertionPoint));
}
/**
- * Replace {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} with indirection.
+ * Find a good place to insert a stateful fixed node that is above the given node. A good
+ * insertion point should have a valid FrameState reaching it.
*
* @param graph
- * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
- * resolution.
+ * @param stateMapper
+ * @param node start search from this node up
+ * @return an insertion point
*/
- private void handleHotSpotMetaspaceConstant(StructuredGraph graph, ConstantNode node) {
- 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)) {
- replaceWithResolution(graph, node);
- }
- } else {
- throw new GraalError("Unsupported metaspace constant type: " + type);
- }
+ private static FixedWithNextNode findInsertionPoint(StructuredGraph graph, FrameStateMapperClosure stateMapper, FloatingNode node) {
+ FixedWithNextNode fixed = findFixedBeforeFloating(graph, node);
+ FixedWithNextNode result = findFixedWithValidState(graph, stateMapper, fixed);
+ return result;
}
/**
- * Find the lowest dominating {@link FixedWithNextNode} before given node.
+ * Find the first {@link FixedWithNextNode} that is currently scheduled before the given
+ * floating node.
*
* @param graph
- * @param node
- * @return the last {@link FixedWithNextNode} that is scheduled before node.
+ * @param node start search from this node up
+ * @return the first {@link FixedWithNextNode}
*/
- private static FixedWithNextNode findFixedWithNextBefore(StructuredGraph graph, Node node) {
+ private static FixedWithNextNode findFixedBeforeFloating(StructuredGraph graph, FloatingNode node) {
ScheduleResult schedule = graph.getLastSchedule();
NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
+ Block block = nodeToBlock.get(node);
BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap();
-
- Block block = nodeToBlock.get(node);
FixedWithNextNode result = null;
for (Node n : blockToNodes.get(block)) {
+ if (n.equals(node)) {
+ break;
+ }
if (n instanceof FixedWithNextNode) {
result = (FixedWithNextNode) n;
}
- if (n.equals(node)) {
- break;
- }
}
assert result != null;
return result;
}
/**
+ * Find first dominating {@link FixedWithNextNode} that has a valid state reaching it starting
+ * from the given node.
+ *
+ * @param graph
+ * @param stateMapper
+ * @param node
+ * @return {@link FixedWithNextNode} that we can use as an insertion point
+ */
+ private static FixedWithNextNode findFixedWithValidState(StructuredGraph graph, FrameStateMapperClosure stateMapper, FixedWithNextNode node) {
+ ScheduleResult schedule = graph.getLastSchedule();
+ NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
+ Block block = nodeToBlock.get(node);
+
+ Node n = node;
+ do {
+ if (isFixedWithValidState(stateMapper, n)) {
+ return (FixedWithNextNode) n;
+ }
+ while (n != block.getBeginNode()) {
+ n = n.predecessor();
+ if (isFixedWithValidState(stateMapper, n)) {
+ return (FixedWithNextNode) n;
+ }
+ }
+ block = block.getDominator();
+ if (block != null) {
+ n = block.getEndNode();
+ }
+ } while (block != null);
+
+ return graph.start();
+ }
+
+ private static boolean isFixedWithValidState(FrameStateMapperClosure stateMapper, Node n) {
+ if (n instanceof FixedWithNextNode) {
+ FixedWithNextNode fixed = (FixedWithNextNode) n;
+ assert stateMapper.getState(fixed) != null;
+ if (!BytecodeFrame.isPlaceholderBci(stateMapper.getState(fixed).bci)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Compute frame states for all fixed nodes in the graph.
+ */
+ private static class FrameStateMapperClosure extends NodeIteratorClosure<FrameState> {
+ private NodeMap<FrameState> reachingStates;
+
+ @Override
+ protected FrameState processNode(FixedNode node, FrameState previousState) {
+ FrameState currentState = previousState;
+ if (node instanceof StateSplit) {
+ StateSplit stateSplit = (StateSplit) node;
+ FrameState stateAfter = stateSplit.stateAfter();
+ if (stateAfter != null) {
+ currentState = stateAfter;
+ }
+ }
+ reachingStates.put(node, currentState);
+ return currentState;
+ }
+
+ @Override
+ protected FrameState merge(AbstractMergeNode merge, List<FrameState> states) {
+ FrameState singleFrameState = singleFrameState(states);
+ FrameState currentState = singleFrameState == null ? merge.stateAfter() : singleFrameState;
+ reachingStates.put(merge, currentState);
+ return currentState;
+ }
+
+ @Override
+ protected FrameState afterSplit(AbstractBeginNode node, FrameState oldState) {
+ return oldState;
+ }
+
+ @Override
+ protected EconomicMap<LoopExitNode, FrameState> processLoop(LoopBeginNode loop, FrameState initialState) {
+ return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates;
+ }
+
+ private static FrameState singleFrameState(List<FrameState> states) {
+ FrameState singleState = states.get(0);
+ for (int i = 1; i < states.size(); ++i) {
+ if (states.get(i) != singleState) {
+ return null;
+ }
+ }
+ return singleState;
+ }
+
+ FrameStateMapperClosure(StructuredGraph graph) {
+ reachingStates = new NodeMap<>(graph);
+ }
+
+ public FrameState getState(Node n) {
+ return reachingStates.get(n);
+ }
+
+ public void addState(Node n, FrameState s) {
+ reachingStates.setAndGrow(n, s);
+ }
+ }
+
+ /**
* Try to find dominating node doing the resolution that can be reused.
*
* @param graph
@@ -223,10 +345,11 @@
* {@link ResolveConstantNode}.
*
* @param graph
+ * @param stateMapper
* @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
* resolution.
*/
- private static void replaceWithResolution(StructuredGraph graph, ConstantNode node) {
+ private static void replaceWithResolution(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node) {
HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass();
@@ -249,27 +372,54 @@
} else {
fixedReplacement = graph.add(new ResolveConstantNode(node));
}
- graph.addAfterFixed(findFixedWithNextBefore(graph, node), fixedReplacement);
+ insertReplacement(graph, stateMapper, node, fixedReplacement);
replacement = fixedReplacement;
}
node.replaceAtUsages(replacement, n -> !isReplacementNode(n));
}
/**
+ * Replace {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} with indirection.
+ *
+ * @param graph
+ * @param stateMapper
+ * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
+ * resolution.
+ */
+ private void handleHotSpotMetaspaceConstant(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node) {
+ 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)) {
+ replaceWithResolution(graph, stateMapper, node);
+ }
+ } else {
+ throw new GraalError("Unsupported metaspace constant type: " + type);
+ }
+ }
+
+ /**
* Replace an object constant with an indirect load {@link ResolveConstantNode}. Currently we
* support only strings.
*
* @param graph
+ * @param stateMapper
* @param node {@link ConstantNode} containing a {@link HotSpotObjectConstant} that needs
* resolution.
*/
- private static void handleHotSpotObjectConstant(StructuredGraph graph, ConstantNode node) {
+ private static void handleHotSpotObjectConstant(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node) {
HotSpotObjectConstant constant = (HotSpotObjectConstant) node.asJavaConstant();
HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) constant.getType();
if (type.mirror().equals(String.class)) {
assert !constant.isCompressed() : "No support for replacing compressed oop constants";
FixedWithNextNode replacement = graph.add(new ResolveConstantNode(node));
- graph.addAfterFixed(findFixedWithNextBefore(graph, node), replacement);
+ insertReplacement(graph, stateMapper, node, replacement);
node.replaceAtUsages(replacement, n -> !(n instanceof ResolveConstantNode));
} else {
throw new GraalError("Unsupported object constant type: " + type);
@@ -281,16 +431,17 @@
* {@link ResolveMethodAndLoadCountersNode}, expose a klass constant of the holder.
*
* @param graph
+ * @param stateMapper
* @param node
* @param context
*/
- private static void handleLoadMethodCounters(StructuredGraph graph, LoadMethodCountersNode node, PhaseContext context) {
+ private static void handleLoadMethodCounters(StructuredGraph graph, FrameStateMapperClosure stateMapper, LoadMethodCountersNode node, PhaseContext context) {
ResolvedJavaType type = node.getMethod().getDeclaringClass();
Stamp hubStamp = context.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull());
ConstantReflectionProvider constantReflection = context.getConstantReflection();
ConstantNode klassHint = ConstantNode.forConstant(hubStamp, constantReflection.asObjectHub(type), context.getMetaAccess(), graph);
FixedWithNextNode replacement = graph.add(new ResolveMethodAndLoadCountersNode(node.getMethod(), klassHint));
- graph.addAfterFixed(findFixedWithNextBefore(graph, node), replacement);
+ insertReplacement(graph, stateMapper, node, replacement);
node.replaceAtUsages(replacement, n -> !(n instanceof ResolveMethodAndLoadCountersNode));
}
@@ -299,13 +450,15 @@
* klass constants.
*
* @param graph
+ * @param stateMapper
* @param context
*/
- private static void replaceLoadMethodCounters(StructuredGraph graph, PhaseContext context) {
+ private static void replaceLoadMethodCounters(StructuredGraph graph, FrameStateMapperClosure stateMapper, PhaseContext context) {
new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false);
+
for (LoadMethodCountersNode node : getLoadMethodCountersNodes(graph)) {
if (anyUsagesNeedReplacement(node)) {
- handleLoadMethodCounters(graph, node, context);
+ handleLoadMethodCounters(graph, stateMapper, node, context);
}
}
}
@@ -314,29 +467,33 @@
* Replace object and klass constants with resolution nodes or reuse preceding initializations.
*
* @param graph
+ * @param stateMapper
*/
- private void replaceKlassesAndObjects(StructuredGraph graph) {
+ private void replaceKlassesAndObjects(StructuredGraph graph, FrameStateMapperClosure stateMapper) {
new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false);
for (ConstantNode node : getConstantNodes(graph)) {
Constant constant = node.asConstant();
if (constant instanceof HotSpotMetaspaceConstant && anyUsagesNeedReplacement(node)) {
- handleHotSpotMetaspaceConstant(graph, node);
+ handleHotSpotMetaspaceConstant(graph, stateMapper, node);
} else if (constant instanceof HotSpotObjectConstant && anyUsagesNeedReplacement(node)) {
- handleHotSpotObjectConstant(graph, node);
+ handleHotSpotObjectConstant(graph, stateMapper, node);
}
}
}
@Override
protected void run(StructuredGraph graph, PhaseContext context) {
+ FrameStateMapperClosure stateMapper = new FrameStateMapperClosure(graph);
+ ReentrantNodeIterator.apply(stateMapper, graph.start(), null);
+
// Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass
// constants.
- replaceLoadMethodCounters(graph, context);
+ replaceLoadMethodCounters(graph, stateMapper, context);
// Replace object and klass constants (including the ones added in the previous pass) with
// resolution nodes.
- replaceKlassesAndObjects(graph);
+ replaceKlassesAndObjects(graph, stateMapper);
}
@Override