changeset 2840:75e0d39833a0

new CompilerGraph, create only one Return and one Unwind per CompilerGraph
author Lukas Stadler <lukas.stadler@jku.at>
date Tue, 31 May 2011 16:53:19 +0200
parents 7b5831f0e913
children 633e66de40fe
files graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java graal/GraalCompiler/src/com/sun/c1x/graph/BlockMap.java graal/GraalCompiler/src/com/sun/c1x/graph/CompilerGraph.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/Return.java graal/GraalCompiler/src/com/sun/c1x/ir/Unwind.java graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java graal/GraalCompiler/src/com/sun/c1x/value/FrameStateAccess.java graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java graal/GraalGraph/src/com/oracle/graal/graph/EndNode.java graal/GraalGraph/src/com/oracle/graal/graph/Graph.java
diffstat 12 files changed, 198 insertions(+), 203 deletions(-) [+]
line wrap: on
line diff
--- a/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java	Tue May 31 13:42:01 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java	Tue May 31 16:53:19 2011 +0200
@@ -56,7 +56,7 @@
     public final CiAssumptions assumptions = new CiAssumptions();
     public final FrameState placeholderState;
 
-    public Graph graph = new Graph();
+    public CompilerGraph graph = new CompilerGraph();
 
     private boolean hasExceptionHandlers;
     private final C1XCompilation parent;
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/BlockMap.java	Tue May 31 13:42:01 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/BlockMap.java	Tue May 31 16:53:19 2011 +0200
@@ -401,15 +401,6 @@
 
     private ExceptionBlock unwindBlock;
 
-    private ExceptionBlock makeUnwind() {
-        if (unwindBlock == null) {
-            unwindBlock = new ExceptionBlock();
-            unwindBlock.startBci = -1;
-            unwindBlock.endBci = -1;
-        }
-        return unwindBlock;
-    }
-
     private Block makeExceptionDispatch(List<RiExceptionHandler> handlers, int index) {
         RiExceptionHandler handler = handlers.get(index);
         if (handler.isCatchAll()) {
@@ -422,14 +413,10 @@
             block.endBci = -1;
             block.handler = handler;
             block.successors.add(blockMap[handler.handlerBCI()]);
-            Block next;
             if (index < handlers.size() - 1) {
-                next = makeExceptionDispatch(handlers, index + 1);
-            } else {
-                next = makeUnwind();
+                block.next = makeExceptionDispatch(handlers, index + 1);
+                block.successors.add(block.next);
             }
-            block.successors.add(next);
-            block.next = next;
             exceptionDispatch.put(handler, block);
         }
         return block;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/CompilerGraph.java	Tue May 31 16:53:19 2011 +0200
@@ -0,0 +1,53 @@
+/*
+ * 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.graph;
+
+import com.oracle.graal.graph.*;
+import com.sun.c1x.ir.*;
+
+
+public class CompilerGraph extends Graph {
+
+    private Return returnSingleton;
+    private Unwind unwindSingleton;
+
+    public Return createReturn(Value result) {
+        assert returnSingleton == null;
+        returnSingleton = new Return(result, this);
+        return returnSingleton;
+    }
+
+    public Return getReturn() {
+        return returnSingleton;
+    }
+
+    public Unwind createUnwind(Value exception) {
+        assert unwindSingleton == null;
+        unwindSingleton = new Unwind(exception, this);
+        return unwindSingleton;
+    }
+
+    public Unwind getUnwind() {
+        return unwindSingleton;
+    }
+}
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Tue May 31 13:42:01 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Tue May 31 16:53:19 2011 +0200
@@ -29,17 +29,18 @@
 import java.util.*;
 
 import com.oracle.graal.graph.*;
-import com.oracle.max.graal.schedule.Schedule;
+import com.oracle.max.graal.schedule.*;
 import com.sun.c1x.*;
 import com.sun.c1x.debug.*;
-import com.sun.c1x.graph.BlockMap.*;
+import com.sun.c1x.graph.BlockMap.Block;
+import com.sun.c1x.graph.BlockMap.ExceptionBlock;
 import com.sun.c1x.ir.*;
 import com.sun.c1x.util.*;
 import com.sun.c1x.value.*;
 import com.sun.cri.bytecode.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
-import com.sun.cri.ri.RiType.*;
+import com.sun.cri.ri.RiType.Representation;
 
 /**
  * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph.
@@ -72,6 +73,9 @@
     private Block syncBlock;
     private CiExceptionHandler syncHandler;
 
+    private Block unwindBlock;
+    private Block returnBlock;
+
     // the constant pool
     private final RiConstantPool constantPool;
 
@@ -89,7 +93,7 @@
 
     private Value rootMethodSynchronizedObject;
 
-    private final Graph graph;
+    private final CompilerGraph graph;
 
     /**
      * Creates a new, initialized, {@code GraphBuilder} instance for a given compilation.
@@ -98,7 +102,7 @@
      * @param ir the IR to build the graph into
      * @param graph
      */
-    public GraphBuilder(C1XCompilation compilation, IR ir, Graph graph) {
+    public GraphBuilder(C1XCompilation compilation, IR ir, CompilerGraph graph) {
         this.compilation = compilation;
         this.ir = ir;
         this.stats = compilation.stats;
@@ -149,9 +153,6 @@
             finishStartBlock(startBlock);
 
             // 4A.3 setup an exception handler to unlock the root method synchronized object
-            syncBlock = nextBlock(Instruction.SYNCHRONIZATION_ENTRY_BCI);
-            markOnWorkList(syncBlock);
-
             syncHandler = new CiExceptionHandler(0, rootMethod.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null);
         } else {
             // 4B.1 simply finish the start block
@@ -164,11 +165,6 @@
         addToWorkList(blockFromBci[0]);
         iterateAllBlocks();
 
-        if (syncBlock != null && syncBlock.firstInstruction != null) {
-            // generate unlocking code if the exception handler is reachable
-            fillSyncHandler(rootMethodSynchronizedObject, syncBlock);
-        }
-
         for (Node n : graph.getNodes()) {
             if (n instanceof Placeholder) {
                 Placeholder p = (Placeholder) n;
@@ -210,6 +206,29 @@
         return block;
     }
 
+    private Block unwindBlock() {
+        if (unwindBlock == null) {
+            unwindBlock = new Block();
+            unwindBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI;
+            unwindBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI;
+            unwindBlock.blockID = ir.nextBlockNumber();
+            addToWorkList(unwindBlock);
+        }
+        return unwindBlock;
+    }
+
+    private Block returnBlock() {
+        if (returnBlock == null) {
+            returnBlock = new Block();
+            returnBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI;
+            returnBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI;
+            returnBlock.blockID = ir.nextBlockNumber();
+            addToWorkList(returnBlock);
+        }
+        return returnBlock;
+    }
+
+
     private Set<Block> blocksOnWorklist = new HashSet<Block>();
 
     private void markOnWorkList(Block block) {
@@ -375,7 +394,7 @@
                 assert isCatchAll(firstHandler);
                 int handlerBCI = firstHandler.handlerBCI();
                 if (handlerBCI == Instruction.SYNCHRONIZATION_ENTRY_BCI) {
-                    dispatchBlock = syncBlock;
+                    dispatchBlock = unwindBlock();
                 } else {
                     dispatchBlock = blockFromBci[handlerBCI];
                 }
@@ -609,11 +628,15 @@
     private void genThrow(int bci) {
         Value exception = frameState.apop();
         append(new NullCheck(exception, graph));
+
         Instruction entry = handleException(exception, bci);
-        if (entry == null) {
-            entry = new Unwind(exception, graph.end(), graph);
+        if (entry != null) {
+            append(entry);
+        } else {
+            frameState.clearStack();
+            frameState.apush(exception);
+            appendGoto(createTarget(unwindBlock(), frameState));
         }
-        append(entry);
     }
 
     private void genCheckCast() {
@@ -893,23 +916,11 @@
     }
 
     private void genReturn(Value x) {
-        if (method().isConstructor() && method().holder().superType() == null) {
-            callRegisterFinalizer();
+        frameState.clearStack();
+        if (x != null) {
+            frameState.push(x.kind, x);
         }
-
-        frameState.clearStack();
-        if (Modifier.isSynchronized(method().accessFlags())) {
-            // unlock before exiting the method
-            int lockNumber = frameState.locksSize() - 1;
-            MonitorAddress lockAddress = null;
-            if (compilation.runtime.sizeOfBasicObjectLock() != 0) {
-                lockAddress = new MonitorAddress(lockNumber, graph);
-                append(lockAddress);
-            }
-            append(new MonitorExit(rootMethodSynchronizedObject, lockAddress, lockNumber, graph));
-            frameState.unlock();
-        }
-        append(new Return(x, graph));
+        appendGoto(createTarget(returnBlock(), frameState));
     }
 
     private void genMonitorEnter(Value x, int bci) {
@@ -1066,27 +1077,6 @@
         }
     }
 
-    private void fillSyncHandler(Value lock, Block syncHandler) {
-        lastInstr = syncHandler.firstInstruction;
-        while (lastInstr.next() != null) {
-            // go forward to the end of the block
-            lastInstr = lastInstr.next();
-        }
-
-        frameState.initializeFrom(((StateSplit) syncHandler.firstInstruction).stateBefore());
-
-        assert lock != null;
-        assert frameState.locksSize() > 0 && frameState.lockAt(frameState.locksSize() - 1) == lock;
-
-        // Exit the monitor and unwind the stack.
-        genMonitorExit(lock);
-        append(new Unwind(frameState.apop(), graph.end(), graph));
-
-        // The sync handler is always the last thing to add => we can clear the frameState.
-        frameState = null;
-        lastInstr = null;
-    }
-
     private void iterateAllBlocks() {
         Block block;
         while ((block = removeFromWorkList()) != null) {
@@ -1104,7 +1094,11 @@
                 lastInstr = block.firstInstruction;
                 assert block.firstInstruction.next() == null : "instructions already appended at block " + block.blockID;
 
-                if (block instanceof ExceptionBlock) {
+                if (block == returnBlock) {
+                    createReturnBlock(block);
+                } else if (block == unwindBlock) {
+                    createUnwindBlock(block);
+                } else if (block instanceof ExceptionBlock) {
                     createExceptionDispatch((ExceptionBlock) block);
                 } else {
                     iterateBytecodesForBlock(block);
@@ -1135,33 +1129,44 @@
         }
     }
 
+    private void createUnwindBlock(Block block) {
+        if (Modifier.isSynchronized(method().accessFlags())) {
+            genMonitorExit(rootMethodSynchronizedObject);
+        }
+        append(graph.createUnwind(frameState.apop()));
+    }
+
+    private void createReturnBlock(Block block) {
+        if (method().isConstructor() && method().holder().superType() == null) {
+            callRegisterFinalizer();
+        }
+        CiKind returnKind = method().signature().returnKind().stackKind();
+        Value x = returnKind == CiKind.Void ? null : frameState.pop(returnKind);
+        assert frameState.stackSize() == 0;
+
+        if (Modifier.isSynchronized(method().accessFlags())) {
+            genMonitorExit(rootMethodSynchronizedObject);
+        }
+        append(graph.createReturn(x));
+    }
+
     private void createExceptionDispatch(ExceptionBlock block) {
         if (block.handler == null) {
             assert frameState.stackSize() == 1 : "only exception object expected on stack, actual size: " + frameState.stackSize();
-            if (Modifier.isSynchronized(method().accessFlags())) {
-                // unlock before exiting the method
-                int lockNumber = frameState.locksSize() - 1;
-                MonitorAddress lockAddress = null;
-                if (compilation.runtime.sizeOfBasicObjectLock() != 0) {
-                    lockAddress = new MonitorAddress(lockNumber, graph);
-                    append(lockAddress);
-                }
-                append(new MonitorExit(rootMethodSynchronizedObject, lockAddress, lockNumber, graph));
-                frameState.unlock();
-            }
-            append(new Unwind(frameState.apop(), graph.end(), graph));
+            createUnwindBlock(block);
         } else {
             assert frameState.stackSize() == 1;
 
+            Block nextBlock = block.next == null ? unwindBlock() : block.next;
             if (block.handler.catchType().isResolved()) {
                 Instruction catchSuccessor = createTarget(blockFromBci[block.handler.handlerBCI()], frameState);
-                Instruction nextDispatch = createTarget(block.next, frameState);
+                Instruction nextDispatch = createTarget(nextBlock, frameState);
                 append(new ExceptionDispatch(frameState.stackAt(0), catchSuccessor, nextDispatch, block.handler.catchType(), graph));
             } else {
                 Deoptimize deopt = new Deoptimize(graph);
                 deopt.setMessage("unresolved " + block.handler.catchType().name());
                 append(deopt);
-                Instruction nextDispatch = createTarget(block.next, frameState);
+                Instruction nextDispatch = createTarget(nextBlock, frameState);
                 appendGoto(nextDispatch);
             }
         }
@@ -1185,8 +1190,7 @@
             if (nextBlock != null && nextBlock != block) {
                 assert !nextBlock.isExceptionEntry;
                 // we fell through to the next block, add a goto and break
-                Instruction next = createTarget(nextBlock, frameState);
-                appendGoto(next);
+                appendGoto(createTarget(nextBlock, frameState));
                 break;
             }
             // read the opcode
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Tue May 31 13:42:01 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Tue May 31 16:53:19 2011 +0200
@@ -32,6 +32,7 @@
 import com.sun.c1x.ir.*;
 import com.sun.c1x.lir.*;
 import com.sun.c1x.observer.*;
+import com.sun.c1x.value.*;
 
 /**
  * This class implements the overall container for the HIR (high-level IR) graph
@@ -49,8 +50,6 @@
      */
     public LIRBlock startBlock;
 
-    private int maxLocks;
-
     /**
      * The linear-scan ordered list of blocks.
      */
@@ -210,21 +209,18 @@
     }
 
     /**
-     * Updates the maximum number of locks held at any one time.
-     *
-     * @param locks a lock count that will replace the current {@linkplain #maxLocks() max locks} if it is greater
-     */
-    public void updateMaxLocks(int locks) {
-        if (locks > maxLocks) {
-            maxLocks = locks;
-        }
-    }
-
-    /**
-     * Gets the number of locks.
-     * @return the number of locks
+     * Gets the maximum number of locks in the graph's frame states.
      */
     public final int maxLocks() {
+        int maxLocks = 0;
+        for (Node node : compilation.graph.getNodes()) {
+            if (node instanceof FrameState) {
+                int lockCount = ((FrameState) node).locksSize();
+                if (lockCount > maxLocks) {
+                    maxLocks = lockCount;
+                }
+            }
+        }
         return maxLocks;
     }
 
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Return.java	Tue May 31 13:42:01 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Return.java	Tue May 31 16:53:19 2011 +0200
@@ -72,7 +72,6 @@
     public Return(Value result, Graph graph) {
         super(result == null ? CiKind.Void : result.kind, 0, INPUT_COUNT, SUCCESSOR_COUNT, graph);
         setResult(result);
-        successors().set(SUCCESSOR_END, graph.end());
     }
 
     // for copying
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Unwind.java	Tue May 31 13:42:01 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Unwind.java	Tue May 31 16:53:19 2011 +0200
@@ -34,8 +34,7 @@
     private static final int INPUT_COUNT = 1;
     private static final int INPUT_EXCEPTION = 0;
 
-    private static final int SUCCESSOR_COUNT = 1;
-    private static final int SUCCESSOR_END = 0;
+    private static final int SUCCESSOR_COUNT = 0;
 
     @Override
     protected int inputCount() {
@@ -64,10 +63,9 @@
         return (Value) inputs().set(super.inputCount() + INPUT_EXCEPTION, n);
     }
 
-    public Unwind(Value exception, Node successor, Graph graph) {
+    public Unwind(Value exception, Graph graph) {
         super(CiKind.Object, 0, INPUT_COUNT, SUCCESSOR_COUNT, graph);
         setException(exception);
-        successors().set(SUCCESSOR_END, successor);
     }
 
     @Override
@@ -82,7 +80,7 @@
 
     @Override
     public Node copy(Graph into) {
-        Unwind x = new Unwind(null, null, into);
+        Unwind x = new Unwind(null, into);
         x.setNonNull(isNonNull());
         return x;
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java	Tue May 31 13:42:01 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java	Tue May 31 16:53:19 2011 +0200
@@ -38,6 +38,10 @@
  */
 public final class FrameState extends Value implements FrameStateAccess {
 
+    private static final int INPUT_COUNT = 1;
+
+    private static final int INPUT_OUTER_FRAME_STATE = 0;
+
     protected final int localsSize;
 
     protected final int stackSize;
@@ -56,6 +60,20 @@
         return super.successorCount() + SUCCESSOR_COUNT;
     }
 
+    public Value outerFrameState() {
+        return (Value) inputs().get(super.inputCount() + INPUT_OUTER_FRAME_STATE);
+    }
+
+    public Value setOuterFrameState(Value n) {
+        assert n == null || n.kind == CiKind.Object;
+        return (Value) inputs().set(super.inputCount() + INPUT_OUTER_FRAME_STATE, n);
+    }
+
+    @Override
+    public void setValueAt(int i, Value x) {
+        inputs().set(INPUT_COUNT + i, x);
+    }
+
     /**
      * The bytecode index to which this frame state applies. This will be {@code -1}
      * iff this state is mutable.
@@ -71,27 +89,25 @@
      * @param lockSize number of locks
      */
     public FrameState(int bci, int localsSize, int stackSize, int locksSize, Graph graph) {
-        super(CiKind.Illegal, localsSize + stackSize + locksSize, SUCCESSOR_COUNT, graph);
+        super(CiKind.Illegal, localsSize + stackSize + locksSize + INPUT_COUNT, SUCCESSOR_COUNT, graph);
         this.bci = bci;
         this.localsSize = localsSize;
         this.stackSize = stackSize;
         this.locksSize = locksSize;
         C1XMetrics.FrameStatesCreated++;
         C1XMetrics.FrameStateValuesCreated += localsSize + stackSize + locksSize;
-        //Exception e = new Exception();
-        //e.printStackTrace();
     }
 
     FrameState(int bci, Value[] locals, Value[] stack, int stackSize, ArrayList<Value> locks, Graph graph) {
         this(bci, locals.length, stackSize, locks.size(), graph);
         for (int i = 0; i < locals.length; i++) {
-            inputs().set(i, locals[i]);
+            setValueAt(i, locals[i]);
         }
         for (int i = 0; i < stackSize; i++) {
-            inputs().set(localsSize + i, stack[i]);
+            setValueAt(localsSize + i, stack[i]);
         }
         for (int i = 0; i < locks.size(); i++) {
-            inputs().set(locals.length + stackSize + i, locks.get(i));
+            setValueAt(locals.length + stackSize + i, locks.get(i));
         }
     }
 
@@ -111,11 +127,12 @@
     public FrameState duplicateWithEmptyStack(int bci) {
         FrameState other = new FrameState(bci, localsSize, 0, locksSize(), graph());
         for (int i = 0; i < localsSize; i++) {
-            other.inputs().set(i, localAt(i));
+            other.setValueAt(i, localAt(i));
         }
         for (int i = 0; i < locksSize; i++) {
-            other.inputs().set(localsSize + i, lockAt(i));
+            other.setValueAt(localsSize + i, lockAt(i));
         }
+        other.setOuterFrameState(outerFrameState());
         return other;
     }
 
@@ -129,18 +146,19 @@
         int pushSlots = pushedValues.length;
         FrameState other = new FrameState(bci, localsSize, stackSize - popSlots + pushSlots, locksSize(), graph());
         for (int i = 0; i < localsSize; i++) {
-            other.inputs().set(i, localAt(i));
+            other.setValueAt(i, localAt(i));
         }
         for (int i = 0; i < stackSize - popSlots; i++) {
-            other.inputs().set(localsSize + i, stackAt(i));
+            other.setValueAt(localsSize + i, stackAt(i));
         }
         int slot = localsSize + stackSize - popSlots;
         for (int i = 0; i < pushSlots; i++) {
-            other.inputs().set(slot++, pushedValues[i]);
+            other.setValueAt(slot++, pushedValues[i]);
         }
         for (int i = 0; i < locksSize; i++) {
-            other.inputs().set(localsSize + other.stackSize + i, lockAt(i));
+            other.setValueAt(localsSize + other.stackSize + i, lockAt(i));
         }
+        other.setOuterFrameState(outerFrameState());
         return other;
     }
 
@@ -160,6 +178,9 @@
                 return false;
             }
         }
+        if (other.outerFrameState() != outerFrameState()) {
+            return false;
+        }
         return true;
     }
 
@@ -194,7 +215,7 @@
         // note that for double word locals, the high slot should already be null
         // unless the local is actually dead and the high slot is being reused;
         // in either case, it is not necessary to null the high slot
-        inputs().set(i, null);
+        setValueAt(i, null);
     }
 
     /**
@@ -207,16 +228,16 @@
     public void storeLocal(int i, Value x) {
         assert i < localsSize : "local variable index out of range: " + i;
         invalidateLocal(i);
-        inputs().set(i, x);
+        setValueAt(i, x);
         if (isDoubleWord(x)) {
             // (tw) if this was a double word then kill i+1
-            inputs().set(i + 1, null);
+            setValueAt(i + 1, null);
         }
         if (i > 0) {
             // if there was a double word at i - 1, then kill it
             Value p = localAt(i - 1);
             if (isDoubleWord(p)) {
-                inputs().set(i - 1, null);
+                setValueAt(i - 1, null);
             }
         }
     }
@@ -229,7 +250,7 @@
      */
     public Value localAt(int i) {
         assert i < localsSize : "local variable index out of range: " + i;
-        return (Value) inputs().get(i);
+        return valueAt(i);
     }
 
     /**
@@ -240,7 +261,7 @@
      */
     public Value stackAt(int i) {
         assert i >= 0 && i < (localsSize + stackSize);
-        return (Value) inputs().get(localsSize + i);
+        return valueAt(localsSize + i);
     }
 
     /**
@@ -250,7 +271,7 @@
      */
     public Value lockAt(int i) {
         assert i >= 0;
-        return (Value) inputs().get(localsSize + stackSize + i);
+        return valueAt(localsSize + stackSize + i);
     }
 
     /**
@@ -268,7 +289,7 @@
                 }
             }
             Phi phi = new Phi(p.kind, block, graph());
-            inputs().set(localsSize + i, phi);
+            setValueAt(localsSize + i, phi);
             return phi;
         }
         return null;
@@ -303,8 +324,8 @@
      * @return the value at index {@code i} which may be {@code null}
      */
     public Value valueAt(int i) {
-        assert i < (localsSize + stackSize);
-        return (Value) inputs().get(i);
+        assert i < (localsSize + stackSize + locksSize);
+        return (Value) inputs().get(INPUT_COUNT + i);
     }
 
     /**
@@ -341,7 +362,7 @@
                                 phi.makeDead();
                             }
                         }
-                        inputs().set(i, null);
+                        setValueAt(i, null);
                         continue;
                     }
                     Phi phi = null;
@@ -484,11 +505,6 @@
     }
 
     @Override
-    public void setValueAt(int j, Value v) {
-        inputs().set(j, v);
-    }
-
-    @Override
     public Node copy(Graph into) {
         FrameState x = new FrameState(bci, localsSize, stackSize, locksSize, into);
         x.setNonNull(isNonNull());
--- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateAccess.java	Tue May 31 13:42:01 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateAccess.java	Tue May 31 16:53:19 2011 +0200
@@ -46,4 +46,6 @@
 
     void setValueAt(int j, Value v);
 
+    Value outerFrameState();
+
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java	Tue May 31 13:42:01 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java	Tue May 31 16:53:19 2011 +0200
@@ -102,7 +102,9 @@
 
     @Override
     public FrameState duplicateWithEmptyStack(int bci) {
-        return new FrameState(bci, locals, new Value[0], 0, locks, graph);
+        FrameState frameState = new FrameState(bci, locals, new Value[0], 0, locks, graph);
+        frameState.setOuterFrameState(outerFrameState());
+        return frameState;
     }
 
     /**
@@ -361,7 +363,6 @@
      */
     public void lock(IR ir, Value obj, int totalNumberOfLocks) {
         locks.add(obj);
-        ir.updateMaxLocks(totalNumberOfLocks);
     }
 
     /**
@@ -496,4 +497,8 @@
         }
     }
 
+    @Override
+    public Value outerFrameState() {
+        return null;
+    }
 }
--- a/graal/GraalGraph/src/com/oracle/graal/graph/EndNode.java	Tue May 31 13:42:01 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * 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.oracle.graal.graph;
-
-public class EndNode extends Node {
-
-    private static final int INPUT_COUNT = 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;
-    }
-
-    EndNode(Graph graph) {
-        super(INPUT_COUNT, SUCCESSOR_COUNT, graph);
-    }
-
-    @Override
-    public Node replace(Node other) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void delete() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Node copy(Graph into) {
-        throw new UnsupportedOperationException();
-    }
-}
--- a/graal/GraalGraph/src/com/oracle/graal/graph/Graph.java	Tue May 31 13:42:01 2011 +0200
+++ b/graal/GraalGraph/src/com/oracle/graal/graph/Graph.java	Tue May 31 16:53:19 2011 +0200
@@ -33,13 +33,11 @@
 
     private final ArrayList<Node> nodes;
     private final StartNode start;
-    private final EndNode end;
     int nextId;
 
     public Graph() {
         nodes = new ArrayList<Node>();
         start = new StartNode(this);
-        end = new EndNode(this);
     }
 
     public Collection<Node> getNodes() {
@@ -60,10 +58,6 @@
         return start;
     }
 
-    public EndNode end() {
-        return end;
-    }
-
     public NodeBitMap createNodeBitMap() {
         return new NodeBitMap(this);
     }