# HG changeset patch # User Lukas Stadler # Date 1347367704 -7200 # Node ID 41fc19bd618d5a46a67cbd370980eb50ba7f85cb # Parent 892d3c82febe0a116b3e6f6f478bf7fdf9f7980e adapt old EscapeAnalysisPhase to infrastructure changes diff -r 892d3c82febe -r 41fc19bd618d graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EscapeAnalysisTest.java Tue Sep 11 14:27:44 2012 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EscapeAnalysisTest.java Tue Sep 11 14:48:24 2012 +0200 @@ -127,7 +127,7 @@ new InliningPhase(null, runtime(), null, null, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); new DeadCodeEliminationPhase().apply(graph); Debug.dump(graph, "Graph"); - new EscapeAnalysisPhase(null, runtime(), null, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new EscapeAnalysisPhase(null, runtime(), null).apply(graph); Debug.dump(graph, "Graph"); int retCount = 0; for (ReturnNode ret : graph.getNodes(ReturnNode.class)) { diff -r 892d3c82febe -r 41fc19bd618d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Tue Sep 11 14:27:44 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Tue Sep 11 14:48:24 2012 +0200 @@ -153,7 +153,7 @@ } if (GraalOptions.EscapeAnalysis && !plan.isPhaseDisabled(EscapeAnalysisPhase.class)) { - new EscapeAnalysisPhase(target, runtime, assumptions, cache, plan, optimisticOpts).apply(graph); + new EscapeAnalysisPhase(target, runtime, assumptions).apply(graph); } if (GraalOptions.OptLoopTransform) { new LoopTransformHighPhase().apply(graph); diff -r 892d3c82febe -r 41fc19bd618d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Tue Sep 11 14:27:44 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Tue Sep 11 14:48:24 2012 +0200 @@ -25,6 +25,7 @@ import java.util.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.graph.*; import com.oracle.graal.compiler.util.*; @@ -153,9 +154,7 @@ } assert node.objectStamp().isExactType(); final VirtualObjectNode virtual = graph.add(new VirtualObjectNode(id, node.objectStamp().type(), escapeFields.length)); - if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) { - TTY.println("new virtual object: " + virtual); - } + Debug.log("new virtual object: " + virtual); node.replaceAtUsages(virtual); FixedNode next = node.next(); graph.removeFixed(node); @@ -190,130 +189,25 @@ } } + private final TargetDescription target; + private final GraalCodeCacheProvider runtime; + private final Assumptions assumptions; private int virtualIds = 0; - - private final TargetDescription target; - private final GraalCodeCacheProvider runtime; - private final Assumptions assumptions; - private final GraphCache cache; - private final PhasePlan plan; - private final OptimisticOptimizations optimisticOpts; - - public EscapeAnalysisPhase(TargetDescription target, GraalCodeCacheProvider runtime, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { + public EscapeAnalysisPhase(TargetDescription target, GraalCodeCacheProvider runtime, Assumptions assumptions) { this.runtime = runtime; this.target = target; this.assumptions = assumptions; - this.cache = cache; - this.plan = plan; - this.optimisticOpts = optimisticOpts; } - private static class EscapeRecord { - - public final Node node; - public final ArrayList escapesThrough = new ArrayList<>(); - public double localWeight; - - public EscapeRecord(Node node) { - this.node = node; - } - - public void dump() { - TTY.print("node %s (%f) escapes through ", node, localWeight); - for (Node escape : escapesThrough) { - TTY.print("%s ", escape); - } - TTY.println(); - } - } - - private static Node escape(EscapeRecord record, Node usage) { - final Node node = record.node; - if (usage instanceof VirtualState) { - assert usage.inputs().contains(node); - return null; - } else { - if (usage instanceof FixedNode) { - record.localWeight += ((FixedNode) usage).probability(); - } - if (usage instanceof IsNullNode) { - assert ((IsNullNode) usage).object() == node; - return null; - } else if (usage instanceof IsTypeNode) { - assert ((IsTypeNode) usage).objectClass() == node; - return null; - } else if (usage instanceof AccessMonitorNode) { - assert ((AccessMonitorNode) usage).object() == node; - return null; - } else if (usage instanceof LoadFieldNode) { - assert ((LoadFieldNode) usage).object() == node; - return null; - } else if (usage instanceof StoreFieldNode) { - StoreFieldNode x = (StoreFieldNode) usage; - // self-references do not escape - return x.value() == node ? x.object() : null; - } else if (usage instanceof LoadIndexedNode) { - LoadIndexedNode x = (LoadIndexedNode) usage; - if (x.index() == node) { - return x.array(); - } else { - assert x.array() == node; - return EscapeOp.isValidConstantIndex(x) ? null : x.array(); - } - } else if (usage instanceof StoreIndexedNode) { - StoreIndexedNode x = (StoreIndexedNode) usage; - if (x.index() == node) { - return x.array(); - } else { - assert x.array() == node || x.value() == node; - // in order to not escape, the access needs to have a valid constant index and either a store into node or be self-referencing - return EscapeOp.isValidConstantIndex(x) && x.value() != node ? null : x.array(); - } - } else if (usage instanceof RegisterFinalizerNode) { - assert ((RegisterFinalizerNode) usage).object() == node; - return null; - } else if (usage instanceof ArrayLengthNode) { - assert ((ArrayLengthNode) usage).array() == node; - return null; - } else { - return usage; - } - } - } - - @SuppressWarnings("unused") - private static void completeAnalysis(StructuredGraph graph) { - // TODO (lstadler): debugging code - - TTY.println("================================================================"); - for (Node node : graph.getNodes()) { - if (node != null && node instanceof FixedWithNextNode && node instanceof EscapeAnalyzable) { - EscapeOp op = ((EscapeAnalyzable) node).getEscapeOp(); - if (op != null && op.canAnalyze(node)) { - EscapeRecord record = new EscapeRecord(node); - - for (Node usage : node.usages()) { - Node escapesThrough = escape(record, usage); - if (escapesThrough != null && escapesThrough != node) { - record.escapesThrough.add(escapesThrough); - } - } - record.dump(); - } - } - } - } - - @Override protected void run(StructuredGraph graph) { for (Node node : new GraphOrder(graph)) { if (node != null && node instanceof FixedWithNextNode && node instanceof EscapeAnalyzable) { FixedWithNextNode fixedNode = (FixedWithNextNode) node; EscapeOp op = ((EscapeAnalyzable) node).getEscapeOp(); - if (op != null && op.canAnalyze(fixedNode)) { + if (op != null) { try { performAnalysis(graph, fixedNode, op); } catch (GraalInternalError e) { @@ -328,60 +222,27 @@ if (!shouldAnalyze(node)) { return; } - Set exits = new HashSet<>(); - Set invokes = new HashSet<>(); - int iterations = 0; - - int minimumWeight = getMinimumWeight(node); - do { - double weight = analyze(op, node, exits, invokes); - if (exits.size() != 0) { - if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) { - TTY.println("%n####### escaping object: %s (%s)", node, node.stamp()); - if (GraalOptions.TraceEscapeAnalysis) { - TTY.print("%d: new value: %s, weight %f, escapes at ", iterations, node, weight); - for (Node n : exits) { - TTY.print("%s, ", n); - } - for (Invoke n : invokes) { - TTY.print("%s, ", n); - } - TTY.println(); - } - } - break; - } - if (invokes.size() == 0) { + HashSet exits = new HashSet<>(); + HashSet invokes = new HashSet<>(); - Debug.dump(graph, "Before escape %s", node); - Debug.log("!!!!!!!! non-escaping object: %s (%s)", node, node.stamp()); - removeAllocation(graph, node, op); - Debug.dump(graph, "After escape", graph); - break; - } - if (weight < minimumWeight) { - if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) { - TTY.println("####### possibly escaping object: %s (insufficient weight for inlining: %f)", node, weight); + analyze(node, exits, invokes); + if (exits.isEmpty() && invokes.isEmpty()) { + Debug.log("!!!!!!!! non-escaping object: %s (%s)", node, node.stamp()); + removeAllocation(graph, node, op); + Debug.dump(graph, "After escape", graph); + } else { + Debug.log("%n####### escaping object: %s (%s)", node, node.stamp()); + if (GraalOptions.TraceEscapeAnalysis) { + TTY.print(" escapes at ", node); + for (Node n : exits) { + TTY.print("%s, ", n); } - break; - } - if (!GraalOptions.Inline) { - break; + for (Invoke n : invokes) { + TTY.print("%s, ", n); + } + TTY.println(); } - if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) { - TTY.println("Trying inlining to get a non-escaping object for %s", node); - } - new InliningPhase(target, runtime, invokes, assumptions, cache, plan, optimisticOpts).apply(graph); - new DeadCodeEliminationPhase().apply(graph); - if (node.isDeleted()) { - if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) { - TTY.println("!!!!!!!! object died while performing escape analysis: %s (%s)", node, node.stamp()); - } - break; - } - exits.clear(); - invokes.clear(); - } while (iterations++ < 3); + } } protected void removeAllocation(StructuredGraph graph, FixedWithNextNode node, EscapeOp op) { @@ -410,14 +271,9 @@ return true; } - protected int getMinimumWeight(@SuppressWarnings("unused") FixedWithNextNode node) { - return GraalOptions.ForcedInlineEscapeWeight; - } - - private static double analyze(EscapeOp op, Node node, Collection exits, Collection invokes) { - double weight = 0; + private static void analyze(Node node, HashSet exits, HashSet invokes) { for (Node usage : node.usages().snapshot()) { - boolean escapes = op.escape(node, usage); + boolean escapes = escape(node, usage); if (escapes) { if (usage instanceof VirtualState) { // nothing to do... @@ -439,15 +295,73 @@ exits.add(usage); break; } + } + } + } + + private static boolean escape(Node node, Node usage) { + if (usage instanceof IsNullNode) { + assert ((IsNullNode) usage).object() == node; + return false; + } else if (usage instanceof IsTypeNode) { + assert ((IsTypeNode) usage).objectClass() == node; + return false; + } else if (usage instanceof VirtualState) { + assert usage.inputs().contains(node); + return true; + } else if (usage instanceof AccessMonitorNode) { + assert ((AccessMonitorNode) usage).object() == node; + return false; + } else if (usage instanceof LoadFieldNode) { + assert ((LoadFieldNode) usage).object() == node; + return false; + } else if (usage instanceof StoreFieldNode) { + StoreFieldNode x = (StoreFieldNode) usage; + // self-references do escape + return x.value() == node; // TODO (thomaswue) Check if we can add this condition? && x.object() != node; + } else if (usage instanceof LoadIndexedNode) { + LoadIndexedNode x = (LoadIndexedNode) usage; + if (x.index() == node) { + return true; } else { - if (GraalOptions.ProbabilityAnalysis && usage instanceof FixedNode) { - weight += ((FixedNode) usage).probability(); - } else { - weight++; + assert x.array() == node; + return !isValidConstantIndex(x); + } + } else if (usage instanceof StoreIndexedNode) { + StoreIndexedNode x = (StoreIndexedNode) usage; + if (x.index() == node) { + return true; + } else { + assert x.array() == node || x.value() == node; + // in order to not escape the access needs to have a valid constant index and either a store into node + // or self-referencing + return !isValidConstantIndex(x) || x.value() == node && x.array() != node; + } + } else if (usage instanceof RegisterFinalizerNode) { + assert ((RegisterFinalizerNode) usage).object() == node; + return false; + } else if (usage instanceof ArrayLengthNode) { + assert ((ArrayLengthNode) usage).array() == node; + return false; + } else if (usage instanceof ValueProxyNode) { + for (Node vpnUsage : usage.usages().snapshot()) { + if (escape(usage, vpnUsage)) { + return true; } } + return false; + } else { + return true; } - return weight; } + public static boolean isValidConstantIndex(AccessIndexedNode x) { + Constant index = x.index().asConstant(); + if (x.array() instanceof NewArrayNode) { + Constant length = ((NewArrayNode) x.array()).dimension(0).asConstant(); + return index != null && length != null && index.asInt() >= 0 && index.asInt() < length.asInt(); + } else { + return false; + } + } } diff -r 892d3c82febe -r 41fc19bd618d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Tue Sep 11 14:27:44 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Tue Sep 11 14:48:24 2012 +0200 @@ -102,13 +102,6 @@ private static final EscapeOp ESCAPE = new EscapeOp() { @Override - public boolean canAnalyze(Node node) { - NewArrayNode x = (NewArrayNode) node; - Constant length = x.dimension(0).asConstant(); - return length != null && length.asInt() >= 0 && length.asInt() < MaximumEscapeAnalysisArrayLength; - } - - @Override public EscapeField[] fields(Node node) { NewArrayNode x = (NewArrayNode) node; assert x.elementType.arrayOf().isArrayClass(); diff -r 892d3c82febe -r 41fc19bd618d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Tue Sep 11 14:27:44 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Tue Sep 11 14:48:24 2012 +0200 @@ -78,11 +78,6 @@ private static final EscapeOp ESCAPE = new EscapeOp() { - @Override - public boolean canAnalyze(Node node) { - return true; - } - private void fillEscapeFields(ResolvedJavaType type, List escapeFields) { if (type != null) { fillEscapeFields(type.superType(), escapeFields); diff -r 892d3c82febe -r 41fc19bd618d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Tue Sep 11 14:27:44 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Tue Sep 11 14:48:24 2012 +0200 @@ -32,79 +32,12 @@ public abstract class EscapeOp { - public abstract boolean canAnalyze(Node node); - - public boolean escape(Node node, Node usage) { - if (usage instanceof IsNullNode) { - assert ((IsNullNode) usage).object() == node; - return false; - } else if (usage instanceof IsTypeNode) { - assert ((IsTypeNode) usage).objectClass() == node; - return false; - } else if (usage instanceof VirtualState) { - assert usage.inputs().contains(node); - return true; - } else if (usage instanceof AccessMonitorNode) { - assert ((AccessMonitorNode) usage).object() == node; - return false; - } else if (usage instanceof LoadFieldNode) { - assert ((LoadFieldNode) usage).object() == node; - return false; - } else if (usage instanceof StoreFieldNode) { - StoreFieldNode x = (StoreFieldNode) usage; - // self-references do escape - return x.value() == node; // TODO (thomaswue) Check if we can add this condition? && x.object() != node; - } else if (usage instanceof LoadIndexedNode) { - LoadIndexedNode x = (LoadIndexedNode) usage; - if (x.index() == node) { - return true; - } else { - assert x.array() == node; - return !isValidConstantIndex(x); - } - } else if (usage instanceof StoreIndexedNode) { - StoreIndexedNode x = (StoreIndexedNode) usage; - if (x.index() == node) { - return true; - } else { - assert x.array() == node || x.value() == node; - // in order to not escape the access needs to have a valid constant index and either a store into node or self-referencing - return !isValidConstantIndex(x) || x.value() == node && x.array() != node; - } - } else if (usage instanceof RegisterFinalizerNode) { - assert ((RegisterFinalizerNode) usage).object() == node; - return false; - } else if (usage instanceof ArrayLengthNode) { - assert ((ArrayLengthNode) usage).array() == node; - return false; - } else if (usage instanceof ValueProxyNode) { - for (Node vpnUsage : usage.usages().snapshot()) { - if (escape(usage, vpnUsage)) { - return true; - } - } - return false; - } else { - return true; - } - } - - public static boolean isValidConstantIndex(AccessIndexedNode x) { - Constant index = x.index().asConstant(); - if (x.array() instanceof NewArrayNode) { - Constant length = ((NewArrayNode) x.array()).dimension(0).asConstant(); - return index != null && length != null && index.asInt() >= 0 && index.asInt() < length.asInt(); - } else { - return false; - } - } - public abstract EscapeField[] fields(Node node); public abstract ResolvedJavaType type(Node node); public void beforeUpdate(Node node, Node usage) { - // IsNonNullNode and IsTypeNode should have been eliminated by the CanonicalizerPhase, but we can't rely on this + // IsNullNode and IsTypeNode should have been eliminated by the CanonicalizerPhase, but we can't rely on this if (usage instanceof IsNullNode) { IsNullNode x = (IsNullNode) usage; ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(false, node.graph())); @@ -119,4 +52,5 @@ public abstract int updateState(Node node, Node current, Map fieldIndex, ValueNode[] fieldState); + }