# HG changeset patch # User Christian Wimmer # Date 1429658303 25200 # Node ID d094ea7e0433b28e4d10bc802449dffe4f705272 # Parent 2e35a4ea22acfaa3d1e0df1ce70cc788d1d7d839 Move PEGraphDecoder from truffle to graal project; factor out SimplifyingGraphDecoder that performs just canonicalization but not method inlining; fix bugs diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Tue Apr 21 10:47:43 2015 -0700 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Tue Apr 21 16:18:23 2015 -0700 @@ -124,7 +124,7 @@ frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || replacementContext != null, graphBuilderConfig.getPlugins().getParameterPlugin()); parser.build(graph.start(), frameState); - connectLoopEndToBegin(graph); + GraphUtil.normalizeLoops(graph); // Remove dead parameters. for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { @@ -2428,27 +2428,4 @@ assert assertionsEnabled = true; return assertionsEnabled; } - - /** - * Remove loop header without loop ends. This can happen with degenerated loops like this one: - * - *
-     * for (;;) {
-     *     try {
-     *         break;
-     *     } catch (UnresolvedException iioe) {
-     *     }
-     * }
-     * 
- */ - public static void connectLoopEndToBegin(StructuredGraph graph) { - for (LoopBeginNode begin : graph.getNodes(LoopBeginNode.TYPE)) { - if (begin.loopEnds().isEmpty()) { - assert begin.forwardEndCount() == 1; - graph.reduceDegenerateLoopBegin(begin); - } else { - GraphUtil.normalizeLoopBegin(begin); - } - } - } } diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java Tue Apr 21 10:47:43 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java Tue Apr 21 16:18:23 2015 -0700 @@ -257,10 +257,14 @@ } public final void decode(StructuredGraph graph, EncodedGraph encodedGraph) { - MethodScope methodScope = new MethodScope(graph, encodedGraph, LoopExplosionKind.NONE); - decode(methodScope, null); - cleanupGraph(methodScope, null); - methodScope.graph.verify(); + try (Debug.Scope scope = Debug.scope("GraphDecoder", graph)) { + MethodScope methodScope = new MethodScope(graph, encodedGraph, LoopExplosionKind.NONE); + decode(methodScope, null); + cleanupGraph(methodScope, null); + methodScope.graph.verify(); + } catch (Throwable ex) { + Debug.handle(ex); + } } protected final void decode(MethodScope methodScope, FixedWithNextNode startNode) { @@ -287,6 +291,7 @@ assert loopScope.nextIterations.peekFirst().loopIteration == loopScope.loopIteration + 1; loopScope = loopScope.nextIterations.removeFirst(); } else { + propagateCreatedNodes(loopScope); loopScope = loopScope.outer; } } @@ -303,6 +308,19 @@ } } + private static void propagateCreatedNodes(LoopScope loopScope) { + if (loopScope.outer == null) { + return; + } + + /* Register nodes that were created while decoding the loop to the outside scope. */ + for (int i = 0; i < loopScope.createdNodes.length; i++) { + if (loopScope.outer.createdNodes[i] == null) { + loopScope.outer.createdNodes[i] = loopScope.createdNodes[i]; + } + } + } + protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope) { int nodeOrderId = loopScope.nodesToProcess.nextSetBit(0); loopScope.nodesToProcess.clear(nodeOrderId); diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java Tue Apr 21 10:47:43 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java Tue Apr 21 16:18:23 2015 -0700 @@ -442,9 +442,6 @@ } } - for (Node expectedNode : expectedGraph.getNodes()) { - assert nodeMapping.get(expectedNode) != null || (expectedNode.hasNoUsages() && !(expectedNode instanceof FixedNode)) : "expectedNode"; - } return true; } @@ -486,7 +483,19 @@ assert !actualIter.hasNext(); } - protected static void verifyNodeEqual(Node expectedNode, Node actualNode, NodeMap nodeMapping, Deque> workList, boolean ignoreEndNode) { + protected static void verifyNodeEqual(Node e, Node actualNode, NodeMap nodeMapping, Deque> workList, boolean ignoreEndNode) { + Node expectedNode = e; + if (expectedNode instanceof PhiNode) { + /* + * The input graph can contain unnecessary (eliminatable) phi functions. Such phis are + * not re-created during decoding, so we need to simplify the expected node too. + */ + Node singleValue = ((PhiNode) expectedNode).singleValue(); + if (singleValue != null && singleValue != PhiNode.MULTIPLE_VALUES) { + expectedNode = singleValue; + } + } + assert expectedNode.getClass() == actualNode.getClass(); if (ignoreEndNode && expectedNode instanceof EndNode) { return; diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java Tue Apr 21 16:18:23 2015 -0700 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2015, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; + +/** + * Graph decoder that simplifies nodes during decoding. The standard + * {@link Canonicalizable#canonical node canonicalization} interface is used to canonicalize nodes + * during decoding. Additionally, {@link IfNode branches} and {@link IntegerSwitchNode switches} + * with constant conditions are simplified. + */ +public class SimplifyingGraphDecoder extends GraphDecoder { + + protected final MetaAccessProvider metaAccess; + protected final ConstantReflectionProvider constantReflection; + protected final StampProvider stampProvider; + protected final boolean canonicalizeReads; + + protected class PECanonicalizerTool implements CanonicalizerTool { + @Override + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + + @Override + public ConstantReflectionProvider getConstantReflection() { + return constantReflection; + } + + @Override + public boolean canonicalizeReads() { + return canonicalizeReads; + } + + @Override + public boolean allUsagesAvailable() { + return false; + } + } + + public SimplifyingGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, boolean canonicalizeReads, Architecture architecture) { + super(architecture); + this.metaAccess = metaAccess; + this.constantReflection = constantReflection; + this.stampProvider = stampProvider; + this.canonicalizeReads = canonicalizeReads; + } + + @Override + protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) { + GraphUtil.normalizeLoops(methodScope.graph); + super.cleanupGraph(methodScope, start); + } + + @Override + protected void simplifyFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) { + if (node instanceof IfNode) { + IfNode ifNode = (IfNode) node; + if (ifNode.condition() instanceof LogicNegationNode) { + ifNode.eliminateNegation(); + } + if (ifNode.condition() instanceof LogicConstantNode) { + boolean condition = ((LogicConstantNode) ifNode.condition()).getValue(); + AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition); + AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition); + + methodScope.graph.removeSplit(ifNode, survivingSuccessor); + assert deadSuccessor.next() == null : "must not be parsed yet"; + deadSuccessor.safeDelete(); + } + + } else if (node instanceof IntegerSwitchNode && ((IntegerSwitchNode) node).value().isConstant()) { + IntegerSwitchNode switchNode = (IntegerSwitchNode) node; + int value = switchNode.value().asJavaConstant().asInt(); + AbstractBeginNode survivingSuccessor = switchNode.successorAtKey(value); + List allSuccessors = switchNode.successors().snapshot(); + + methodScope.graph.removeSplit(switchNode, survivingSuccessor); + for (Node successor : allSuccessors) { + if (successor != survivingSuccessor) { + assert ((AbstractBeginNode) successor).next() == null : "must not be parsed yet"; + successor.safeDelete(); + } + } + + } else if (node instanceof Canonicalizable) { + Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool()); + if (canonical == null) { + /* + * This is a possible return value of canonicalization. However, we might need to + * add additional usages later on for which we need a node. Therefore, we just do + * nothing and leave the node in place. + */ + } else if (canonical != node) { + if (!canonical.isAlive()) { + assert !canonical.isDeleted(); + canonical = methodScope.graph.addOrUniqueWithInputs(canonical); + if (canonical instanceof FixedWithNextNode) { + methodScope.graph.addBeforeFixed(node, (FixedWithNextNode) canonical); + } else if (canonical instanceof ControlSinkNode) { + FixedWithNextNode predecessor = (FixedWithNextNode) node.predecessor(); + predecessor.setNext((ControlSinkNode) canonical); + node.safeDelete(); + for (Node successor : node.successors()) { + successor.safeDelete(); + } + + } else { + assert !(canonical instanceof FixedNode); + } + } + if (!node.isDeleted()) { + GraphUtil.unlinkFixedNode((FixedWithNextNode) node); + node.replaceAtUsages(canonical); + node.safeDelete(); + } + assert lookupNode(loopScope, nodeOrderId) == node; + registerNode(loopScope, nodeOrderId, canonical, true, false); + } + } + } + + @Override + protected Node handleFloatingNodeBeforeAdd(MethodScope methodScope, LoopScope loopScope, Node node) { + if (node instanceof Canonicalizable) { + Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool()); + if (canonical == null) { + /* + * This is a possible return value of canonicalization. However, we might need to + * add additional usages later on for which we need a node. Therefore, we just do + * nothing and leave the node in place. + */ + } else if (canonical != node) { + if (!canonical.isAlive()) { + assert !canonical.isDeleted(); + canonical = methodScope.graph.addOrUniqueWithInputs(canonical); + } + assert node.hasNoUsages(); + // methodScope.graph.replaceFloating((FloatingNode) node, canonical); + return canonical; + } + } + return node; + } +} diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Tue Apr 21 10:47:43 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Tue Apr 21 16:18:23 2015 -0700 @@ -79,7 +79,7 @@ if (result != null) { return result; } - Assumptions assumptions = graph().getAssumptions(); + Assumptions assumptions = graph() == null ? null : graph().getAssumptions(); if (assumptions != null) { AssumptionResult leafConcreteSubtype = stampType.findLeafConcreteSubtype(); if (leafConcreteSubtype != null) { diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Tue Apr 21 10:47:43 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Tue Apr 21 16:18:23 2015 -0700 @@ -225,7 +225,30 @@ } } - public static void normalizeLoopBegin(LoopBeginNode begin) { + /** + * Remove loop header without loop ends. This can happen with degenerated loops like this one: + * + *
+     * for (;;) {
+     *     try {
+     *         break;
+     *     } catch (UnresolvedException iioe) {
+     *     }
+     * }
+     * 
+ */ + public static void normalizeLoops(StructuredGraph graph) { + for (LoopBeginNode begin : graph.getNodes(LoopBeginNode.TYPE)) { + if (begin.loopEnds().isEmpty()) { + assert begin.forwardEndCount() == 1; + graph.reduceDegenerateLoopBegin(begin); + } else { + normalizeLoopBegin(begin); + } + } + } + + private static void normalizeLoopBegin(LoopBeginNode begin) { // Delete unnecessary loop phi functions, i.e., phi functions where all inputs are either // the same or the phi itself. for (PhiNode phi : begin.phis().snapshot()) { diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CachingPEGraphDecoder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CachingPEGraphDecoder.java Tue Apr 21 16:18:23 2015 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.phases.util.*; + +/** + * A graph decoder that provides all necessary encoded graphs on-the-fly (by parsing the methods and + * encoding the graphs). + */ +public class CachingPEGraphDecoder extends PEGraphDecoder { + + private final Providers providers; + private final GraphBuilderConfiguration graphBuilderConfig; + private final OptimisticOptimizations optimisticOpts; + private final AllowAssumptions allowAssumptions; + private final Map graphCache; + + public CachingPEGraphDecoder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, AllowAssumptions allowAssumptions, Architecture architecture) { + super(providers.getMetaAccess(), providers.getConstantReflection(), providers.getStampProvider(), architecture); + + this.providers = providers; + this.graphBuilderConfig = graphBuilderConfig; + this.optimisticOpts = optimisticOpts; + this.allowAssumptions = allowAssumptions; + this.graphCache = new HashMap<>(); + } + + private EncodedGraph createGraph(ResolvedJavaMethod method) { + StructuredGraph graph = new StructuredGraph(method, allowAssumptions); + try (Debug.Scope scope = Debug.scope("createGraph", graph)) { + + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), graphBuilderConfig, optimisticOpts, null).apply(graph); + + PhaseContext context = new PhaseContext(providers); + new CanonicalizerPhase().apply(graph, context); + + EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, architecture); + graphCache.put(method, encodedGraph); + return encodedGraph; + + } catch (Throwable ex) { + throw Debug.handle(ex); + } + } + + @Override + protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method) { + EncodedGraph result = graphCache.get(method); + if (result == null && method.hasBytecodes()) { + result = createGraph(method); + } + return result; + } +} diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java Tue Apr 21 16:18:23 2015 -0700 @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2015, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import static com.oracle.graal.compiler.common.GraalInternalError.*; +import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver; +import com.oracle.graal.java.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.common.inlining.*; + +/** + * A graph decoder that performs partial evaluation, i.e., that performs method inlining and + * canonicalization/simplification of nodes during decoding. + * + * Inlining and loop explosion are configured via the plugin mechanism also used by the + * {@link GraphBuilderPhase}. However, not all callback methods defined in + * {@link GraphBuilderContext} are available since decoding is more limited than graph building. + * + * The standard {@link Canonicalizable#canonical node canonicalization} interface is used to + * canonicalize nodes during decoding. Additionally, {@link IfNode branches} and + * {@link IntegerSwitchNode switches} with constant conditions are simplified. + */ +public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { + + protected class PEMethodScope extends MethodScope { + /** The state of the caller method. Only non-null during method inlining. */ + protected final PEMethodScope caller; + protected final LoopScope callerLoopScope; + protected final ResolvedJavaMethod method; + protected final InvokeData invokeData; + protected final int inliningDepth; + + protected final LoopExplosionPlugin loopExplosionPlugin; + protected final InvocationPlugins invocationPlugins; + protected final InlineInvokePlugin inlineInvokePlugin; + protected final ParameterPlugin parameterPlugin; + protected final ValueNode[] arguments; + + protected FrameState outerState; + protected FrameState exceptionState; + protected ExceptionPlaceholderNode exceptionPlaceholderNode; + protected BytecodePosition bytecodePosition; + + protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData, + int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, ParameterPlugin parameterPlugin, + ValueNode[] arguments) { + super(targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin)); + + this.caller = caller; + this.callerLoopScope = callerLoopScope; + this.method = method; + this.invokeData = invokeData; + this.inliningDepth = inliningDepth; + this.loopExplosionPlugin = loopExplosionPlugin; + this.invocationPlugins = invocationPlugins; + this.inlineInvokePlugin = inlineInvokePlugin; + this.parameterPlugin = parameterPlugin; + this.arguments = arguments; + } + + public boolean isInlinedMethod() { + return caller != null; + } + } + + protected class PENonAppendGraphBuilderContext implements GraphBuilderContext { + protected final PEMethodScope methodScope; + protected final Invoke invoke; + + public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) { + this.methodScope = methodScope; + this.invoke = invoke; + } + + @Override + public BailoutException bailout(String string) { + throw new BailoutException(string); + } + + @Override + public StampProvider getStampProvider() { + return stampProvider; + } + + @Override + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + + @Override + public ConstantReflectionProvider getConstantReflection() { + return constantReflection; + } + + @Override + public StructuredGraph getGraph() { + return methodScope.graph; + } + + @Override + public int getDepth() { + return methodScope.inliningDepth; + } + + @Override + public Replacement getReplacement() { + return null; + } + + @Override + public T append(T value) { + throw unimplemented(); + } + + @Override + public T recursiveAppend(T value) { + throw unimplemented(); + } + + @Override + public void push(Kind kind, ValueNode value) { + throw unimplemented(); + } + + @Override + public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) { + throw unimplemented(); + } + + @Override + public void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args) { + throw unimplemented(); + } + + @Override + public FrameState createStateAfter() { + throw unimplemented(); + } + + @Override + public GraphBuilderContext getParent() { + throw unimplemented(); + } + + @Override + public ResolvedJavaMethod getMethod() { + throw unimplemented(); + } + + @Override + public int bci() { + return invoke.bci(); + } + + @Override + public InvokeKind getInvokeKind() { + throw unimplemented(); + } + + @Override + public JavaType getInvokeReturnType() { + throw unimplemented(); + } + } + + protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext { + protected FixedWithNextNode lastInstr; + protected ValueNode pushedNode; + + public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) { + super(inlineScope, inlineScope.invokeData.invoke); + this.lastInstr = lastInstr; + } + + @Override + public void push(Kind kind, ValueNode value) { + if (pushedNode != null) { + throw unimplemented("Only one push is supported"); + } + pushedNode = value; + } + + @Override + public FrameState createStateAfter() { + Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); + getGraph().add(stateAfter); + return (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter); + } + + @Override + public T append(T v) { + if (v.graph() != null) { + return v; + } + T added = getGraph().addOrUnique(v); + if (added == v) { + updateLastInstruction(v); + } + return added; + } + + @Override + public T recursiveAppend(T v) { + if (v.graph() != null) { + return v; + } + T added = getGraph().addOrUniqueWithInputs(v); + if (added == v) { + updateLastInstruction(v); + } + return added; + } + + private void updateLastInstruction(T v) { + if (v instanceof FixedNode) { + FixedNode fixedNode = (FixedNode) v; + lastInstr.setNext(fixedNode); + if (fixedNode instanceof FixedWithNextNode) { + FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode; + assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end"; + lastInstr = fixedWithNextNode; + } else { + lastInstr = null; + } + } + } + } + + @NodeInfo + static class ExceptionPlaceholderNode extends ValueNode { + public static final NodeClass TYPE = NodeClass.create(ExceptionPlaceholderNode.class); + + public ExceptionPlaceholderNode() { + super(TYPE, StampFactory.object()); + } + } + + public PEGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, Architecture architecture) { + super(metaAccess, constantReflection, stampProvider, true, architecture); + } + + protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) { + if (loopExplosionPlugin == null) { + return LoopExplosionKind.NONE; + } else if (loopExplosionPlugin.shouldMergeExplosions(method)) { + return LoopExplosionKind.MERGE_EXPLODE; + } else if (loopExplosionPlugin.shouldExplodeLoops(method)) { + return LoopExplosionKind.FULL_EXPLODE; + } else { + return LoopExplosionKind.NONE; + } + } + + public void decode(StructuredGraph targetGraph, ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, + ParameterPlugin parameterPlugin) { + PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugin, + parameterPlugin, null); + decode(methodScope, null); + cleanupGraph(methodScope, null); + methodScope.graph.verify(); + } + + @Override + protected void checkLoopExplosionIteration(MethodScope s, LoopScope loopScope) { + PEMethodScope methodScope = (PEMethodScope) s; + + if (loopScope.loopIteration > MaximumLoopExplosionCount.getValue()) { + String message = "too many loop explosion iterations - does the explosion not terminate for method " + methodScope.method + "?"; + if (FailedLoopExplosionIsFatal.getValue()) { + throw new RuntimeException(message); + } else { + throw new BailoutException(message); + } + } + } + + @Override + protected void handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) { + PEMethodScope methodScope = (PEMethodScope) s; + + /* + * Decode the call target, but do not add it to the graph yet. This avoids adding usages for + * all the arguments, which are expensive to remove again when we can inline the method. + */ + assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke"; + CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId); + if (!(callTarget instanceof MethodCallTargetNode) || !trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget)) { + + /* We know that we need an invoke, so now we can add the call target to the graph. */ + methodScope.graph.add(callTarget); + registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false); + super.handleInvoke(methodScope, loopScope, invokeData); + } + } + + protected boolean trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { + // attempt to devirtualize the call + ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), invokeData.contextType); + if (specialCallTarget != null) { + callTarget.setTargetMethod(specialCallTarget); + callTarget.setInvokeKind(InvokeKind.Special); + } + + if (tryInvocationPlugin(methodScope, loopScope, invokeData, callTarget)) { + return true; + } + if (tryInline(methodScope, loopScope, invokeData, callTarget)) { + return true; + } + + if (methodScope.inlineInvokePlugin != null) { + methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke); + } + return false; + } + + protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { + if (methodScope.invocationPlugins == null) { + return false; + } + + Invoke invoke = invokeData.invoke; + + ResolvedJavaMethod targetMethod = callTarget.targetMethod(); + InvocationPlugin invocationPlugin = methodScope.invocationPlugins.lookupInvocation(targetMethod); + if (invocationPlugin == null) { + return false; + } + + ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); + FixedWithNextNode invokePredecessor = (FixedWithNextNode) invoke.asNode().predecessor(); + + /* Remove invoke from graph so that invocation plugin can append nodes to the predecessor. */ + invoke.asNode().replaceAtPredecessor(null); + + PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin, + methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments); + PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor); + InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext); + + if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) { + + if (graphBuilderContext.lastInstr != null) { + registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true); + invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode); + graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData)); + } else { + assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?"; + invoke.asNode().replaceAtUsages(null); + } + + deleteInvoke(invoke); + return true; + + } else { + /* Intrinsification failed, restore original state: invoke is in Graph. */ + invokePredecessor.setNext(invoke.asNode()); + return false; + } + } + + protected boolean tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { + if (methodScope.inlineInvokePlugin == null || !callTarget.invokeKind().isDirect()) { + return false; + } + + ResolvedJavaMethod targetMethod = callTarget.targetMethod(); + if (!targetMethod.canBeInlined()) { + return false; + } + + ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); + GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke); + InlineInfo inlineInfo = methodScope.inlineInvokePlugin.getInlineInfo(graphBuilderContext, targetMethod, arguments, callTarget.returnType()); + if (inlineInfo == null) { + return false; + } + assert !inlineInfo.isIntrinsic && !inlineInfo.isReplacement : "not supported"; + + ResolvedJavaMethod inlineMethod = inlineInfo.methodToInline; + EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod); + if (graphToInline == null) { + return false; + } + + Invoke invoke = invokeData.invoke; + FixedNode invokeNode = invoke.asNode(); + FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor(); + invokeNode.replaceAtPredecessor(null); + + PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1, + methodScope.loopExplosionPlugin, methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments); + /* Do the actual inlining by decoding the inlineMethod */ + decode(inlineScope, predecessor); + + ValueNode exceptionValue = null; + if (inlineScope.unwindNode != null) { + exceptionValue = inlineScope.unwindNode.exception(); + } + UnwindNode unwindNode = inlineScope.unwindNode; + + if (invoke instanceof InvokeWithExceptionNode) { + InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke); + assert invokeWithException.next() == null; + assert invokeWithException.exceptionEdge() == null; + + if (unwindNode != null) { + assert unwindNode.predecessor() != null; + Node n = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId); + unwindNode.replaceAndDelete(n); + } + + } else { + if (unwindNode != null && !unwindNode.isDeleted()) { + DeoptimizeNode deoptimizeNode = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); + unwindNode.replaceAndDelete(deoptimizeNode); + } + } + + assert invoke.next() == null; + + ValueNode returnValue; + List returnNodes = inlineScope.returnNodes; + if (!returnNodes.isEmpty()) { + FixedNode n; + n = nodeAfterInvoke(methodScope, loopScope, invokeData); + if (returnNodes.size() == 1) { + ReturnNode returnNode = returnNodes.get(0); + returnValue = returnNode.result(); + returnNode.replaceAndDelete(n); + } else { + AbstractMergeNode merge = methodScope.graph.add(new MergeNode()); + merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId)); + returnValue = InliningUtil.mergeReturns(merge, returnNodes, null); + merge.setNext(n); + } + } else { + returnValue = null; + } + invokeNode.replaceAtUsages(returnValue); + + /* + * Usage the handles that we have on the return value and the exception to update the + * orderId->Node table. + */ + registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true); + if (invoke instanceof InvokeWithExceptionNode) { + registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true); + } + if (inlineScope.exceptionPlaceholderNode != null) { + inlineScope.exceptionPlaceholderNode.replaceAndDelete(exceptionValue); + } + deleteInvoke(invoke); + + methodScope.inlineInvokePlugin.postInline(inlineMethod); + return true; + } + + public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData) { + FixedNode n; + if (invokeData.invoke instanceof InvokeWithExceptionNode) { + n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId); + } else { + n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId); + } + return n; + } + + private static void deleteInvoke(Invoke invoke) { + /* + * Clean up unused nodes. We cannot just call killCFG on the invoke node because that can + * kill too much: nodes that are decoded later can use values that appear unused by now. + */ + FrameState frameState = invoke.stateAfter(); + invoke.asNode().safeDelete(); + assert invoke.callTarget() == null : "must not have been added to the graph yet"; + if (frameState != null && frameState.hasNoUsages()) { + frameState.safeDelete(); + } + } + + protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method); + + @Override + protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) { + PEMethodScope methodScope = (PEMethodScope) s; + + if (node instanceof ParameterNode) { + if (methodScope.arguments != null) { + Node result = methodScope.arguments[((ParameterNode) node).index()]; + assert result != null; + return result; + + } else if (methodScope.parameterPlugin != null) { + GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null); + Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, ((ParameterNode) node).index(), ((ParameterNode) node).stamp()); + if (result != null) { + return result; + } + } + + } + + return super.handleFloatingNodeBeforeAdd(methodScope, loopScope, node); + } + + protected void ensureOuterStateDecoded(PEMethodScope methodScope) { + if (methodScope.outerState == null && methodScope.caller != null) { + FrameState stateAtReturn = methodScope.invokeData.invoke.stateAfter(); + if (stateAtReturn == null) { + stateAtReturn = (FrameState) decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); + } + + Kind invokeReturnKind = methodScope.invokeData.invoke.asNode().getKind(); + FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind); + + /* + * When the encoded graph has methods inlining, we can already have a proper caller + * state. If not, we set the caller state here. + */ + if (outerState.outerFrameState() == null && methodScope.caller != null) { + ensureOuterStateDecoded(methodScope.caller); + outerState.setOuterFrameState(methodScope.caller.outerState); + } + methodScope.outerState = outerState; + } + } + + protected void ensureStateAfterDecoded(PEMethodScope methodScope) { + if (methodScope.invokeData.invoke.stateAfter() == null) { + methodScope.invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId)); + } + } + + protected void ensureExceptionStateDecoded(PEMethodScope methodScope) { + if (methodScope.exceptionState == null && methodScope.caller != null && methodScope.invokeData.invoke instanceof InvokeWithExceptionNode) { + ensureStateAfterDecoded(methodScope); + + assert methodScope.exceptionPlaceholderNode == null; + methodScope.exceptionPlaceholderNode = methodScope.graph.add(new ExceptionPlaceholderNode()); + registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false); + FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId); + + if (exceptionState.outerFrameState() == null && methodScope.caller != null) { + ensureOuterStateDecoded(methodScope.caller); + exceptionState.setOuterFrameState(methodScope.caller.outerState); + } + methodScope.exceptionState = exceptionState; + } + } + + @Override + protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) { + PEMethodScope methodScope = (PEMethodScope) s; + + if (methodScope.isInlinedMethod()) { + if (node instanceof SimpleInfopointNode) { + methodScope.bytecodePosition = InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.bytecodePosition); + return node; + + } else if (node instanceof FrameState) { + FrameState frameState = (FrameState) node; + + ensureOuterStateDecoded(methodScope); + if (frameState.bci < 0) { + ensureExceptionStateDecoded(methodScope); + } + return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, methodScope.method, methodScope.exceptionState, methodScope.outerState, true); + + } else if (node instanceof MonitorIdNode) { + ensureOuterStateDecoded(methodScope); + InliningUtil.processMonitorId(methodScope.outerState, (MonitorIdNode) node); + return node; + } + } + + return node; + } +} diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CachingPEGraphDecoder.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CachingPEGraphDecoder.java Tue Apr 21 10:47:43 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2015, 2015, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.truffle; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.phases.util.*; - -/** - * A graph decoder that provides all necessary encoded graphs on-the-fly (by parsing the methods and - * encoding the graphs). - */ -public class CachingPEGraphDecoder extends PEGraphDecoder { - - private final Providers providers; - private final GraphBuilderConfiguration graphBuilderConfig; - private final AllowAssumptions allowAssumptions; - private final Map graphCache; - - public CachingPEGraphDecoder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, AllowAssumptions allowAssumptions, Architecture architecture) { - super(providers.getMetaAccess(), providers.getConstantReflection(), providers.getStampProvider(), architecture); - - this.providers = providers; - this.graphBuilderConfig = graphBuilderConfig; - this.allowAssumptions = allowAssumptions; - this.graphCache = new HashMap<>(); - } - - private EncodedGraph createGraph(ResolvedJavaMethod method) { - StructuredGraph graph = new StructuredGraph(method, allowAssumptions); - try (Debug.Scope scope = Debug.scope("createGraph", graph)) { - - new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), graphBuilderConfig, TruffleCompilerImpl.Optimizations, null).apply(graph); - - PhaseContext context = new PhaseContext(providers); - new CanonicalizerPhase().apply(graph, context); - - EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, architecture); - graphCache.put(method, encodedGraph); - return encodedGraph; - - } catch (Throwable ex) { - throw Debug.handle(ex); - } - } - - @Override - protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method) { - EncodedGraph result = graphCache.get(method); - if (result == null && method.hasBytecodes()) { - result = createGraph(method); - } - return result; - } -} diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java Tue Apr 21 10:47:43 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,725 +0,0 @@ -/* - * Copyright (c) 2015, 2015, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.truffle; - -import static com.oracle.graal.compiler.common.GraalInternalError.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo; -import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver; -import com.oracle.graal.java.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.CallTargetNode.InvokeKind; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.common.inlining.*; - -/** - * A graph decoder that performs partial evaluation, i.e., that performs method inlining and - * canonicalization/simplification of nodes during decoding. - * - * Inlining and loop explosion are configured via the plugin mechanism also used by the - * {@link GraphBuilderPhase}. However, not all callback methods defined in - * {@link GraphBuilderContext} are available since decoding is more limited than graph building. - * - * The standard {@link Canonicalizable#canonical node canonicalization} interface is used to - * canonicalize nodes during decoding. Additionally, {@link IfNode branches} and - * {@link IntegerSwitchNode switches} with constant conditions are simplified. - */ -public abstract class PEGraphDecoder extends GraphDecoder { - - protected final MetaAccessProvider metaAccess; - protected final ConstantReflectionProvider constantReflection; - protected final StampProvider stampProvider; - - protected class PEMethodScope extends MethodScope { - /** The state of the caller method. Only non-null during method inlining. */ - protected final PEMethodScope caller; - protected final LoopScope callerLoopScope; - protected final ResolvedJavaMethod method; - protected final InvokeData invokeData; - protected final int inliningDepth; - - protected final LoopExplosionPlugin loopExplosionPlugin; - protected final InvocationPlugins invocationPlugins; - protected final InlineInvokePlugin inlineInvokePlugin; - protected final ParameterPlugin parameterPlugin; - protected final ValueNode[] arguments; - - protected FrameState outerState; - protected FrameState exceptionState; - protected ExceptionPlaceholderNode exceptionPlaceholderNode; - protected BytecodePosition bytecodePosition; - - protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData, - int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, ParameterPlugin parameterPlugin, - ValueNode[] arguments) { - super(targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin)); - - this.caller = caller; - this.callerLoopScope = callerLoopScope; - this.method = method; - this.invokeData = invokeData; - this.inliningDepth = inliningDepth; - this.loopExplosionPlugin = loopExplosionPlugin; - this.invocationPlugins = invocationPlugins; - this.inlineInvokePlugin = inlineInvokePlugin; - this.parameterPlugin = parameterPlugin; - this.arguments = arguments; - } - - public boolean isInlinedMethod() { - return caller != null; - } - } - - protected class PECanonicalizerTool implements CanonicalizerTool { - @Override - public MetaAccessProvider getMetaAccess() { - return metaAccess; - } - - @Override - public ConstantReflectionProvider getConstantReflection() { - return constantReflection; - } - - @Override - public boolean canonicalizeReads() { - return true; - } - - @Override - public boolean allUsagesAvailable() { - return false; - } - } - - protected class PENonAppendGraphBuilderContext implements GraphBuilderContext { - protected final PEMethodScope methodScope; - protected final Invoke invoke; - - public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) { - this.methodScope = methodScope; - this.invoke = invoke; - } - - @Override - public BailoutException bailout(String string) { - throw new BailoutException(string); - } - - @Override - public StampProvider getStampProvider() { - return stampProvider; - } - - @Override - public MetaAccessProvider getMetaAccess() { - return metaAccess; - } - - @Override - public ConstantReflectionProvider getConstantReflection() { - return constantReflection; - } - - @Override - public StructuredGraph getGraph() { - return methodScope.graph; - } - - @Override - public int getDepth() { - return methodScope.inliningDepth; - } - - @Override - public Replacement getReplacement() { - return null; - } - - @Override - public T append(T value) { - throw unimplemented(); - } - - @Override - public T recursiveAppend(T value) { - throw unimplemented(); - } - - @Override - public void push(Kind kind, ValueNode value) { - throw unimplemented(); - } - - @Override - public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) { - throw unimplemented(); - } - - @Override - public void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args) { - throw unimplemented(); - } - - @Override - public FrameState createStateAfter() { - throw unimplemented(); - } - - @Override - public GraphBuilderContext getParent() { - throw unimplemented(); - } - - @Override - public ResolvedJavaMethod getMethod() { - throw unimplemented(); - } - - @Override - public int bci() { - return invoke.bci(); - } - - @Override - public InvokeKind getInvokeKind() { - throw unimplemented(); - } - - @Override - public JavaType getInvokeReturnType() { - throw unimplemented(); - } - } - - protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext { - protected FixedWithNextNode lastInstr; - protected ValueNode pushedNode; - - public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) { - super(inlineScope, inlineScope.invokeData.invoke); - this.lastInstr = lastInstr; - } - - @Override - public void push(Kind kind, ValueNode value) { - if (pushedNode != null) { - throw unimplemented("Only one push is supported"); - } - pushedNode = value; - } - - @Override - public FrameState createStateAfter() { - Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); - getGraph().add(stateAfter); - return (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter); - } - - @Override - public T append(T v) { - if (v.graph() != null) { - return v; - } - T added = getGraph().addOrUnique(v); - if (added == v) { - updateLastInstruction(v); - } - return added; - } - - @Override - public T recursiveAppend(T v) { - if (v.graph() != null) { - return v; - } - T added = getGraph().addOrUniqueWithInputs(v); - if (added == v) { - updateLastInstruction(v); - } - return added; - } - - private void updateLastInstruction(T v) { - if (v instanceof FixedNode) { - FixedNode fixedNode = (FixedNode) v; - lastInstr.setNext(fixedNode); - if (fixedNode instanceof FixedWithNextNode) { - FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode; - assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end"; - lastInstr = fixedWithNextNode; - } else { - lastInstr = null; - } - } - } - } - - @NodeInfo - static class ExceptionPlaceholderNode extends ValueNode { - public static final NodeClass TYPE = NodeClass.create(ExceptionPlaceholderNode.class); - - public ExceptionPlaceholderNode() { - super(TYPE, StampFactory.object()); - } - } - - public PEGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, Architecture architecture) { - super(architecture); - this.metaAccess = metaAccess; - this.constantReflection = constantReflection; - this.stampProvider = stampProvider; - } - - protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) { - if (loopExplosionPlugin == null) { - return LoopExplosionKind.NONE; - } else if (loopExplosionPlugin.shouldMergeExplosions(method)) { - return LoopExplosionKind.MERGE_EXPLODE; - } else if (loopExplosionPlugin.shouldExplodeLoops(method)) { - return LoopExplosionKind.FULL_EXPLODE; - } else { - return LoopExplosionKind.NONE; - } - } - - public void decode(StructuredGraph targetGraph, ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, - ParameterPlugin parameterPlugin) { - PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugin, - parameterPlugin, null); - decode(methodScope, null); - cleanupGraph(methodScope, null); - methodScope.graph.verify(); - } - - @Override - protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) { - GraphBuilderPhase.connectLoopEndToBegin(methodScope.graph); - super.cleanupGraph(methodScope, start); - } - - @Override - protected void checkLoopExplosionIteration(MethodScope s, LoopScope loopScope) { - PEMethodScope methodScope = (PEMethodScope) s; - - if (loopScope.loopIteration > MaximumLoopExplosionCount.getValue()) { - String message = "too many loop explosion iterations - does the explosion not terminate for method " + methodScope.method + "?"; - if (FailedLoopExplosionIsFatal.getValue()) { - throw new RuntimeException(message); - } else { - throw new BailoutException(message); - } - } - } - - @Override - protected void handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) { - PEMethodScope methodScope = (PEMethodScope) s; - - /* - * Decode the call target, but do not add it to the graph yet. This avoids adding usages for - * all the arguments, which are expensive to remove again when we can inline the method. - */ - assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke"; - CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId); - if (!(callTarget instanceof MethodCallTargetNode) || !trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget)) { - - /* We know that we need an invoke, so now we can add the call target to the graph. */ - methodScope.graph.add(callTarget); - registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false); - super.handleInvoke(methodScope, loopScope, invokeData); - } - } - - protected boolean trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { - // attempt to devirtualize the call - ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), invokeData.contextType); - if (specialCallTarget != null) { - callTarget.setTargetMethod(specialCallTarget); - callTarget.setInvokeKind(InvokeKind.Special); - } - - if (tryInvocationPlugin(methodScope, loopScope, invokeData, callTarget)) { - return true; - } - if (tryInline(methodScope, loopScope, invokeData, callTarget)) { - return true; - } - - if (methodScope.inlineInvokePlugin != null) { - methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke); - } - return false; - } - - protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { - if (methodScope.invocationPlugins == null) { - return false; - } - - Invoke invoke = invokeData.invoke; - - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - InvocationPlugin invocationPlugin = methodScope.invocationPlugins.lookupInvocation(targetMethod); - if (invocationPlugin == null) { - return false; - } - - ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); - FixedWithNextNode invokePredecessor = (FixedWithNextNode) invoke.asNode().predecessor(); - - /* Remove invoke from graph so that invocation plugin can append nodes to the predecessor. */ - invoke.asNode().replaceAtPredecessor(null); - - PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin, - methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments); - PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor); - InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext); - - if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) { - - if (graphBuilderContext.lastInstr != null) { - registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true); - invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode); - graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData)); - } else { - assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?"; - invoke.asNode().replaceAtUsages(null); - } - - deleteInvoke(invoke); - return true; - - } else { - /* Intrinsification failed, restore original state: invoke is in Graph. */ - invokePredecessor.setNext(invoke.asNode()); - return false; - } - } - - protected boolean tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { - if (methodScope.inlineInvokePlugin == null || !callTarget.invokeKind().isDirect()) { - return false; - } - - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - if (!targetMethod.canBeInlined()) { - return false; - } - - ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); - GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke); - InlineInfo inlineInfo = methodScope.inlineInvokePlugin.getInlineInfo(graphBuilderContext, targetMethod, arguments, callTarget.returnType()); - if (inlineInfo == null) { - return false; - } - assert !inlineInfo.isIntrinsic && !inlineInfo.isReplacement : "not supported"; - - ResolvedJavaMethod inlineMethod = inlineInfo.methodToInline; - EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod); - if (graphToInline == null) { - return false; - } - - Invoke invoke = invokeData.invoke; - FixedNode invokeNode = invoke.asNode(); - FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor(); - invokeNode.replaceAtPredecessor(null); - - PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1, - methodScope.loopExplosionPlugin, methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments); - /* Do the actual inlining by decoding the inlineMethod */ - decode(inlineScope, predecessor); - - ValueNode exceptionValue = null; - if (inlineScope.unwindNode != null) { - exceptionValue = inlineScope.unwindNode.exception(); - } - UnwindNode unwindNode = inlineScope.unwindNode; - - if (invoke instanceof InvokeWithExceptionNode) { - InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke); - assert invokeWithException.next() == null; - assert invokeWithException.exceptionEdge() == null; - - if (unwindNode != null) { - assert unwindNode.predecessor() != null; - Node n = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId); - unwindNode.replaceAndDelete(n); - } - - } else { - if (unwindNode != null && !unwindNode.isDeleted()) { - DeoptimizeNode deoptimizeNode = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); - unwindNode.replaceAndDelete(deoptimizeNode); - } - } - - assert invoke.next() == null; - - ValueNode returnValue; - List returnNodes = inlineScope.returnNodes; - if (!returnNodes.isEmpty()) { - FixedNode n; - n = nodeAfterInvoke(methodScope, loopScope, invokeData); - if (returnNodes.size() == 1) { - ReturnNode returnNode = returnNodes.get(0); - returnValue = returnNode.result(); - returnNode.replaceAndDelete(n); - } else { - AbstractMergeNode merge = methodScope.graph.add(new MergeNode()); - merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId)); - returnValue = InliningUtil.mergeReturns(merge, returnNodes, null); - merge.setNext(n); - } - } else { - returnValue = null; - } - invokeNode.replaceAtUsages(returnValue); - - /* - * Usage the handles that we have on the return value and the exception to update the - * orderId->Node table. - */ - registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true); - if (invoke instanceof InvokeWithExceptionNode) { - registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true); - } - if (inlineScope.exceptionPlaceholderNode != null) { - inlineScope.exceptionPlaceholderNode.replaceAndDelete(exceptionValue); - } - deleteInvoke(invoke); - - methodScope.inlineInvokePlugin.postInline(inlineMethod); - return true; - } - - public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData) { - FixedNode n; - if (invokeData.invoke instanceof InvokeWithExceptionNode) { - n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId); - } else { - n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId); - } - return n; - } - - private static void deleteInvoke(Invoke invoke) { - /* - * Clean up unused nodes. We cannot just call killCFG on the invoke node because that can - * kill too much: nodes that are decoded later can use values that appear unused by now. - */ - FrameState frameState = invoke.stateAfter(); - invoke.asNode().safeDelete(); - assert invoke.callTarget() == null : "must not have been added to the graph yet"; - if (frameState != null && frameState.hasNoUsages()) { - frameState.safeDelete(); - } - } - - protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method); - - @Override - protected void simplifyFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) { - PEMethodScope methodScope = (PEMethodScope) s; - - if (node instanceof IfNode) { - IfNode ifNode = (IfNode) node; - if (ifNode.condition() instanceof LogicNegationNode) { - ifNode.eliminateNegation(); - } - if (ifNode.condition() instanceof LogicConstantNode) { - boolean condition = ((LogicConstantNode) ifNode.condition()).getValue(); - AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition); - AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition); - - methodScope.graph.removeSplit(ifNode, survivingSuccessor); - assert deadSuccessor.next() == null : "must not be parsed yet"; - deadSuccessor.safeDelete(); - } - - } else if (node instanceof IntegerSwitchNode && ((IntegerSwitchNode) node).value().isConstant()) { - IntegerSwitchNode switchNode = (IntegerSwitchNode) node; - int value = switchNode.value().asJavaConstant().asInt(); - AbstractBeginNode survivingSuccessor = switchNode.successorAtKey(value); - List allSuccessors = switchNode.successors().snapshot(); - - methodScope.graph.removeSplit(switchNode, survivingSuccessor); - for (Node successor : allSuccessors) { - if (successor != survivingSuccessor) { - assert ((AbstractBeginNode) successor).next() == null : "must not be parsed yet"; - successor.safeDelete(); - } - } - - } else if (node instanceof Canonicalizable) { - Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool()); - if (canonical == null) { - /* - * This is a possible return value of canonicalization. However, we might need to - * add additional usages later on for which we need a node. Therefore, we just do - * nothing and leave the node in place. - */ - } else if (canonical != node) { - if (!canonical.isAlive()) { - assert !canonical.isDeleted(); - canonical = methodScope.graph.addOrUniqueWithInputs(canonical); - if (canonical instanceof FixedWithNextNode) { - methodScope.graph.addBeforeFixed(node, (FixedWithNextNode) canonical); - } - } - GraphUtil.unlinkFixedNode((FixedWithNextNode) node); - node.replaceAtUsages(canonical); - node.safeDelete(); - assert lookupNode(loopScope, nodeOrderId) == node; - registerNode(loopScope, nodeOrderId, canonical, true, false); - } - } - } - - @Override - protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) { - PEMethodScope methodScope = (PEMethodScope) s; - - if (node instanceof ParameterNode) { - if (methodScope.arguments != null) { - Node result = methodScope.arguments[((ParameterNode) node).index()]; - assert result != null; - return result; - - } else if (methodScope.parameterPlugin != null) { - GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null); - Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, ((ParameterNode) node).index(), ((ParameterNode) node).stamp()); - if (result != null) { - return result; - } - } - - } else if (node instanceof Canonicalizable) { - Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool()); - if (canonical == null) { - /* - * This is a possible return value of canonicalization. However, we might need to - * add additional usages later on for which we need a node. Therefore, we just do - * nothing and leave the node in place. - */ - } else if (canonical != node) { - if (!canonical.isAlive()) { - assert !canonical.isDeleted(); - canonical = methodScope.graph.addOrUniqueWithInputs(canonical); - } - assert node.hasNoUsages(); - // methodScope.graph.replaceFloating((FloatingNode) node, canonical); - return canonical; - } - } - return node; - } - - protected void ensureOuterStateDecoded(PEMethodScope methodScope) { - if (methodScope.outerState == null && methodScope.caller != null) { - FrameState stateAtReturn = methodScope.invokeData.invoke.stateAfter(); - if (stateAtReturn == null) { - stateAtReturn = (FrameState) decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); - } - - Kind invokeReturnKind = methodScope.invokeData.invoke.asNode().getKind(); - FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind); - - /* - * When the encoded graph has methods inlining, we can already have a proper caller - * state. If not, we set the caller state here. - */ - if (outerState.outerFrameState() == null && methodScope.caller != null) { - ensureOuterStateDecoded(methodScope.caller); - outerState.setOuterFrameState(methodScope.caller.outerState); - } - methodScope.outerState = outerState; - } - } - - protected void ensureStateAfterDecoded(PEMethodScope methodScope) { - if (methodScope.invokeData.invoke.stateAfter() == null) { - methodScope.invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId)); - } - } - - protected void ensureExceptionStateDecoded(PEMethodScope methodScope) { - if (methodScope.exceptionState == null && methodScope.caller != null && methodScope.invokeData.invoke instanceof InvokeWithExceptionNode) { - ensureStateAfterDecoded(methodScope); - - assert methodScope.exceptionPlaceholderNode == null; - methodScope.exceptionPlaceholderNode = methodScope.graph.add(new ExceptionPlaceholderNode()); - registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false); - FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId); - - if (exceptionState.outerFrameState() == null && methodScope.caller != null) { - ensureOuterStateDecoded(methodScope.caller); - exceptionState.setOuterFrameState(methodScope.caller.outerState); - } - methodScope.exceptionState = exceptionState; - } - } - - @Override - protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) { - PEMethodScope methodScope = (PEMethodScope) s; - - if (methodScope.isInlinedMethod()) { - if (node instanceof SimpleInfopointNode) { - methodScope.bytecodePosition = InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.bytecodePosition); - return node; - - } else if (node instanceof FrameState) { - FrameState frameState = (FrameState) node; - - ensureOuterStateDecoded(methodScope); - if (frameState.bci < 0) { - ensureExceptionStateDecoded(methodScope); - } - return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, methodScope.method, methodScope.exceptionState, methodScope.outerState, true); - - } else if (node instanceof MonitorIdNode) { - ensureOuterStateDecoded(methodScope); - InliningUtil.processMonitorId(methodScope.outerState, (MonitorIdNode) node); - return node; - } - } - - return node; - } -} diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Tue Apr 21 10:47:43 2015 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Tue Apr 21 16:18:23 2015 -0700 @@ -340,7 +340,7 @@ plugins.setInlineInvokePlugin(new ParsingInlineInvokePlugin((ReplacementsImpl) providers.getReplacements(), parsingInvocationPlugins, loopExplosionPlugin, !PrintTruffleExpansionHistogram.getValue())); - CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(providers, newConfig, AllowAssumptions.from(graph.getAssumptions() != null), architecture); + CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(providers, newConfig, TruffleCompilerImpl.Optimizations, AllowAssumptions.from(graph.getAssumptions() != null), architecture); ParameterPlugin parameterPlugin = new InterceptReceiverPlugin(callTarget); diff -r 2e35a4ea22ac -r d094ea7e0433 graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java Tue Apr 21 10:47:43 2015 -0700 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java Tue Apr 21 16:18:23 2015 -0700 @@ -63,7 +63,7 @@ @Override public Node canonical(CanonicalizerTool tool) { - if (getUsageCount() == 0) { + if (tool.allUsagesAvailable() && hasNoUsages()) { /* If the cast is unused, it can be eliminated. */ return input; }