1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.hotspot.phases.aot; 24 25 import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates; 26 import static org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode.getLoadMethodCountersNodes; 27 import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; 28 29 import java.util.HashSet; 30 import java.util.List; 31 32 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; 33 import jdk.vm.ci.hotspot.HotSpotObjectConstant; 34 import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; 35 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; 36 import jdk.vm.ci.meta.Constant; 37 import jdk.vm.ci.meta.ConstantReflectionProvider; 38 import jdk.vm.ci.meta.ResolvedJavaType; 39 40 import org.graalvm.compiler.core.common.cfg.BlockMap; 41 import org.graalvm.compiler.core.common.type.ObjectStamp; 42 import org.graalvm.compiler.core.common.type.Stamp; 43 import org.graalvm.compiler.core.common.type.StampFactory; 44 import org.graalvm.compiler.debug.GraalError; 45 import org.graalvm.compiler.graph.Node; 46 import org.graalvm.compiler.graph.NodeMap; 47 import org.graalvm.compiler.hotspot.FingerprintUtil; 48 import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; 49 import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; 50 import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode; 51 import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; 52 import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode; 53 import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; 54 import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; 55 import org.graalvm.compiler.nodes.ConstantNode; 56 import org.graalvm.compiler.nodes.FixedWithNextNode; 57 import org.graalvm.compiler.nodes.StructuredGraph; 58 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; 59 import org.graalvm.compiler.nodes.ValueNode; 60 import org.graalvm.compiler.nodes.cfg.Block; 61 import org.graalvm.compiler.phases.BasePhase; 62 import org.graalvm.compiler.phases.schedule.SchedulePhase; 63 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; 64 import org.graalvm.compiler.phases.tiers.PhaseContext; 65 import org.graalvm.util.EconomicMap; 66 67 public class ReplaceConstantNodesPhase extends BasePhase<PhaseContext> { 68 69 private static final HashSet<Class<?>> builtIns = new HashSet<>(); 70 private final boolean verifyFingerprints; 71 72 static { 73 builtIns.add(Boolean.class); 74 75 Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0]; 76 assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); 77 builtIns.add(characterCacheClass); 78 79 Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0]; 80 assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); 81 builtIns.add(byteCacheClass); 82 83 Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0]; 84 assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); 85 builtIns.add(shortCacheClass); 86 98 return n instanceof LoadConstantIndirectlyNode || 99 n instanceof LoadConstantIndirectlyFixedNode || 100 n instanceof ResolveConstantNode || 101 n instanceof InitializeKlassNode; 102 // @formatter:on 103 } 104 105 private static boolean anyUsagesNeedReplacement(ConstantNode node) { 106 return node.usages().filter(n -> !isReplacementNode(n)).isNotEmpty(); 107 } 108 109 private static boolean anyUsagesNeedReplacement(LoadMethodCountersNode node) { 110 return node.usages().filter(n -> !(n instanceof ResolveMethodAndLoadCountersNode)).isNotEmpty(); 111 } 112 113 private static boolean checkForBadFingerprint(HotSpotResolvedJavaType type) { 114 if (type.isArray()) { 115 if (type.getElementalType().isPrimitive()) { 116 return false; 117 } 118 return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) (type.getElementalType())) == 0; 119 } 120 return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) type) == 0; 121 } 122 123 /** 124 * Replace {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} with indirection. 125 * 126 * @param graph 127 * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs 128 * resolution. 129 */ 130 private void handleHotSpotMetaspaceConstant(StructuredGraph graph, ConstantNode node) { 131 HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant(); 132 HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType(); 133 134 if (type != null) { 135 if (verifyFingerprints && checkForBadFingerprint(type)) { 136 throw new GraalError("Type with bad fingerprint: " + type); 137 } 138 assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants"; 139 tryToReplaceWithExisting(graph, node); 140 if (anyUsagesNeedReplacement(node)) { 141 replaceWithResolution(graph, node); 142 } 143 } else { 144 throw new GraalError("Unsupported metaspace constant type: " + type); 145 } 146 } 147 148 /** 149 * Find the lowest dominating {@link FixedWithNextNode} before given node. 150 * 151 * @param graph 152 * @param node 153 * @return the last {@link FixedWithNextNode} that is scheduled before node. 154 */ 155 private static FixedWithNextNode findFixedWithNextBefore(StructuredGraph graph, Node node) { 156 ScheduleResult schedule = graph.getLastSchedule(); 157 NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap(); 158 BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap(); 159 160 Block block = nodeToBlock.get(node); 161 FixedWithNextNode result = null; 162 for (Node n : blockToNodes.get(block)) { 163 if (n instanceof FixedWithNextNode) { 164 result = (FixedWithNextNode) n; 165 } 166 if (n.equals(node)) { 167 break; 168 } 169 } 170 assert result != null; 171 return result; 172 } 173 174 /** 175 * Try to find dominating node doing the resolution that can be reused. 176 * 177 * @param graph 178 * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs 179 * resolution. 180 */ 181 private static void tryToReplaceWithExisting(StructuredGraph graph, ConstantNode node) { 182 ScheduleResult schedule = graph.getLastSchedule(); 183 NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap(); 184 BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap(); 185 186 EconomicMap<Block, Node> blockToExisting = EconomicMap.create(); 187 for (Node n : node.usages().filter(n -> isReplacementNode(n))) { 188 blockToExisting.put(nodeToBlock.get(n), n); 189 } 190 for (Node use : node.usages().filter(n -> !isReplacementNode(n)).snapshot()) { 191 boolean replaced = false; 192 Block b = nodeToBlock.get(use); 193 Node e = blockToExisting.get(b); 194 if (e != null) { 206 } 207 } 208 } 209 if (!replaced) { 210 // Look for dominating blocks that have existing nodes 211 for (Block d : blockToExisting.getKeys()) { 212 if (strictlyDominates(d, b)) { 213 use.replaceFirstInput(node, blockToExisting.get(d)); 214 break; 215 } 216 } 217 } 218 } 219 } 220 221 /** 222 * Replace the uses of a constant with either {@link LoadConstantIndirectlyNode} or 223 * {@link ResolveConstantNode}. 224 * 225 * @param graph 226 * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs 227 * resolution. 228 */ 229 private static void replaceWithResolution(StructuredGraph graph, ConstantNode node) { 230 HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant(); 231 HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType(); 232 ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass(); 233 ValueNode replacement; 234 235 if (type.isArray() && type.getComponentType().isPrimitive()) { 236 // Special case for primitive arrays. The AOT runtime pre-resolves them, so we may 237 // omit the resolution call. 238 replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node)); 239 } else if (type.equals(topMethodHolder) || (type.isAssignableFrom(topMethodHolder) && !type.isInterface())) { 240 // If it's a supertype of or the same class that declares the top method, we are 241 // guaranteed to have it resolved already. If it's an interface, we just test for 242 // equality. 243 replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node)); 244 } else { 245 FixedWithNextNode fixedReplacement; 246 if (builtIns.contains(type.mirror())) { 247 // Special case of klass constants that come from {@link BoxingSnippets}. 248 fixedReplacement = graph.add(new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE)); 249 } else { 250 fixedReplacement = graph.add(new ResolveConstantNode(node)); 251 } 252 graph.addAfterFixed(findFixedWithNextBefore(graph, node), fixedReplacement); 253 replacement = fixedReplacement; 254 } 255 node.replaceAtUsages(replacement, n -> !isReplacementNode(n)); 256 } 257 258 /** 259 * Replace an object constant with an indirect load {@link ResolveConstantNode}. Currently we 260 * support only strings. 261 * 262 * @param graph 263 * @param node {@link ConstantNode} containing a {@link HotSpotObjectConstant} that needs 264 * resolution. 265 */ 266 private static void handleHotSpotObjectConstant(StructuredGraph graph, ConstantNode node) { 267 HotSpotObjectConstant constant = (HotSpotObjectConstant) node.asJavaConstant(); 268 HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) constant.getType(); 269 if (type.mirror().equals(String.class)) { 270 assert !constant.isCompressed() : "No support for replacing compressed oop constants"; 271 FixedWithNextNode replacement = graph.add(new ResolveConstantNode(node)); 272 graph.addAfterFixed(findFixedWithNextBefore(graph, node), replacement); 273 node.replaceAtUsages(replacement, n -> !(n instanceof ResolveConstantNode)); 274 } else { 275 throw new GraalError("Unsupported object constant type: " + type); 276 } 277 } 278 279 /** 280 * Replace {@link LoadMethodCountersNode} with indirect load 281 * {@link ResolveMethodAndLoadCountersNode}, expose a klass constant of the holder. 282 * 283 * @param graph 284 * @param node 285 * @param context 286 */ 287 private static void handleLoadMethodCounters(StructuredGraph graph, LoadMethodCountersNode node, PhaseContext context) { 288 ResolvedJavaType type = node.getMethod().getDeclaringClass(); 289 Stamp hubStamp = context.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull()); 290 ConstantReflectionProvider constantReflection = context.getConstantReflection(); 291 ConstantNode klassHint = ConstantNode.forConstant(hubStamp, constantReflection.asObjectHub(type), context.getMetaAccess(), graph); 292 FixedWithNextNode replacement = graph.add(new ResolveMethodAndLoadCountersNode(node.getMethod(), klassHint)); 293 graph.addAfterFixed(findFixedWithNextBefore(graph, node), replacement); 294 node.replaceAtUsages(replacement, n -> !(n instanceof ResolveMethodAndLoadCountersNode)); 295 } 296 297 /** 298 * Replace {@link LoadMethodCountersNode} with {@link ResolveMethodAndLoadCountersNode}, expose 299 * klass constants. 300 * 301 * @param graph 302 * @param context 303 */ 304 private static void replaceLoadMethodCounters(StructuredGraph graph, PhaseContext context) { 305 new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false); 306 for (LoadMethodCountersNode node : getLoadMethodCountersNodes(graph)) { 307 if (anyUsagesNeedReplacement(node)) { 308 handleLoadMethodCounters(graph, node, context); 309 } 310 } 311 } 312 313 /** 314 * Replace object and klass constants with resolution nodes or reuse preceding initializations. 315 * 316 * @param graph 317 */ 318 private void replaceKlassesAndObjects(StructuredGraph graph) { 319 new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false); 320 321 for (ConstantNode node : getConstantNodes(graph)) { 322 Constant constant = node.asConstant(); 323 if (constant instanceof HotSpotMetaspaceConstant && anyUsagesNeedReplacement(node)) { 324 handleHotSpotMetaspaceConstant(graph, node); 325 } else if (constant instanceof HotSpotObjectConstant && anyUsagesNeedReplacement(node)) { 326 handleHotSpotObjectConstant(graph, node); 327 } 328 } 329 } 330 331 @Override 332 protected void run(StructuredGraph graph, PhaseContext context) { 333 // Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass 334 // constants. 335 replaceLoadMethodCounters(graph, context); 336 337 // Replace object and klass constants (including the ones added in the previous pass) with 338 // resolution nodes. 339 replaceKlassesAndObjects(graph); 340 } 341 342 @Override 343 public boolean checkContract() { 344 return false; 345 } 346 347 public ReplaceConstantNodesPhase() { 348 this(true); 349 } 350 351 public ReplaceConstantNodesPhase(boolean verifyFingerprints) { 352 this.verifyFingerprints = verifyFingerprints; 353 } 354 } | 1 /* 2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.hotspot.phases.aot; 24 25 import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates; 26 import static org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode.getLoadMethodCountersNodes; 27 import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; 28 29 import java.util.HashSet; 30 import java.util.List; 31 32 import org.graalvm.compiler.core.common.cfg.BlockMap; 33 import org.graalvm.compiler.core.common.type.ObjectStamp; 34 import org.graalvm.compiler.core.common.type.Stamp; 35 import org.graalvm.compiler.core.common.type.StampFactory; 36 import org.graalvm.compiler.debug.GraalError; 37 import org.graalvm.compiler.graph.Node; 38 import org.graalvm.compiler.graph.NodeMap; 39 import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; 40 import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; 41 import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode; 42 import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; 43 import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode; 44 import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; 45 import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; 46 import org.graalvm.compiler.nodes.AbstractBeginNode; 47 import org.graalvm.compiler.nodes.AbstractMergeNode; 48 import org.graalvm.compiler.nodes.ConstantNode; 49 import org.graalvm.compiler.nodes.FixedNode; 50 import org.graalvm.compiler.nodes.FixedWithNextNode; 51 import org.graalvm.compiler.nodes.FrameState; 52 import org.graalvm.compiler.nodes.LoopBeginNode; 53 import org.graalvm.compiler.nodes.LoopExitNode; 54 import org.graalvm.compiler.nodes.StateSplit; 55 import org.graalvm.compiler.nodes.StructuredGraph; 56 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; 57 import org.graalvm.compiler.nodes.ValueNode; 58 import org.graalvm.compiler.nodes.calc.FloatingNode; 59 import org.graalvm.compiler.nodes.cfg.Block; 60 import org.graalvm.compiler.phases.BasePhase; 61 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; 62 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; 63 import org.graalvm.compiler.phases.schedule.SchedulePhase; 64 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; 65 import org.graalvm.compiler.phases.tiers.PhaseContext; 66 import org.graalvm.util.EconomicMap; 67 68 import jdk.vm.ci.code.BytecodeFrame; 69 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; 70 import jdk.vm.ci.hotspot.HotSpotObjectConstant; 71 import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; 72 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; 73 import jdk.vm.ci.meta.Constant; 74 import jdk.vm.ci.meta.ConstantReflectionProvider; 75 import jdk.vm.ci.meta.ResolvedJavaType; 76 77 public class ReplaceConstantNodesPhase extends BasePhase<PhaseContext> { 78 79 private static final HashSet<Class<?>> builtIns = new HashSet<>(); 80 private final boolean verifyFingerprints; 81 82 static { 83 builtIns.add(Boolean.class); 84 85 Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0]; 86 assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); 87 builtIns.add(characterCacheClass); 88 89 Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0]; 90 assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); 91 builtIns.add(byteCacheClass); 92 93 Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0]; 94 assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); 95 builtIns.add(shortCacheClass); 96 108 return n instanceof LoadConstantIndirectlyNode || 109 n instanceof LoadConstantIndirectlyFixedNode || 110 n instanceof ResolveConstantNode || 111 n instanceof InitializeKlassNode; 112 // @formatter:on 113 } 114 115 private static boolean anyUsagesNeedReplacement(ConstantNode node) { 116 return node.usages().filter(n -> !isReplacementNode(n)).isNotEmpty(); 117 } 118 119 private static boolean anyUsagesNeedReplacement(LoadMethodCountersNode node) { 120 return node.usages().filter(n -> !(n instanceof ResolveMethodAndLoadCountersNode)).isNotEmpty(); 121 } 122 123 private static boolean checkForBadFingerprint(HotSpotResolvedJavaType type) { 124 if (type.isArray()) { 125 if (type.getElementalType().isPrimitive()) { 126 return false; 127 } 128 return ((HotSpotResolvedObjectType) (type.getElementalType())).getFingerprint() == 0; 129 } 130 return ((HotSpotResolvedObjectType) type).getFingerprint() == 0; 131 } 132 133 /** 134 * Insert the replacement node into the graph. We may need to insert it into a place different 135 * than the original {@link FloatingNode} since we need to make sure that replacement will have 136 * a valid state assigned. 137 * 138 * @param graph 139 * @param stateMapper 140 * @param node 141 * @param replacement 142 */ 143 private static void insertReplacement(StructuredGraph graph, FrameStateMapperClosure stateMapper, FloatingNode node, FixedWithNextNode replacement) { 144 FixedWithNextNode insertionPoint = findInsertionPoint(graph, stateMapper, node); 145 graph.addAfterFixed(insertionPoint, replacement); 146 stateMapper.addState(replacement, stateMapper.getState(insertionPoint)); 147 } 148 149 /** 150 * Find a good place to insert a stateful fixed node that is above the given node. A good 151 * insertion point should have a valid FrameState reaching it. 152 * 153 * @param graph 154 * @param stateMapper 155 * @param node start search from this node up 156 * @return an insertion point 157 */ 158 private static FixedWithNextNode findInsertionPoint(StructuredGraph graph, FrameStateMapperClosure stateMapper, FloatingNode node) { 159 FixedWithNextNode fixed = findFixedBeforeFloating(graph, node); 160 FixedWithNextNode result = findFixedWithValidState(graph, stateMapper, fixed); 161 return result; 162 } 163 164 /** 165 * Find the first {@link FixedWithNextNode} that is currently scheduled before the given 166 * floating node. 167 * 168 * @param graph 169 * @param node start search from this node up 170 * @return the first {@link FixedWithNextNode} 171 */ 172 private static FixedWithNextNode findFixedBeforeFloating(StructuredGraph graph, FloatingNode node) { 173 ScheduleResult schedule = graph.getLastSchedule(); 174 NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap(); 175 Block block = nodeToBlock.get(node); 176 BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap(); 177 FixedWithNextNode result = null; 178 for (Node n : blockToNodes.get(block)) { 179 if (n.equals(node)) { 180 break; 181 } 182 if (n instanceof FixedWithNextNode) { 183 result = (FixedWithNextNode) n; 184 } 185 } 186 assert result != null; 187 return result; 188 } 189 190 /** 191 * Find first dominating {@link FixedWithNextNode} that has a valid state reaching it starting 192 * from the given node. 193 * 194 * @param graph 195 * @param stateMapper 196 * @param node 197 * @return {@link FixedWithNextNode} that we can use as an insertion point 198 */ 199 private static FixedWithNextNode findFixedWithValidState(StructuredGraph graph, FrameStateMapperClosure stateMapper, FixedWithNextNode node) { 200 ScheduleResult schedule = graph.getLastSchedule(); 201 NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap(); 202 Block block = nodeToBlock.get(node); 203 204 Node n = node; 205 do { 206 if (isFixedWithValidState(stateMapper, n)) { 207 return (FixedWithNextNode) n; 208 } 209 while (n != block.getBeginNode()) { 210 n = n.predecessor(); 211 if (isFixedWithValidState(stateMapper, n)) { 212 return (FixedWithNextNode) n; 213 } 214 } 215 block = block.getDominator(); 216 if (block != null) { 217 n = block.getEndNode(); 218 } 219 } while (block != null); 220 221 return graph.start(); 222 } 223 224 private static boolean isFixedWithValidState(FrameStateMapperClosure stateMapper, Node n) { 225 if (n instanceof FixedWithNextNode) { 226 FixedWithNextNode fixed = (FixedWithNextNode) n; 227 assert stateMapper.getState(fixed) != null; 228 if (!BytecodeFrame.isPlaceholderBci(stateMapper.getState(fixed).bci)) { 229 return true; 230 } 231 } 232 return false; 233 } 234 235 /** 236 * Compute frame states for all fixed nodes in the graph. 237 */ 238 private static class FrameStateMapperClosure extends NodeIteratorClosure<FrameState> { 239 private NodeMap<FrameState> reachingStates; 240 241 @Override 242 protected FrameState processNode(FixedNode node, FrameState previousState) { 243 FrameState currentState = previousState; 244 if (node instanceof StateSplit) { 245 StateSplit stateSplit = (StateSplit) node; 246 FrameState stateAfter = stateSplit.stateAfter(); 247 if (stateAfter != null) { 248 currentState = stateAfter; 249 } 250 } 251 reachingStates.put(node, currentState); 252 return currentState; 253 } 254 255 @Override 256 protected FrameState merge(AbstractMergeNode merge, List<FrameState> states) { 257 FrameState singleFrameState = singleFrameState(states); 258 FrameState currentState = singleFrameState == null ? merge.stateAfter() : singleFrameState; 259 reachingStates.put(merge, currentState); 260 return currentState; 261 } 262 263 @Override 264 protected FrameState afterSplit(AbstractBeginNode node, FrameState oldState) { 265 return oldState; 266 } 267 268 @Override 269 protected EconomicMap<LoopExitNode, FrameState> processLoop(LoopBeginNode loop, FrameState initialState) { 270 return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates; 271 } 272 273 private static FrameState singleFrameState(List<FrameState> states) { 274 FrameState singleState = states.get(0); 275 for (int i = 1; i < states.size(); ++i) { 276 if (states.get(i) != singleState) { 277 return null; 278 } 279 } 280 return singleState; 281 } 282 283 FrameStateMapperClosure(StructuredGraph graph) { 284 reachingStates = new NodeMap<>(graph); 285 } 286 287 public FrameState getState(Node n) { 288 return reachingStates.get(n); 289 } 290 291 public void addState(Node n, FrameState s) { 292 reachingStates.setAndGrow(n, s); 293 } 294 } 295 296 /** 297 * Try to find dominating node doing the resolution that can be reused. 298 * 299 * @param graph 300 * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs 301 * resolution. 302 */ 303 private static void tryToReplaceWithExisting(StructuredGraph graph, ConstantNode node) { 304 ScheduleResult schedule = graph.getLastSchedule(); 305 NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap(); 306 BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap(); 307 308 EconomicMap<Block, Node> blockToExisting = EconomicMap.create(); 309 for (Node n : node.usages().filter(n -> isReplacementNode(n))) { 310 blockToExisting.put(nodeToBlock.get(n), n); 311 } 312 for (Node use : node.usages().filter(n -> !isReplacementNode(n)).snapshot()) { 313 boolean replaced = false; 314 Block b = nodeToBlock.get(use); 315 Node e = blockToExisting.get(b); 316 if (e != null) { 328 } 329 } 330 } 331 if (!replaced) { 332 // Look for dominating blocks that have existing nodes 333 for (Block d : blockToExisting.getKeys()) { 334 if (strictlyDominates(d, b)) { 335 use.replaceFirstInput(node, blockToExisting.get(d)); 336 break; 337 } 338 } 339 } 340 } 341 } 342 343 /** 344 * Replace the uses of a constant with either {@link LoadConstantIndirectlyNode} or 345 * {@link ResolveConstantNode}. 346 * 347 * @param graph 348 * @param stateMapper 349 * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs 350 * resolution. 351 */ 352 private static void replaceWithResolution(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node) { 353 HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant(); 354 HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType(); 355 ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass(); 356 ValueNode replacement; 357 358 if (type.isArray() && type.getComponentType().isPrimitive()) { 359 // Special case for primitive arrays. The AOT runtime pre-resolves them, so we may 360 // omit the resolution call. 361 replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node)); 362 } else if (type.equals(topMethodHolder) || (type.isAssignableFrom(topMethodHolder) && !type.isInterface())) { 363 // If it's a supertype of or the same class that declares the top method, we are 364 // guaranteed to have it resolved already. If it's an interface, we just test for 365 // equality. 366 replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node)); 367 } else { 368 FixedWithNextNode fixedReplacement; 369 if (builtIns.contains(type.mirror())) { 370 // Special case of klass constants that come from {@link BoxingSnippets}. 371 fixedReplacement = graph.add(new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE)); 372 } else { 373 fixedReplacement = graph.add(new ResolveConstantNode(node)); 374 } 375 insertReplacement(graph, stateMapper, node, fixedReplacement); 376 replacement = fixedReplacement; 377 } 378 node.replaceAtUsages(replacement, n -> !isReplacementNode(n)); 379 } 380 381 /** 382 * Replace {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} with indirection. 383 * 384 * @param graph 385 * @param stateMapper 386 * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs 387 * resolution. 388 */ 389 private void handleHotSpotMetaspaceConstant(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node) { 390 HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant(); 391 HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType(); 392 393 if (type != null) { 394 if (verifyFingerprints && checkForBadFingerprint(type)) { 395 throw new GraalError("Type with bad fingerprint: " + type); 396 } 397 assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants"; 398 tryToReplaceWithExisting(graph, node); 399 if (anyUsagesNeedReplacement(node)) { 400 replaceWithResolution(graph, stateMapper, node); 401 } 402 } else { 403 throw new GraalError("Unsupported metaspace constant type: " + type); 404 } 405 } 406 407 /** 408 * Replace an object constant with an indirect load {@link ResolveConstantNode}. Currently we 409 * support only strings. 410 * 411 * @param graph 412 * @param stateMapper 413 * @param node {@link ConstantNode} containing a {@link HotSpotObjectConstant} that needs 414 * resolution. 415 */ 416 private static void handleHotSpotObjectConstant(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node) { 417 HotSpotObjectConstant constant = (HotSpotObjectConstant) node.asJavaConstant(); 418 HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) constant.getType(); 419 if (type.mirror().equals(String.class)) { 420 assert !constant.isCompressed() : "No support for replacing compressed oop constants"; 421 FixedWithNextNode replacement = graph.add(new ResolveConstantNode(node)); 422 insertReplacement(graph, stateMapper, node, replacement); 423 node.replaceAtUsages(replacement, n -> !(n instanceof ResolveConstantNode)); 424 } else { 425 throw new GraalError("Unsupported object constant type: " + type); 426 } 427 } 428 429 /** 430 * Replace {@link LoadMethodCountersNode} with indirect load 431 * {@link ResolveMethodAndLoadCountersNode}, expose a klass constant of the holder. 432 * 433 * @param graph 434 * @param stateMapper 435 * @param node 436 * @param context 437 */ 438 private static void handleLoadMethodCounters(StructuredGraph graph, FrameStateMapperClosure stateMapper, LoadMethodCountersNode node, PhaseContext context) { 439 ResolvedJavaType type = node.getMethod().getDeclaringClass(); 440 Stamp hubStamp = context.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull()); 441 ConstantReflectionProvider constantReflection = context.getConstantReflection(); 442 ConstantNode klassHint = ConstantNode.forConstant(hubStamp, constantReflection.asObjectHub(type), context.getMetaAccess(), graph); 443 FixedWithNextNode replacement = graph.add(new ResolveMethodAndLoadCountersNode(node.getMethod(), klassHint)); 444 insertReplacement(graph, stateMapper, node, replacement); 445 node.replaceAtUsages(replacement, n -> !(n instanceof ResolveMethodAndLoadCountersNode)); 446 } 447 448 /** 449 * Replace {@link LoadMethodCountersNode} with {@link ResolveMethodAndLoadCountersNode}, expose 450 * klass constants. 451 * 452 * @param graph 453 * @param stateMapper 454 * @param context 455 */ 456 private static void replaceLoadMethodCounters(StructuredGraph graph, FrameStateMapperClosure stateMapper, PhaseContext context) { 457 new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false); 458 459 for (LoadMethodCountersNode node : getLoadMethodCountersNodes(graph)) { 460 if (anyUsagesNeedReplacement(node)) { 461 handleLoadMethodCounters(graph, stateMapper, node, context); 462 } 463 } 464 } 465 466 /** 467 * Replace object and klass constants with resolution nodes or reuse preceding initializations. 468 * 469 * @param graph 470 * @param stateMapper 471 */ 472 private void replaceKlassesAndObjects(StructuredGraph graph, FrameStateMapperClosure stateMapper) { 473 new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false); 474 475 for (ConstantNode node : getConstantNodes(graph)) { 476 Constant constant = node.asConstant(); 477 if (constant instanceof HotSpotMetaspaceConstant && anyUsagesNeedReplacement(node)) { 478 handleHotSpotMetaspaceConstant(graph, stateMapper, node); 479 } else if (constant instanceof HotSpotObjectConstant && anyUsagesNeedReplacement(node)) { 480 handleHotSpotObjectConstant(graph, stateMapper, node); 481 } 482 } 483 } 484 485 @Override 486 protected void run(StructuredGraph graph, PhaseContext context) { 487 FrameStateMapperClosure stateMapper = new FrameStateMapperClosure(graph); 488 ReentrantNodeIterator.apply(stateMapper, graph.start(), null); 489 490 // Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass 491 // constants. 492 replaceLoadMethodCounters(graph, stateMapper, context); 493 494 // Replace object and klass constants (including the ones added in the previous pass) with 495 // resolution nodes. 496 replaceKlassesAndObjects(graph, stateMapper); 497 } 498 499 @Override 500 public boolean checkContract() { 501 return false; 502 } 503 504 public ReplaceConstantNodesPhase() { 505 this(true); 506 } 507 508 public ReplaceConstantNodesPhase(boolean verifyFingerprints) { 509 this.verifyFingerprints = verifyFingerprints; 510 } 511 } |