@Override public void lower(LoweringTool tool) { StructuredGraph replacementGraph = getLoweredSnippetGraph(tool); InvokeNode invoke = replaceWithInvoke(); assert invoke.verify(); if (replacementGraph != null) { // Pull out the receiver null check so that a replaced // receiver can be lowered if necessary if (!targetMethod.isStatic()) { ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke); if (nonNullReceiver instanceof Lowerable) { ((Lowerable) nonNullReceiver).lower(tool); } } InliningUtil.inline(invoke, replacementGraph, false, null); Debug.dump(Debug.INFO_LOG_LEVEL, graph(), "After inlining replacement %s", replacementGraph); } else { if (isPlaceholderBci(invoke.bci())) { throw new GraalError("%s: cannot lower to invoke with placeholder BCI: %s", graph(), this); } if (invoke.stateAfter() == null) { ResolvedJavaMethod method = graph().method(); if (method.getAnnotation(MethodSubstitution.class) != null || method.getAnnotation(Snippet.class) != null) { // One cause for this is that a MacroNode is created for a method that // no longer needs a MacroNode. For example, Class.getComponentType() // only needs a MacroNode prior to JDK9 as it was given a non-native // implementation in JDK9. throw new GraalError( "%s macro created for call to %s in %s must be lowerable to a snippet or intrinsic graph. " + "Maybe a macro node is not needed for this method in the current JDK?", getClass().getSimpleName(), targetMethod.format("%h.%n(%p)"), graph()); } throw new GraalError("%s: cannot lower to invoke without state: %s", graph(), this); } invoke.lower(tool); } }
/** * Checks that lowering of a given node did not introduce any new {@link Lowerable} nodes that * could be lowered in the current {@link LoweringPhase}. Such nodes must be recursively lowered * as part of lowering {@code node}. * * @param node a node that was just lowered * @param preLoweringMark the graph mark before {@code node} was lowered * @param unscheduledUsages set of {@code node}'s usages that were unscheduled before it was * lowered * @throws AssertionError if the check fails */ private static boolean checkPostNodeLowering( Node node, LoweringToolImpl loweringTool, Mark preLoweringMark, Collection<Node> unscheduledUsages) { StructuredGraph graph = (StructuredGraph) node.graph(); Mark postLoweringMark = graph.getMark(); NodeIterable<Node> newNodesAfterLowering = graph.getNewNodes(preLoweringMark); if (node instanceof FloatingNode) { if (!unscheduledUsages.isEmpty()) { for (Node n : newNodesAfterLowering) { assert !(n instanceof FixedNode) : node.graph() + ": cannot lower floatable node " + node + " as it introduces fixed node(s) but has the following unscheduled usages: " + unscheduledUsages; } } } for (Node n : newNodesAfterLowering) { if (n instanceof Lowerable) { ((Lowerable) n).lower(loweringTool); Mark mark = graph.getMark(); assert postLoweringMark.equals(mark) : graph + ": lowering of " + node + " produced lowerable " + n + " that should have been recursively lowered as it introduces these new nodes: " + graph.getNewNodes(postLoweringMark).snapshot(); } } return true; }
@SuppressWarnings("try") private AnchoringNode process( final Block b, final NodeBitMap activeGuards, final AnchoringNode startAnchor) { final LoweringToolImpl loweringTool = new LoweringToolImpl(context, startAnchor, activeGuards, b.getBeginNode()); // Lower the instructions of this block. List<Node> nodes = schedule.nodesFor(b); for (Node node : nodes) { if (node.isDeleted()) { // This case can happen when previous lowerings deleted nodes. continue; } // Cache the next node to be able to reconstruct the previous of the next node // after lowering. FixedNode nextNode = null; if (node instanceof FixedWithNextNode) { nextNode = ((FixedWithNextNode) node).next(); } else { nextNode = loweringTool.lastFixedNode().next(); } if (node instanceof Lowerable) { Collection<Node> unscheduledUsages = null; assert (unscheduledUsages = getUnscheduledUsages(node)) != null; Mark preLoweringMark = node.graph().getMark(); try (DebugCloseable s = node.graph().withNodeContext(node)) { ((Lowerable) node).lower(loweringTool); } if (loweringTool.guardAnchor.asNode().isDeleted()) { // TODO nextNode could be deleted but this is not currently supported assert nextNode.isAlive(); loweringTool.guardAnchor = AbstractBeginNode.prevBegin(nextNode); } assert checkPostNodeLowering(node, loweringTool, preLoweringMark, unscheduledUsages); } if (!nextNode.isAlive()) { // can happen when the rest of the block is killed by lowering // (e.g. by an unconditional deopt) break; } else { Node nextLastFixed = nextNode.predecessor(); if (!(nextLastFixed instanceof FixedWithNextNode)) { // insert begin node, to have a valid last fixed for next lowerable node. // This is about lowering a FixedWithNextNode to a control split while this // FixedWithNextNode is followed by some kind of BeginNode. // For example the when a FixedGuard followed by a loop exit is lowered to a // control-split + deopt. AbstractBeginNode begin = node.graph().add(new BeginNode()); nextLastFixed.replaceFirstSuccessor(nextNode, begin); begin.setNext(nextNode); nextLastFixed = begin; } loweringTool.setLastFixedNode((FixedWithNextNode) nextLastFixed); } } return loweringTool.getCurrentGuardAnchor(); }