changeset 2866:7f14e6b48a9c

added dead code elimination added ValueAnchor (temp workaround) more inlining logic (now uses DCE) IdealGraphPrinter: print even if Scheduler fails added inlining and DCE tracing options to C1XOptions
author Lukas Stadler <lukas.stadler@jku.at>
date Tue, 07 Jun 2011 16:27:08 +0200
parents e55543ff91fd
children 5c545fef2c81
files graal/GraalCompiler/src/com/oracle/max/graal/schedule/Schedule.java graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java graal/GraalCompiler/src/com/sun/c1x/debug/IdealGraphPrinter.java graal/GraalCompiler/src/com/sun/c1x/gen/PhiSimplifier.java graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java graal/GraalCompiler/src/com/sun/c1x/graph/IR.java graal/GraalCompiler/src/com/sun/c1x/ir/Anchor.java graal/GraalCompiler/src/com/sun/c1x/ir/Deoptimize.java graal/GraalCompiler/src/com/sun/c1x/ir/Merge.java graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java graal/GraalCompiler/src/com/sun/c1x/ir/ValueAnchor.java graal/GraalCompiler/src/com/sun/c1x/ir/ValueVisitor.java graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.java graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java graal/GraalGraph/src/com/oracle/graal/graph/Node.java
diffstat 16 files changed, 309 insertions(+), 164 deletions(-) [+]
line wrap: on
line diff
--- a/graal/GraalCompiler/src/com/oracle/max/graal/schedule/Schedule.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/oracle/max/graal/schedule/Schedule.java	Tue Jun 07 16:27:08 2011 +0200
@@ -81,7 +81,7 @@
         return b;
     }
 
-    private static boolean isCFG(Node n) {
+    public static boolean isCFG(Node n) {
         return n != null && ((n instanceof Instruction) || n == n.graph().start());
     }
 
--- a/graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java	Tue Jun 07 16:27:08 2011 +0200
@@ -39,6 +39,7 @@
     // Checkstyle: resume
 
     // inlining settings
+    public static boolean Inline                             = ____;
     public static int     MaximumInstructionCount            = 37000;
     public static float   MaximumInlineRatio                 = 0.90f;
     public static int     MaximumInlineSize                  = 35;
@@ -68,7 +69,7 @@
     // DOT output settings
     public static boolean PrintDOTGraphToFile                = ____;
     public static boolean PrintDOTGraphToPdf                 = ____;
-    public static boolean OmitDOTFrameStates                 = true;
+    public static boolean OmitDOTFrameStates                 = ____;
 
     // Ideal graph visualizer output settings
     public static int     PrintIdealGraphLevel               = 0;
@@ -91,6 +92,7 @@
     public static boolean TraceLIRVisit                      = ____;
     public static boolean TraceAssembler                     = ____;
     public static boolean TraceInlining                      = ____;
+    public static boolean TraceDeadCodeElimination           = ____;
     public static int     TraceBytecodeParserLevel           = 0;
     public static boolean QuietBailout                       = ____;
 
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java	Tue Jun 07 16:27:08 2011 +0200
@@ -1898,7 +1898,8 @@
                 values[valueIndex++] = monitorAddress;
                 assert frameRefMap != null;
                 CiStackSlot objectAddress = frameMap.toMonitorObjectStackAddress(i);
-                LIRDebugInfo.setBit(frameRefMap, objectAddress.index());
+//                LIRDebugInfo.setBit(frameRefMap, objectAddress.index());
+                frameRefMap.set(objectAddress.index());
             } else {
                 Value lock = state.lockAt(i);
                 if (lock.isConstant() && compilation.runtime.asJavaClass(lock.asConstant()) != null) {
--- a/graal/GraalCompiler/src/com/sun/c1x/debug/IdealGraphPrinter.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/debug/IdealGraphPrinter.java	Tue Jun 07 16:27:08 2011 +0200
@@ -112,10 +112,15 @@
     public void print(Graph graph, String title, boolean shortNames) {
         stream.printf(" <graph name='%s'>%n", escape(title));
 
-        Schedule schedule = new Schedule(graph);
+        Schedule schedule = null;
+        try {
+            schedule = new Schedule(graph);
+        } catch (Throwable t) {
+            // nothing to do here...
+        }
 
         stream.println("  <nodes>");
-        List<Edge> edges = printNodes(graph.getNodes(), shortNames, schedule.getNodeToBlock());
+        List<Edge> edges = printNodes(graph.getNodes(), shortNames, schedule == null ? null : schedule.getNodeToBlock());
         stream.println("  </nodes>");
 
         stream.println("  <edges>");
@@ -125,10 +130,12 @@
         stream.println("  </edges>");
 
         stream.println("  <controlFlow>");
-        for (Block block : schedule.getBlocks()) {
-            printBlock(graph, block);
+        if (schedule != null) {
+            for (Block block : schedule.getBlocks()) {
+                printBlock(graph, block);
+            }
+            printNoBlock();
         }
-        printNoBlock();
         stream.println("  </controlFlow>");
 
         stream.println(" </graph>");
@@ -155,12 +162,14 @@
                 }
                 stream.printf("    <p name='name'>%s</p>%n", escape(name));
             }
-            Block block = nodeToBlock.get(node);
-            if (block != null) {
-                stream.printf("    <p name='block'>%d</p>%n", block.blockID());
-            } else {
-                stream.printf("    <p name='block'>noBlock</p>%n");
-                noBlockNodes.add(node);
+            if (nodeToBlock != null) {
+                Block block = nodeToBlock.get(node);
+                if (block != null) {
+                    stream.printf("    <p name='block'>%d</p>%n", block.blockID());
+                } else {
+                    stream.printf("    <p name='block'>noBlock</p>%n");
+                    noBlockNodes.add(node);
+                }
             }
             for (Entry<Object, Object> entry : props.entrySet()) {
                 String key = entry.getKey().toString();
--- a/graal/GraalCompiler/src/com/sun/c1x/gen/PhiSimplifier.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/gen/PhiSimplifier.java	Tue Jun 07 16:27:08 2011 +0200
@@ -23,7 +23,6 @@
 package com.sun.c1x.gen;
 
 import com.oracle.graal.graph.*;
-import com.sun.c1x.graph.*;
 import com.sun.c1x.ir.*;
 
 /**
@@ -34,8 +33,7 @@
     private NodeBitMap visited;
     private NodeBitMap cannotSimplify;
 
-    public PhiSimplifier(IR ir) {
-        Graph graph = ir.compilation.graph;
+    public PhiSimplifier(Graph graph) {
         visited = graph.createNodeBitMap();
         cannotSimplify = graph.createNodeBitMap();
 
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Tue Jun 07 16:27:08 2011 +0200
@@ -121,9 +121,11 @@
 
     /**
      * Builds the graph for a the specified {@code IRScope}.
-     * @param scope the top IRScope
+     *
+     * @param createUnwind setting this to true will always generate an unwind block, even if there is no exception
+     *            handler and the method is not synchronized
      */
-    public void build() {
+    public void build(boolean createUnwind) {
         if (log != null) {
             log.println();
             log.println("Compiling " + method);
@@ -161,6 +163,10 @@
         } else {
             // 4B.1 simply finish the start block
             finishStartBlock(startBlock);
+
+            if (createUnwind) {
+                syncHandler = new CiExceptionHandler(0, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null);
+            }
         }
 
         // 5. SKIPPED: look for intrinsics
@@ -544,6 +550,7 @@
         Value yValue = frameState.pop(y);
         Value xValue = frameState.pop(x);
         Value result1 = append(new ArithmeticOp(opcode, result, xValue, yValue, isStrict(method.accessFlags()), canTrap, graph));
+        append(new ValueAnchor(result1, graph));
         frameState.push(result, result1);
     }
 
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Tue Jun 07 16:27:08 2011 +0200
@@ -83,15 +83,6 @@
             C1XTimers.HIR_OPTIMIZE.start();
         }
 
-        new PhiSimplifier(this);
-
-//        Graph newGraph = new Graph();
-//        HashMap<Node, Node> replacement = new HashMap<Node, Node>();
-//        replacement.put(compilation.graph.start(), newGraph.start());
-//        replacement.put(compilation.graph.end(), newGraph.end());
-//        newGraph.addDuplicate(compilation.graph.getNodes(), replacement);
-//        compilation.graph = newGraph;
-
         Graph graph = compilation.graph;
 
         // Split critical edges.
@@ -102,7 +93,7 @@
                 for (int j = 0; j < n.successors().size(); ++j) {
                     Node succ = n.successors().get(j);
                     if (Schedule.truePredecessorCount(succ) > 1) {
-                        Anchor a = new Anchor(null, graph);
+                        Anchor a = new Anchor(graph);
                         a.successors().setAndClear(1, n, j);
                         n.successors().set(j, a);
                     }
@@ -164,52 +155,18 @@
 
     private void buildGraph() {
         // Graph builder must set the startBlock and the osrEntryBlock
-        new GraphBuilder(compilation, compilation.method, compilation.graph).build();
+        new GraphBuilder(compilation, compilation.method, compilation.graph).build(false);
 
         verifyAndPrint("After graph building");
 
-        List<Invoke> trivialInline = new ArrayList<Invoke>();
-        List<Invoke> deoptInline = new ArrayList<Invoke>();
-        List<RiMethod> deoptMethods = new ArrayList<RiMethod>();
-        for (Node node : compilation.graph.getNodes()) {
-            if (node instanceof Invoke) {
-                Invoke invoke = (Invoke) node;
-                RiMethod target = invoke.target;
-                if (target.isResolved() && !Modifier.isNative(target.accessFlags())) {
-                    if (target.canBeStaticallyBound()) {
-                        trivialInline.add(invoke);
-                    } else {
-                        RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target);
-                        if (concrete != null) {
-                            deoptInline.add(invoke);
-                            deoptMethods.add(concrete);
-                        }
-                    }
-                }
-            }
+        DeadCodeElimination dce = new DeadCodeElimination();
+        dce.apply(compilation.graph);
+        if (dce.deletedNodeCount > 0) {
+            verifyAndPrint("After dead code elimination");
         }
 
-        int allowedInlinings = 50;
-        for (Invoke invoke : trivialInline) {
-            if (inlineMethod(invoke, invoke.target)) {
-                if (--allowedInlinings <= 0) {
-                    break;
-                }
-            }
-        }
-
-        for (int i = 0; i < deoptInline.size(); i++) {
-            Invoke invoke = deoptInline.get(i);
-            RiMethod method = deoptMethods.get(i);
-            if (inlineMethod(invoke, method)) {
-                if (C1XOptions.TraceInlining) {
-                    System.out.println("registering concrete method assumption...");
-                }
-                compilation.assumptions.recordConcreteMethod(invoke.target, method);
-                if (--allowedInlinings <= 0) {
-                    break;
-                }
-            }
+        if (C1XOptions.Inline) {
+            inlineMethods();
         }
 
         if (C1XOptions.PrintCompilation) {
@@ -217,23 +174,100 @@
         }
     }
 
+    private void inlineMethods() {
+        int inliningSize = compilation.method.code().length;
+        boolean inlined;
+        int iterations = C1XOptions.MaximumRecursiveInlineLevel;
+        do {
+            inlined = false;
+
+            List<Invoke> trivialInline = new ArrayList<Invoke>();
+            List<Invoke> deoptInline = new ArrayList<Invoke>();
+            List<RiMethod> deoptMethods = new ArrayList<RiMethod>();
+            for (Node node : compilation.graph.getNodes()) {
+                if (node instanceof Invoke) {
+                    Invoke invoke = (Invoke) node;
+                    RiMethod target = invoke.target;
+                    if (target.isResolved() && !Modifier.isNative(target.accessFlags())) {
+                        if (target.canBeStaticallyBound()) {
+                            trivialInline.add(invoke);
+                        } else {
+                            RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target);
+                            if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags())) {
+                                deoptInline.add(invoke);
+                                deoptMethods.add(concrete);
+                            }
+                        }
+                    }
+                }
+            }
+
+            for (Invoke invoke : trivialInline) {
+                if (inlineMethod(invoke, invoke.target)) {
+                    inlined = true;
+                    inliningSize += invoke.target.code().length;
+                    if (inliningSize > C1XOptions.MaximumInstructionCount) {
+                        break;
+                    }
+                }
+            }
+
+            for (int i = 0; i < deoptInline.size(); i++) {
+                Invoke invoke = deoptInline.get(i);
+                RiMethod method = deoptMethods.get(i);
+                if (inlineMethod(invoke, method)) {
+                    if (C1XOptions.TraceInlining) {
+                        System.out.println("registering concrete method assumption...");
+                    }
+                    compilation.assumptions.recordConcreteMethod(invoke.target, method);
+                    inlined = true;
+                    inliningSize += method.code().length;
+                    if (inliningSize > C1XOptions.MaximumInstructionCount) {
+                        break;
+                    }
+                }
+            }
+
+            if (inlined) {
+                DeadCodeElimination dce = new DeadCodeElimination();
+                dce.apply(compilation.graph);
+                if (dce.deletedNodeCount > 0) {
+                    verifyAndPrint("After dead code elimination");
+                }
+                verifyAndPrint("After inlining iteration");
+            }
+
+            if (inliningSize > C1XOptions.MaximumInstructionCount) {
+                break;
+            }
+        } while(inlined && (--iterations > 0));
+    }
+
     private boolean inlineMethod(Invoke invoke, RiMethod method) {
         String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)";
+        FrameState stateAfter = invoke.stateAfter();
 
-        if (method.code().length > 50) {
+        if (method.code().length > C1XOptions.MaximumInlineSize) {
             if (C1XOptions.TraceInlining) {
                 System.out.println("not inlining " + name + " because of code size");
             }
             return false;
         }
 
-        Instruction exceptionEdge = invoke.exceptionEdge();
-        if (exceptionEdge != null) {
+        if (invoke.predecessors().size() == 0) {
             if (C1XOptions.TraceInlining) {
-                System.out.println("not inlining " + name + " because of exceptionEdge");
+                System.out.println("not inlining " + name + " because the invoke is dead code");
             }
             return false;
         }
+
+        Instruction exceptionEdge = invoke.exceptionEdge();
+//        if (exceptionEdge != null) {
+//            if (C1XOptions.TraceInlining) {
+//                System.out.println("not inlining " + name + " because of exceptionEdge");
+//            }
+//            return false;
+//        }
         if (!method.holder().isInitialized()) {
             if (C1XOptions.TraceInlining) {
                 System.out.println("not inlining " + name + " because of non-initialized class");
@@ -242,10 +276,11 @@
         }
 
         if (C1XOptions.TraceInlining) {
-            System.out.println("building graph: " + name);
+            System.out.printf("Building graph for %s, locals: %d, stack: %d\n", name, method.maxLocals(), method.maxStackSize());
         }
+
         CompilerGraph graph = new CompilerGraph();
-        new GraphBuilder(compilation, method, graph).build();
+        new GraphBuilder(compilation, method, graph).build(true);
 
         boolean withReceiver = !Modifier.isStatic(method.accessFlags());
 
@@ -266,12 +301,11 @@
         ArrayList<Node> frameStates = new ArrayList<Node>();
         Return returnNode = null;
         Unwind unwindNode = null;
-        StartNode startNode = null;
-        boolean invokes = false;
+        StartNode startNode = graph.start();
         for (Node node : graph.getNodes()) {
             if (node != null) {
                 if (node instanceof StartNode) {
-                    startNode = (StartNode) node;
+                    assert startNode == node;
                 } else if (node instanceof Local) {
                     replacements.put(node, parameters[((Local) node).index()]);
                 } else {
@@ -286,30 +320,19 @@
                 }
             }
         }
-        if (unwindNode != null) {
-            if (C1XOptions.TraceInlining) {
-                System.out.println("not inlining " + name + " because of unwind node");
-            }
-            return false;
-        }
-        if (invokes) {
-            if (C1XOptions.TraceInlining) {
-                System.out.println("not inlining " + name + " because of invokes");
-            }
-            return false;
-        }
 
         if (C1XOptions.TraceInlining) {
+            printGraph("Subgraph " + CiUtil.format("%H.%n(%p):%r", method, false), graph);
             System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes");
         }
 
+        assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size();
         Instruction pred;
         if (withReceiver) {
             pred = new NullCheck(parameters[0], compilation.graph);
         } else {
             pred = new Merge(compilation.graph);
         }
-        assert invoke.predecessors().size() == 1;
         invoke.predecessors().get(0).successors().replace(invoke, pred);
         replacements.put(startNode, pred);
 
@@ -331,10 +354,48 @@
             Node returnPred = returnDuplicate.predecessors().get(0);
             int index = returnDuplicate.predecessorsIndex().get(0);
             returnPred.successors().setAndClear(index, invoke, 0);
-
             returnDuplicate.delete();
         }
-        FrameState stateAfter = invoke.stateAfter();
+
+//        if (invoke.next() instanceof Merge) {
+//            ((Merge) invoke.next()).removePhiPredecessor(invoke);
+//        }
+//        invoke.successors().clearAll();
+        invoke.inputs().clearAll();
+        invoke.setExceptionEdge(null);
+//        invoke.delete();
+
+
+        if (exceptionEdge != null) {
+            if (unwindNode != null) {
+                assert unwindNode.predecessors().size() == 1;
+                assert exceptionEdge.successors().size() == 1;
+                ExceptionObject obj = (ExceptionObject) exceptionEdge;
+
+                List<Node> usages = new ArrayList<Node>(obj.usages());
+                for (Node usage : usages) {
+                    if (replacements.containsKey(unwindNode.exception())) {
+                        usage.inputs().replace(obj, replacements.get(unwindNode.exception()));
+                    } else {
+                        usage.inputs().replace(obj, duplicates.get(unwindNode.exception()));
+                    }
+                }
+                Node unwindDuplicate = duplicates.get(unwindNode);
+                unwindDuplicate.inputs().clearAll();
+
+                assert unwindDuplicate.predecessors().size() == 1;
+                Node unwindPred = unwindDuplicate.predecessors().get(0);
+                int index = unwindDuplicate.predecessorsIndex().get(0);
+                unwindPred.successors().setAndClear(index, obj, 0);
+
+                obj.inputs().clearAll();
+                obj.delete();
+                unwindDuplicate.delete();
+
+            }
+        }
+
+        // adjust all frame states that were copied
         if (frameStates.size() > 0) {
             FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind);
             for (Node frameState : frameStates) {
@@ -342,52 +403,12 @@
             }
         }
 
-        invoke.successors().clearAll();
-        invoke.inputs().clearAll();
-        invoke.delete();
-
-        stateAfter.delete();
-
-        deleteUnused(exceptionEdge);
-
-        verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false));
+        if (C1XOptions.TraceInlining) {
+            verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false));
+        }
         return true;
     }
 
-    private void deleteUnused(Node node) {
-        if (node != null && node.predecessors().size() == 0) {
-            if (node instanceof ExceptionObject) {
-                Node successor = node.successors().get(0);
-                node.successors().clearAll();
-                if (successor instanceof ExceptionDispatch) {
-                    ExceptionDispatch dispatch = (ExceptionDispatch) successor;
-                    Node succ1 = dispatch.catchSuccessor();
-                    Node succ2 = dispatch.otherSuccessor();
-                    if (succ1 instanceof Merge) {
-                        ((Merge) succ1).removePhiPredecessor(dispatch);
-                    }
-                    if (succ2 instanceof Merge) {
-                        ((Merge) succ2).removePhiPredecessor(dispatch);
-                    }
-                    dispatch.successors().clearAll();
-                    deleteUnused(succ1);
-                    deleteUnused(succ2);
-                    dispatch.delete();
-                } else {
-                    assert successor instanceof Merge;
-                    System.out.println("succ: " + successor.successors().get(0));
-                    Node next = successor.successors().get(0);
-                    successor.successors().clearAll();
-                    deleteUnused(next);
-                    successor.delete();
-                }
-                node.delete();
-            } else if (node instanceof Unwind) {
-                node.delete();
-            }
-        }
-    }
-
     /**
      * Gets the linear scan ordering of blocks as a list.
      * @return the blocks in linear scan order
@@ -420,6 +441,17 @@
         }
     }
 
+    public void printGraph(String phase, Graph graph) {
+        if (C1XOptions.PrintHIR && !TTY.isSuppressed()) {
+            TTY.println(phase);
+            print(false);
+        }
+
+        if (compilation.compiler.isObserved()) {
+            compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, phase, graph, true, false));
+        }
+    }
+
     public int numLoops() {
         return compilation.stats.loopCount;
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Anchor.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Anchor.java	Tue Jun 07 16:27:08 2011 +0200
@@ -27,7 +27,7 @@
 import com.sun.cri.ci.*;
 
 /**
- * The {@code Goto} instruction represents the end of a block with an unconditional jump to another block.
+ * The {@code Anchor} instruction represents the end of a block with an unconditional jump to another block.
  */
 public final class Anchor extends BlockEnd {
 
@@ -35,14 +35,11 @@
     private static final int SUCCESSOR_COUNT = 0;
 
     /**
-     * Constructs a new Goto instruction.
-     * @param succ the successor block of the goto
-     * @param stateAfter the frame state at the end of this block
+     * Constructs a new Anchor instruction.
      * @param graph
      */
-    public Anchor(Instruction succ, Graph graph) {
+    public Anchor(Graph graph) {
         super(CiKind.Illegal, 1, INPUT_COUNT, SUCCESSOR_COUNT, graph);
-        setBlockSuccessor(0, succ);
     }
 
     @Override
@@ -57,7 +54,7 @@
 
     @Override
     public Node copy(Graph into) {
-        Anchor x = new Anchor(null, into);
+        Anchor x = new Anchor(into);
         x.setNonNull(isNonNull());
         return x;
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Deoptimize.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Deoptimize.java	Tue Jun 07 16:27:08 2011 +0200
@@ -57,7 +57,7 @@
 
     @Override
     public String shortName() {
-        return "Deopt " + message;
+        return message == null ? "Deopt " : "Deopt " + message;
     }
 
     @Override
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Merge.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Merge.java	Tue Jun 07 16:27:08 2011 +0200
@@ -268,15 +268,15 @@
         return x;
     }
 
-    public void removePhiPredecessor(ExceptionDispatch successor) {
-        int predIndex = predecessors().indexOf(successor);
+    public void removePhiPredecessor(Node pred) {
+        int predIndex = predecessors().lastIndexOf(pred);
         assert predIndex != -1;
 
         for (Node usage : usages()) {
             if (usage instanceof Phi) {
                 Phi phi = (Phi) usage;
-                assert phi.valueCount() == predecessors().size();
-                phi.removeInput(predIndex + 1);
+//                assert phi.valueCount() == predecessors().size();
+                phi.removeInput(predIndex);
             }
         }
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java	Tue Jun 07 16:27:08 2011 +0200
@@ -78,7 +78,7 @@
     public Phi(CiKind kind, Merge block, int maxValues, Graph graph) {
         super(kind, INPUT_COUNT + maxValues, SUCCESSOR_COUNT, graph);
         this.maxValues = maxValues;
-        usedInputCount = 1;
+        usedInputCount = 0;
         setBlock(block);
     }
 
@@ -89,7 +89,11 @@
      * @return the instruction that produced the value in the i'th predecessor
      */
     public Value valueAt(int i) {
-        return (Value) inputs().get(i + INPUT_COUNT);
+        return (Value) inputs().get(INPUT_COUNT + i);
+    }
+
+    public Node setValueAt(int i, Node x) {
+        return inputs().set(INPUT_COUNT + i, x);
     }
 
     /**
@@ -97,7 +101,7 @@
      * @return the number of inputs in this phi
      */
     public int valueCount() {
-        return usedInputCount - 1;
+        return usedInputCount;
     }
 
     @Override
@@ -119,11 +123,11 @@
     @Override
     public void print(LogStream out) {
         out.print("phi function (");
-        for (int i = 0; i < inputs().size(); ++i) {
+        for (int i = 0; i < valueCount(); ++i) {
             if (i != 0) {
                 out.print(' ');
             }
-            out.print((Value) inputs().get(i));
+            out.print(valueAt(i));
         }
         out.print(')');
     }
@@ -143,23 +147,24 @@
     public Phi addInput(Node y) {
         assert !this.isDeleted() && !y.isDeleted();
         Phi phi = this;
-        if (usedInputCount == inputs().size()) {
-            phi = new Phi(kind, block(), usedInputCount * 2, graph());
+        if (usedInputCount == maxValues) {
+            phi = new Phi(kind, block(), maxValues * 2, graph());
             for (int i = 0; i < valueCount(); ++i) {
                 phi.addInput(valueAt(i));
             }
             phi.addInput(y);
             this.replace(phi);
         } else {
-            phi.inputs().set(usedInputCount++, y);
+            setValueAt(usedInputCount++, y);
         }
         return phi;
     }
 
     public void removeInput(int index) {
-        inputs().set(index, null);
-        for (int i = index + 1; i < usedInputCount; ++i) {
-            inputs().set(i - 1, inputs().get(i));
+        assert index < valueCount() : "index: " + index + ", valueCount: " + valueCount() + "@phi " + id();
+        setValueAt(index, Node.Null);
+        for (int i = index + 1; i < valueCount(); ++i) {
+            setValueAt(i - 1, valueAt(i));
         }
         usedInputCount--;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/ValueAnchor.java	Tue Jun 07 16:27:08 2011 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2011, 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.sun.c1x.ir;
+
+import com.oracle.graal.graph.*;
+import com.sun.c1x.debug.*;
+import com.sun.cri.ci.*;
+
+/**
+ * The ValueAnchor instruction keeps non-CFG nodes above a certain point in the graph.
+ */
+public final class ValueAnchor extends Instruction {
+
+    private static final int INPUT_COUNT = 1;
+    private static final int INPUT_OBJECT = 0;
+
+    private static final int SUCCESSOR_COUNT = 0;
+
+    @Override
+    protected int inputCount() {
+        return super.inputCount() + INPUT_COUNT;
+    }
+
+    @Override
+    protected int successorCount() {
+        return super.successorCount() + SUCCESSOR_COUNT;
+    }
+
+    /**
+     * The instruction that should be scheduled before this anchor.
+     */
+     public Value object() {
+        return (Value) inputs().get(super.inputCount() + INPUT_OBJECT);
+    }
+
+    public Value setObject(Value n) {
+        return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n);
+    }
+
+    /**
+     * Constructs a new Anchor instruction.
+     * @param succ the successor block of the anchor
+     * @param graph
+     */
+    public ValueAnchor(Value object, Graph graph) {
+        super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        setObject(object);
+    }
+
+    @Override
+    public void accept(ValueVisitor v) {
+        v.visitValueAnchor(this);
+    }
+
+    @Override
+    public void print(LogStream out) {
+        out.print("value_anchor ").print(object());
+    }
+
+    @Override
+    public Node copy(Graph into) {
+        ValueAnchor x = new ValueAnchor(null, into);
+        x.setNonNull(isNonNull());
+        return x;
+    }
+}
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/ValueVisitor.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/ValueVisitor.java	Tue Jun 07 16:27:08 2011 +0200
@@ -71,4 +71,5 @@
     public abstract void visitUnwind(Unwind unwind);
     public abstract void visitLoopBegin(LoopBegin loopBegin);
     public abstract void visitLoopEnd(LoopEnd loopEnd);
+    public abstract void visitValueAnchor(ValueAnchor valueAnchor);
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.java	Tue Jun 07 16:27:08 2011 +0200
@@ -547,4 +547,9 @@
         lir.jump(getLIRBlock(x.loopBegin()));
     }
 
+    @Override
+    public void visitValueAnchor(ValueAnchor valueAnchor) {
+        // nothing to do for ValueAnchors
+    }
+
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java	Tue Jun 07 16:27:08 2011 +0200
@@ -49,7 +49,9 @@
         this.method = method;
         this.graph = graph;
         this.locals = new Value[method.maxLocals()];
-        this.stack = new Value[method.maxStackSize()];
+        // we always need at least one stack slot (for exceptions)
+        int stackSize = Math.max(1, method.maxStackSize());
+        this.stack = new Value[stackSize];
 
         int javaIndex = 0;
         int index = 0;
@@ -82,8 +84,8 @@
     }
 
     public void initializeFrom(FrameState other) {
-        assert locals.length == other.localsSize();
-        assert stack.length >= other.stackSize();
+        assert locals.length == other.localsSize() : "expected: " + locals.length + ", actual: " + other.localsSize();
+        assert stack.length >= other.stackSize() : "expected: <=" + stack.length + ", actual: " + other.stackSize();
 
         this.stackIndex = other.stackSize();
         for (int i = 0; i < other.localsSize(); i++) {
--- a/graal/GraalGraph/src/com/oracle/graal/graph/Node.java	Wed Jun 01 16:56:54 2011 +0200
+++ b/graal/GraalGraph/src/com/oracle/graal/graph/Node.java	Tue Jun 07 16:27:08 2011 +0200
@@ -118,7 +118,7 @@
 
     public void delete() {
         assert !isDeleted();
-        assert usages.size() == 0 && predecessors.size() == 0 : "usages: " + usages.size() + ", predecessors: " + predecessors().size();
+        assert usages.size() == 0 && predecessors.size() == 0 : "id: " + id + ", usages: " + usages.size() + ", predecessors: " + predecessors().size();
         assert predecessorsIndex.size() == 0;
         for (int i = 0; i < inputs.size(); ++i) {
             inputs.set(i, Null);