changeset 2611:bd235cb4375a

FrameState cleanup: split into FrameStateBuilder and fixed-size FrameState, removed MutableFrameState
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 06 May 2011 17:08:00 +0200
parents 39aa89baa165
children 32461558c98f
files graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java graal/GraalCompiler/src/com/sun/c1x/debug/BlockPrinter.java graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java graal/GraalCompiler/src/com/sun/c1x/ir/BlockBegin.java graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java graal/GraalCompiler/src/com/sun/c1x/value/ImmutableFrameState.java graal/GraalCompiler/src/com/sun/c1x/value/MutableFrameState.java graal/GraalCompiler/src/com/sun/c1x/value/ValueUtil.java runtests.sh
diffstat 10 files changed, 734 insertions(+), 709 deletions(-) [+]
line wrap: on
line diff
--- a/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java	Fri May 06 13:03:33 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java	Fri May 06 17:08:00 2011 +0200
@@ -94,7 +94,7 @@
         this.method = method;
         this.stats = stats == null ? new CiStatistics() : stats;
         this.registerConfig = method == null ? compiler.globalStubRegisterConfig : runtime.getRegisterConfig(method);
-        this.placeholderState = method != null && method.minimalDebugInfo() ? new MutableFrameState(0, 0, 0) : null;
+        this.placeholderState = method != null && method.minimalDebugInfo() ? new FrameState(0, 0, 0, 0) : null;
 
         if (compiler.isObserved()) {
             compiler.fireCompilationStarted(new CompilationEvent(this));
--- a/graal/GraalCompiler/src/com/sun/c1x/debug/BlockPrinter.java	Fri May 06 13:03:33 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/debug/BlockPrinter.java	Fri May 06 17:08:00 2011 +0200
@@ -67,7 +67,7 @@
 
     private static void printFrameState(FrameState newFrameState, LogStream out) {
         int startPosition = out.position();
-        if (newFrameState.stackEmpty()) {
+        if (newFrameState.stackSize() == 0) {
           out.print("empty stack");
         } else {
           out.print("stack [");
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Fri May 06 13:03:33 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Fri May 06 17:08:00 2011 +0200
@@ -81,47 +81,47 @@
         public final int mask = 1 << ordinal();
     }
 
-    final IR ir;
-    final C1XCompilation compilation;
-    final CiStatistics stats;
+    private final IR ir;
+    private final C1XCompilation compilation;
+    private final CiStatistics stats;
 
     /**
      * Map used to implement local value numbering for the current block.
      */
-    final ValueMap localValueMap;
+    private final ValueMap localValueMap;
 
     /**
      * Map used for local load elimination (i.e. within the current block).
      */
-    final MemoryMap memoryMap;
+    private final MemoryMap memoryMap;
 
-    final BytecodeStream stream;           // the bytecode stream
+    private final BytecodeStream stream;           // the bytecode stream
     // bci-to-block mapping
-    BlockMap blockMap;
+    private BlockMap blockMap;
 
     // the constant pool
-    final RiConstantPool constantPool;
+    private final RiConstantPool constantPool;
 
     // the worklist of blocks, managed like a sorted list
-    BlockBegin[] workList;
+    private BlockBegin[] workList;
 
     // the current position in the worklist
-    int workListIndex;
+    private int workListIndex;
 
     /**
      * Mask of {@link Flag} values.
      */
-    int flags;
+    private int flags;
 
     // Exception handler list
-    List<ExceptionHandler> exceptionHandlers;
+    private List<ExceptionHandler> exceptionHandlers;
 
-    BlockBegin curBlock;                   // the current block
-    MutableFrameState curState;            // the current execution state
-    Instruction lastInstr;                 // the last instruction added
-    final LogStream log;
+    private BlockBegin curBlock;                   // the current block
+    private FrameStateBuilder frameState;          // the current execution state
+    private Instruction lastInstr;                 // the last instruction added
+    private final LogStream log;
 
-    boolean skipBlock;                     // skip processing of the rest of this block
+    private boolean skipBlock;                     // skip processing of the rest of this block
     private Value rootMethodSynchronizedObject;
 
     private final Graph graph;
@@ -143,6 +143,7 @@
         stream = new BytecodeStream(compilation.method.code());
         constantPool = compilation.runtime.getConstantPool(compilation.method);
         this.graph = graph;
+        this.frameState = new FrameStateBuilder(compilation.method, graph);
     }
 
     /**
@@ -181,7 +182,7 @@
             flags |= Flag.HasHandler.mask;
         }
 
-        MutableFrameState initialState = stateAtEntry(rootMethod);
+        FrameState initialState = frameState.create(-1);
         startBlock.mergeOrClone(initialState, rootMethod);
         BlockBegin syncHandler = null;
 
@@ -189,7 +190,6 @@
         curBlock = startBlock;
         lastInstr = startBlock;
         lastInstr.appendNext(null, -1);
-        curState = initialState;
 
         if (isSynchronized(rootMethod.accessFlags())) {
             // 4A.1 add a monitor enter to the start block
@@ -228,7 +228,7 @@
         assert curBlock == startBlock;
         Base base = new Base(stdEntry, graph);
         appendWithoutOptimization(base, 0);
-        FrameState stateAfter = curState.immutableCopy(bci());
+        FrameState stateAfter = frameState.create(bci());
         base.setStateAfter(stateAfter);
         startBlock.setEnd(base);
         assert stdEntry.stateBefore() == null;
@@ -252,71 +252,71 @@
     }
 
     private void ipush(Value x) {
-        curState.ipush(x);
+        frameState.ipush(x);
     }
 
     private void lpush(Value x) {
-        curState.lpush(x);
+        frameState.lpush(x);
     }
 
     private void fpush(Value x) {
-        curState.fpush(x);
+        frameState.fpush(x);
     }
 
     private void dpush(Value x) {
-        curState.dpush(x);
+        frameState.dpush(x);
     }
 
     private void apush(Value x) {
-        curState.apush(x);
+        frameState.apush(x);
     }
 
     private void wpush(Value x) {
-        curState.wpush(x);
+        frameState.wpush(x);
     }
 
     private void push(CiKind kind, Value x) {
-        curState.push(kind, x);
+        frameState.push(kind, x);
     }
 
     private void pushReturn(CiKind kind, Value x) {
         if (kind != CiKind.Void) {
-            curState.push(kind.stackKind(), x);
+            frameState.push(kind.stackKind(), x);
         }
     }
 
     private Value ipop() {
-        return curState.ipop();
+        return frameState.ipop();
     }
 
     private Value lpop() {
-        return curState.lpop();
+        return frameState.lpop();
     }
 
     private Value fpop() {
-        return curState.fpop();
+        return frameState.fpop();
     }
 
     private Value dpop() {
-        return curState.dpop();
+        return frameState.dpop();
     }
 
     private Value apop() {
-        return curState.apop();
+        return frameState.apop();
     }
 
     private Value wpop() {
-        return curState.wpop();
+        return frameState.wpop();
     }
 
     private Value pop(CiKind kind) {
-        return curState.pop(kind);
+        return frameState.pop(kind);
     }
 
     private CiKind peekKind() {
-        Value top = curState.stackAt(curState.stackSize() - 1);
+        Value top = frameState.stackAt(frameState.stackSize() - 1);
         if (top == null) {
-            top = curState.stackAt(curState.stackSize() - 2);
+            top = frameState.stackAt(frameState.stackSize() - 2);
             assert top != null;
             assert top.kind.isDoubleWord();
         }
@@ -324,11 +324,11 @@
     }
 
     private void loadLocal(int index, CiKind kind) {
-        push(kind, curState.loadLocal(index));
+        push(kind, frameState.loadLocal(index));
     }
 
     private void storeLocal(CiKind kind, int index) {
-        curState.storeLocal(index, pop(kind));
+        frameState.storeLocal(index, pop(kind));
     }
 
     List<ExceptionHandler> handleException(Instruction x, int bci) {
@@ -380,7 +380,7 @@
         assert entryState == null || curState.locksSize() == entryState.locksSize() : "locks do not match : cur:" + curState.locksSize() + " entry:" + entryState.locksSize();
 
         // exception handler starts with an empty expression stack
-        curState = curState.immutableCopyWithEmptyStack();
+        curState = curState.copyWithEmptyStack();
 
         entry.mergeOrClone(curState, method());
 
@@ -435,7 +435,7 @@
     }
 
     void genLoadIndexed(CiKind kind) {
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         Value index = ipop();
         Value array = apop();
         Value length = null;
@@ -447,7 +447,7 @@
     }
 
     void genStoreIndexed(CiKind kind) {
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         Value value = pop(kind.stackKind());
         Value index = ipop();
         Value array = apop();
@@ -465,76 +465,76 @@
     void stackOp(int opcode) {
         switch (opcode) {
             case POP: {
-                curState.xpop();
+                frameState.xpop();
                 break;
             }
             case POP2: {
-                curState.xpop();
-                curState.xpop();
+                frameState.xpop();
+                frameState.xpop();
                 break;
             }
             case DUP: {
-                Value w = curState.xpop();
-                curState.xpush(w);
-                curState.xpush(w);
+                Value w = frameState.xpop();
+                frameState.xpush(w);
+                frameState.xpush(w);
                 break;
             }
             case DUP_X1: {
-                Value w1 = curState.xpop();
-                Value w2 = curState.xpop();
-                curState.xpush(w1);
-                curState.xpush(w2);
-                curState.xpush(w1);
+                Value w1 = frameState.xpop();
+                Value w2 = frameState.xpop();
+                frameState.xpush(w1);
+                frameState.xpush(w2);
+                frameState.xpush(w1);
                 break;
             }
             case DUP_X2: {
-                Value w1 = curState.xpop();
-                Value w2 = curState.xpop();
-                Value w3 = curState.xpop();
-                curState.xpush(w1);
-                curState.xpush(w3);
-                curState.xpush(w2);
-                curState.xpush(w1);
+                Value w1 = frameState.xpop();
+                Value w2 = frameState.xpop();
+                Value w3 = frameState.xpop();
+                frameState.xpush(w1);
+                frameState.xpush(w3);
+                frameState.xpush(w2);
+                frameState.xpush(w1);
                 break;
             }
             case DUP2: {
-                Value w1 = curState.xpop();
-                Value w2 = curState.xpop();
-                curState.xpush(w2);
-                curState.xpush(w1);
-                curState.xpush(w2);
-                curState.xpush(w1);
+                Value w1 = frameState.xpop();
+                Value w2 = frameState.xpop();
+                frameState.xpush(w2);
+                frameState.xpush(w1);
+                frameState.xpush(w2);
+                frameState.xpush(w1);
                 break;
             }
             case DUP2_X1: {
-                Value w1 = curState.xpop();
-                Value w2 = curState.xpop();
-                Value w3 = curState.xpop();
-                curState.xpush(w2);
-                curState.xpush(w1);
-                curState.xpush(w3);
-                curState.xpush(w2);
-                curState.xpush(w1);
+                Value w1 = frameState.xpop();
+                Value w2 = frameState.xpop();
+                Value w3 = frameState.xpop();
+                frameState.xpush(w2);
+                frameState.xpush(w1);
+                frameState.xpush(w3);
+                frameState.xpush(w2);
+                frameState.xpush(w1);
                 break;
             }
             case DUP2_X2: {
-                Value w1 = curState.xpop();
-                Value w2 = curState.xpop();
-                Value w3 = curState.xpop();
-                Value w4 = curState.xpop();
-                curState.xpush(w2);
-                curState.xpush(w1);
-                curState.xpush(w4);
-                curState.xpush(w3);
-                curState.xpush(w2);
-                curState.xpush(w1);
+                Value w1 = frameState.xpop();
+                Value w2 = frameState.xpop();
+                Value w3 = frameState.xpop();
+                Value w4 = frameState.xpop();
+                frameState.xpush(w2);
+                frameState.xpush(w1);
+                frameState.xpush(w4);
+                frameState.xpush(w3);
+                frameState.xpush(w2);
+                frameState.xpush(w1);
                 break;
             }
             case SWAP: {
-                Value w1 = curState.xpop();
-                Value w2 = curState.xpop();
-                curState.xpush(w1);
-                curState.xpush(w2);
+                Value w1 = frameState.xpop();
+                Value w2 = frameState.xpop();
+                frameState.xpush(w1);
+                frameState.xpush(w2);
                 break;
             }
             default:
@@ -592,9 +592,9 @@
     void genIncrement() {
         int index = stream().readLocalIndex();
         int delta = stream().readIncrement();
-        Value x = curState.localAt(index);
+        Value x = frameState.localAt(index);
         Value y = append(Constant.forInt(delta, graph));
-        curState.storeLocal(index, append(new ArithmeticOp(IADD, CiKind.Int, x, y, isStrict(method().accessFlags()), null, graph)));
+        frameState.storeLocal(index, append(new ArithmeticOp(IADD, CiKind.Int, x, y, isStrict(method().accessFlags()), null, graph)));
     }
 
     void genGoto(int fromBCI, int toBCI) {
@@ -612,27 +612,27 @@
 
     void genIfZero(Condition cond) {
         Value y = appendConstant(CiConstant.INT_0);
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         Value x = ipop();
         ifNode(x, cond, y, stateBefore);
     }
 
     void genIfNull(Condition cond) {
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         Value y = appendConstant(CiConstant.NULL_OBJECT);
         Value x = apop();
         ifNode(x, cond, y, stateBefore);
     }
 
     void genIfSame(CiKind kind, Condition cond) {
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         Value y = pop(kind);
         Value x = pop(kind);
         ifNode(x, cond, y, stateBefore);
     }
 
     void genThrow(int bci) {
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         Throw t = new Throw(apop(), stateBefore, !noSafepoints(), graph);
         appendWithoutOptimization(t, bci);
     }
@@ -665,7 +665,7 @@
     }
 
     void genNewInstance(int cpi) {
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         RiType type = constantPool().lookupType(cpi, NEW);
         NewInstance n = new NewInstance(type, cpi, constantPool(), stateBefore, graph);
         if (memoryMap != null) {
@@ -675,7 +675,7 @@
     }
 
     void genNewTypeArray(int typeCode) {
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         CiKind kind = CiKind.fromArrayTypeCode(typeCode);
         RiType elementType = compilation.runtime.asRiType(kind);
         apush(append(new NewTypeArray(ipop(), elementType, stateBefore, graph)));
@@ -683,14 +683,14 @@
 
     void genNewObjectArray(int cpi) {
         RiType type = constantPool().lookupType(cpi, ANEWARRAY);
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         NewArray n = new NewObjectArray(type, ipop(), stateBefore, graph);
         apush(append(n));
     }
 
     void genNewMultiArray(int cpi) {
         RiType type = constantPool().lookupType(cpi, MULTIANEWARRAY);
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         int rank = stream().readUByte(bci() + 3);
         Value[] dims = new Value[rank];
         for (int i = rank - 1; i >= 0; i--) {
@@ -702,14 +702,14 @@
 
     void genGetField(int cpi, RiField field) {
         // Must copy the state here, because the field holder must still be on the stack.
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         LoadField load = new LoadField(apop(), field, stateBefore, graph);
         appendOptimizedLoadField(field.kind(), load);
     }
 
     void genPutField(int cpi, RiField field) {
         // Must copy the state here, because the field holder must still be on the stack.
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         Value value = pop(field.kind().stackKind());
         appendOptimizedStoreField(new StoreField(apop(), field, value, stateBefore, graph));
     }
@@ -787,25 +787,25 @@
             genResolveClass(RiType.Representation.StaticFields, holder, isInitialized, cpi);
         }
 
-        Value[] args = curState.popArguments(target.signature().argumentSlots(false));
+        Value[] args = frameState.popArguments(target.signature().argumentSlots(false));
         appendInvoke(INVOKESTATIC, target, args, cpi, constantPool);
     }
 
     void genInvokeInterface(RiMethod target, int cpi, RiConstantPool constantPool) {
-        Value[] args = curState.popArguments(target.signature().argumentSlots(true));
+        Value[] args = frameState.popArguments(target.signature().argumentSlots(true));
 
         genInvokeIndirect(INVOKEINTERFACE, target, args, cpi, constantPool);
 
     }
 
     void genInvokeVirtual(RiMethod target, int cpi, RiConstantPool constantPool) {
-        Value[] args = curState.popArguments(target.signature().argumentSlots(true));
+        Value[] args = frameState.popArguments(target.signature().argumentSlots(true));
         genInvokeIndirect(INVOKEVIRTUAL, target, args, cpi, constantPool);
 
     }
 
     void genInvokeSpecial(RiMethod target, RiType knownHolder, int cpi, RiConstantPool constantPool) {
-        Value[] args = curState.popArguments(target.signature().argumentSlots(true));
+        Value[] args = frameState.popArguments(target.signature().argumentSlots(true));
         invokeDirect(target, args, knownHolder, cpi, constantPool);
 
     }
@@ -967,7 +967,7 @@
     }
 
     void callRegisterFinalizer() {
-        Value receiver = curState.loadLocal(0);
+        Value receiver = frameState.loadLocal(0);
         RiType declaredType = receiver.declaredType();
         RiType receiverType = declaredType;
         RiType exactType = receiver.exactType();
@@ -1000,7 +1000,7 @@
 
         if (needsCheck) {
             // append a call to the finalizer registration
-            append(new RegisterFinalizer(curState.loadLocal(0), curState.immutableCopy(bci()), graph));
+            append(new RegisterFinalizer(frameState.loadLocal(0), frameState.create(bci()), graph));
             C1XMetrics.InlinedFinalizerChecks++;
         }
     }
@@ -1010,18 +1010,18 @@
             callRegisterFinalizer();
         }
 
-        curState.truncateStack(0);
+        frameState.clearStack();
         if (Modifier.isSynchronized(method().accessFlags())) {
-            FrameState stateBefore = curState.immutableCopy(bci());
+            FrameState stateBefore = frameState.create(bci());
             // unlock before exiting the method
-            int lockNumber = curState.locksSize() - 1;
+            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, stateBefore, graph));
-            curState.unlock();
+            frameState.unlock();
         }
         append(new Return(x, !noSafepoints(), graph));
     }
@@ -1030,7 +1030,7 @@
      * Gets the number of locks held.
      */
     private int locksSize() {
-        return curState.locksSize();
+        return frameState.locksSize();
     }
 
     void genMonitorEnter(Value x, int bci) {
@@ -1042,13 +1042,13 @@
         }
         MonitorEnter monitorEnter = new MonitorEnter(x, lockAddress, lockNumber, null, graph);
         appendWithoutOptimization(monitorEnter, bci);
-        curState.lock(ir, x, lockNumber + 1);
-        monitorEnter.setStateAfter(curState.immutableCopy(bci));
+        frameState.lock(ir, x, lockNumber + 1);
+        monitorEnter.setStateAfter(frameState.create(bci));
         killMemoryMap(); // prevent any optimizations across synchronization
     }
 
     void genMonitorExit(Value x, int bci) {
-        int lockNumber = curState.locksSize() - 1;
+        int lockNumber = frameState.locksSize() - 1;
         if (lockNumber < 0) {
             throw new CiBailout("monitor stack underflow");
         }
@@ -1058,7 +1058,7 @@
             append(lockAddress);
         }
         appendWithoutOptimization(new MonitorExit(x, lockAddress, lockNumber, null, graph), bci);
-        curState.unlock();
+        frameState.unlock();
         killMemoryMap(); // prevent any optimizations across synchronization
     }
 
@@ -1086,7 +1086,7 @@
         isBackwards |= offset < 0; // if the default successor is backwards
         list.add(blockAt(bci + offset));
         boolean isSafepoint = isBackwards && !noSafepoints();
-        FrameState stateBefore = isSafepoint ? curState.immutableCopy(bci()) : null;
+        FrameState stateBefore = isSafepoint ? frameState.create(bci()) : null;
         append(new TableSwitch(ipop(), list, ts.lowKey(), stateBefore, isSafepoint, graph));
     }
 
@@ -1108,7 +1108,7 @@
         isBackwards |= offset < 0; // if the default successor is backwards
         list.add(blockAt(bci + offset));
         boolean isSafepoint = isBackwards && !noSafepoints();
-        FrameState stateBefore = isSafepoint ? curState.immutableCopy(bci()) : null;
+        FrameState stateBefore = isSafepoint ? frameState.create(bci()) : null;
         append(new LookupSwitch(ipop(), list, keys, stateBefore, isSafepoint, graph));
     }
 
@@ -1186,7 +1186,7 @@
         if (x instanceof StateSplit) {
             StateSplit stateSplit = (StateSplit) x;
             if (stateSplit.stateBefore() == null) {
-                stateSplit.setStateBefore(curState.immutableCopy(bci));
+                stateSplit.setStateBefore(frameState.create(bci));
             }
         }
 
@@ -1212,33 +1212,6 @@
         return result;
     }
 
-    MutableFrameState stateAtEntry(RiMethod method) {
-        MutableFrameState state = new MutableFrameState(-1, method.maxLocals(), method.maxStackSize());
-        int index = 0;
-        if (!isStatic(method.accessFlags())) {
-            // add the receiver and assume it is non null
-            Local local = new Local(method.holder().kind(), index, graph);
-            local.setFlag(Value.Flag.NonNull, true);
-            local.setDeclaredType(method.holder());
-            state.storeLocal(index, local);
-            index = 1;
-        }
-        RiSignature sig = method.signature();
-        int max = sig.argumentCount(false);
-        RiType accessingClass = method.holder();
-        for (int i = 0; i < max; i++) {
-            RiType type = sig.argumentTypeAt(i, accessingClass);
-            CiKind kind = type.kind().stackKind();
-            Local local = new Local(kind, index, graph);
-            if (type.isResolved()) {
-                local.setDeclaredType(type);
-            }
-            state.storeLocal(index, local);
-            index += kind.sizeInSlots();
-        }
-        return state;
-    }
-
     private Value synchronizedObject(FrameState curState2, RiMethod target) {
         if (isStatic(target.accessFlags())) {
             Constant classConstant = new Constant(target.holder().getEncoding(Representation.JavaClass), graph);
@@ -1250,7 +1223,7 @@
 
     private void fillSyncHandler(Value lock, BlockBegin syncHandler) {
         BlockBegin origBlock = curBlock;
-        MutableFrameState origState = curState;
+        FrameState origState = frameState.create(-1);
         Instruction origLast = lastInstr;
 
         lastInstr = curBlock = syncHandler;
@@ -1258,13 +1231,13 @@
             // go forward to the end of the block
             lastInstr = lastInstr.next();
         }
-        curState = syncHandler.stateBefore().copy();
+        frameState.initializeFrom(syncHandler.stateBefore());
 
         int bci = Instruction.SYNCHRONIZATION_ENTRY_BCI;
-        Value exception = appendWithoutOptimization(new ExceptionObject(curState.immutableCopy(bci), graph), bci);
+        Value exception = appendWithoutOptimization(new ExceptionObject(frameState.create(bci), graph), bci);
 
         assert lock != null;
-        assert curState.locksSize() > 0 && curState.lockAt(locksSize() - 1) == lock;
+        assert frameState.locksSize() > 0 && frameState.lockAt(locksSize() - 1) == lock;
         if (lock instanceof Instruction) {
             Instruction l = (Instruction) lock;
             if (!l.isAppended()) {
@@ -1278,10 +1251,10 @@
         genThrow(bci);
         BlockEnd end = (BlockEnd) lastInstr;
         curBlock.setEnd(end);
-        end.setStateAfter(curState.immutableCopy(bci()));
+        end.setStateAfter(frameState.create(bci()));
 
         curBlock = origBlock;
-        curState = origState;
+        frameState.initializeFrom(origState);
         lastInstr = origLast;
     }
 
@@ -1293,7 +1266,7 @@
                 // now parse the block
                 killMemoryMap();
                 curBlock = b;
-                curState = b.stateBefore().copy();
+                frameState.initializeFrom(b.stateBefore());
                 lastInstr = b;
                 b.appendNext(null, -1);
 
@@ -1304,7 +1277,7 @@
 
     private BlockEnd iterateBytecodesForBlock(int bci, boolean inliningIntoCurrentBlock) {
         skipBlock = false;
-        assert curState != null;
+        assert frameState != null;
         stream.setBCI(bci);
 
         BlockBegin block = curBlock;
@@ -1335,7 +1308,7 @@
 
             // push an exception object onto the stack if we are parsing an exception handler
             if (pushException) {
-                FrameState stateBefore = curState.immutableCopy(bci());
+                FrameState stateBefore = frameState.create(bci());
                 apush(append(new ExceptionObject(stateBefore, graph)));
                 pushException = false;
             }
@@ -1363,13 +1336,13 @@
 
         // if the method terminates, we don't need the stack anymore
         if (end instanceof Return || end instanceof Throw) {
-            curState.clearStack();
+            frameState.clearStack();
         }
 
         // connect to begin and set state
         // NOTE that inlining may have changed the block we are parsing
         assert end != null : "end should exist after iterating over bytecodes";
-        end.setStateAfter(curState.immutableCopy(bci()));
+        end.setStateAfter(frameState.create(bci()));
         curBlock.setEnd(end);
         // propagate the state
         for (BlockBegin succ : end.blockSuccessors()) {
@@ -1382,17 +1355,17 @@
 
     private void traceState() {
         if (C1XOptions.TraceBytecodeParserLevel >= TRACELEVEL_STATE && !TTY.isSuppressed()) {
-            log.println(String.format("|   state [nr locals = %d, stack depth = %d, method = %s]", curState.localsSize(), curState.stackSize(), method()));
-            for (int i = 0; i < curState.localsSize(); ++i) {
-                Value value = curState.localAt(i);
+            log.println(String.format("|   state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method()));
+            for (int i = 0; i < frameState.localsSize(); ++i) {
+                Value value = frameState.localAt(i);
                 log.println(String.format("|   local[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value));
             }
-            for (int i = 0; i < curState.stackSize(); ++i) {
-                Value value = curState.stackAt(i);
+            for (int i = 0; i < frameState.stackSize(); ++i) {
+                Value value = frameState.stackAt(i);
                 log.println(String.format("|   stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value));
             }
-            for (int i = 0; i < curState.locksSize(); ++i) {
-                Value value = curState.lockAt(i);
+            for (int i = 0; i < frameState.locksSize(); ++i) {
+                Value value = frameState.lockAt(i);
                 log.println(String.format("|   lock[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value));
             }
         }
@@ -1503,12 +1476,12 @@
             case ISUB           : // fall through
             case IMUL           : genArithmeticOp(CiKind.Int, opcode); break;
             case IDIV           : // fall through
-            case IREM           : genArithmeticOp(CiKind.Int, opcode, curState.immutableCopy(bci())); break;
+            case IREM           : genArithmeticOp(CiKind.Int, opcode, frameState.create(bci())); break;
             case LADD           : // fall through
             case LSUB           : // fall through
             case LMUL           : genArithmeticOp(CiKind.Long, opcode); break;
             case LDIV           : // fall through
-            case LREM           : genArithmeticOp(CiKind.Long, opcode, curState.immutableCopy(bci())); break;
+            case LREM           : genArithmeticOp(CiKind.Long, opcode, frameState.create(bci())); break;
             case FADD           : // fall through
             case FSUB           : // fall through
             case FMUL           : // fall through
@@ -1629,7 +1602,7 @@
     }
 
     private void genArrayLength() {
-        FrameState stateBefore = curState.immutableCopy(bci());
+        FrameState stateBefore = frameState.create(bci());
         ipush(append(new ArrayLength(apop(), stateBefore, graph)));
     }
 
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/BlockBegin.java	Fri May 06 13:03:33 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/BlockBegin.java	Fri May 06 17:08:00 2011 +0200
@@ -410,7 +410,7 @@
             }
 
             // copy state because it is modified
-            newState = newState.immutableCopy();
+            newState = newState.copy();
 
             if (C1XOptions.UseStackMapTableLiveness) {
                 // if a liveness map is available, use it to invalidate dead locals
--- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java	Fri May 06 13:03:33 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java	Fri May 06 17:08:00 2011 +0200
@@ -26,16 +26,16 @@
 
 import com.oracle.graal.graph.*;
 import com.sun.c1x.*;
-import com.sun.c1x.graph.*;
 import com.sun.c1x.ir.*;
-import com.sun.c1x.util.*;
 import com.sun.cri.ci.*;
 
+import static com.sun.c1x.value.ValueUtil.*;
+
 /**
  * The {@code FrameState} class encapsulates the frame state (i.e. local variables and
  * operand stack) at a particular point in the abstract interpretation.
  */
-public abstract class FrameState {
+public class FrameState {
 
     /**
      * The operand stack and local variables.
@@ -51,15 +51,11 @@
     protected final Value[] values;
 
     /**
-     * The depth of the operand stack.
-     * The top of stack value is in {@code values[maxLocals + stackIndex]}.
-     */
-    protected int stackIndex;
-
-    /**
      * The number of local variables.
      */
-    protected final int maxLocals;
+    protected final int localsSize;
+
+    protected final int stackSize;
 
     /**
      * The bytecode index to which this frame state applies. This will be {@code -1}
@@ -68,117 +64,64 @@
     public final int bci;
 
     /**
-     * The list of locks held by this frame state.
-     * This does not include locks held by parent frames.
-     */
-    protected ArrayList<Value> locks;
-
-    /**
-     * The number of minimum stack slots required for doing IR wrangling during
-     * {@linkplain GraphBuilder bytecode parsing}. While this may hide stack
-     * overflow issues in the original bytecode, the assumption is that such
-     * issues must be caught by the verifier.
-     */
-    private static final int MINIMUM_STACK_SLOTS = 1;
-
-    /**
      * Creates a {@code FrameState} for the given scope and maximum number of stack and local variables.
      *
-     * @param irScope the inlining context of the method
      * @param bci the bytecode index of the frame state
-     * @param maxLocals maximum number of locals
-     * @param maxStack maximum size of the stack
+     * @param localsSize number of locals
+     * @param stackSize size of the stack
+     * @param lockSize number of locks
      */
-    public FrameState(int bci, int maxLocals, int maxStack) {
+    public FrameState(int bci, int localsSize, int stackSize, int lockSize) {
         this.bci = bci;
-        this.values = new Value[maxLocals + Math.max(maxStack, MINIMUM_STACK_SLOTS)];
-        this.maxLocals = maxLocals;
+        this.values = new Value[localsSize + stackSize + lockSize];
+        this.localsSize = localsSize;
+        this.stackSize = stackSize;
         C1XMetrics.FrameStatesCreated++;
         C1XMetrics.FrameStateValuesCreated += this.values.length;
     }
 
-    /**
-     * Copies the contents of this frame state so that further updates to either stack aren't reflected in the other.
-     * @param bci the bytecode index of the copy
-     * @param withLocals indicates whether to copy the local state
-     * @param withStack indicates whether to copy the stack state
-     * @param withLocks indicates whether to copy the lock state
-     *
-     * @return a new frame state with the specified components
-     */
-    public FrameState immutableCopy(int bci, boolean withLocals, boolean withStack, boolean withLocks) {
-        final ImmutableFrameState other = new ImmutableFrameState(bci, localsSize(), maxStackSize());
-        if (withLocals && withStack) {
-            // fast path: use array copy
-            System.arraycopy(values, 0, other.values, 0, valuesSize());
-            other.stackIndex = stackIndex;
-        } else {
-            if (withLocals) {
-                System.arraycopy(values, 0, other.values, 0, maxLocals);
-            }
-            if (withStack) {
-                System.arraycopy(values, maxLocals, other.values, other.maxLocals, stackIndex);
-                other.stackIndex = stackIndex;
-            }
+    FrameState(int bci, Value[] locals, Value[] stack, int stackSize, ArrayList<Value> locks) {
+        this(bci, locals.length, stackSize, locks.size());
+        System.arraycopy(locals, 0, values, 0, locals.length);
+        System.arraycopy(stack, 0, values, locals.length, stackSize);
+        for (int i = 0; i < locks.size(); i++) {
+            values[locals.length + stackSize + i] = locks.get(i);
         }
-        if (withLocks) {
-            if (locks != null) {
-                other.locks = new ArrayList<Value>(locks);
-            }
-        }
-        return other;
     }
 
     /**
-     * Gets a mutable copy ({@link MutableFrameState}) of this frame state.
+     * Gets a immutable copy ({@link FrameState}) of this frame state.
      */
-    public MutableFrameState copy() {
-        final MutableFrameState other = new MutableFrameState(bci, localsSize(), maxStackSize());
-        System.arraycopy(values, 0, other.values, 0, valuesSize());
-        other.stackIndex = stackIndex;
-        if (locks != null) {
-            other.locks = new ArrayList<Value>(locks);
-        }
+    public FrameState copy() {
+        FrameState other = new FrameState(bci, localsSize, stackSize, locksSize());
+        System.arraycopy(values, 0, other.values, 0, values.length);
         return other;
     }
 
     /**
-     * Gets a immutable copy ({@link MutableFrameState}) of this frame state.
-     */
-    public FrameState immutableCopy() {
-        return immutableCopy(bci, true, true, true);
-    }
-
-    /**
      * Gets an immutable copy of this frame state but without the stack.
      */
-    public FrameState immutableCopyWithEmptyStack() {
-        return immutableCopy(bci, true, false, true);
-    }
-
-    /**
-     * Gets an immutable copy of this frame state but without the frame info.
-     */
-    public FrameState immutableCopyCodePosOnly() {
-        return immutableCopy(bci, false, false, false);
+    public FrameState copyWithEmptyStack() {
+        FrameState other = new FrameState(bci, localsSize, 0, locksSize());
+        System.arraycopy(values, 0, other.values, 0, localsSize);
+        System.arraycopy(values, localsSize + stackSize, other.values, localsSize, locksSize());
+        return other;
     }
 
     public boolean isCompatibleWith(FrameState other) {
         if (stackSize() != other.stackSize() || localsSize() != other.localsSize() || locksSize() != other.locksSize()) {
             return false;
         }
-        for (int i = 0; i < stackIndex; i++) {
+        for (int i = 0; i < stackSize(); i++) {
             Value x = stackAt(i);
             Value y = other.stackAt(i);
             if (x != y && typeMismatch(x, y)) {
                 return false;
             }
         }
-        if (locks != null) {
-            for (int i = 0; i < locks.size(); i++) {
-                if (lockAt(i) != other.lockAt(i)) {
-                    return false;
-                }
+        for (int i = 0; i < locksSize(); i++) {
+            if (lockAt(i) != other.lockAt(i)) {
+                return false;
             }
         }
         return true;
@@ -190,37 +133,21 @@
      * @return the size of the local variables
      */
     public int localsSize() {
-        return maxLocals;
-    }
-
-    /**
-     * Gets number of locks held by this frame state.
-     */
-    public int locksSize() {
-        return locks == null ? 0 : locks.size();
+        return localsSize;
     }
 
     /**
      * Gets the current size (height) of the stack.
      */
     public int stackSize() {
-        return stackIndex;
+        return stackSize;
     }
 
     /**
-     * Gets the maximum size (height) of the stack.
-]     */
-    public int maxStackSize() {
-        return values.length - maxLocals;
-    }
-
-    /**
-     * Checks whether the stack is empty.
-     *
-     * @return {@code true} the stack is currently empty
+     * Gets number of locks held by this frame state.
      */
-    public boolean stackEmpty() {
-        return stackIndex == 0;
+    public int locksSize() {
+        return values.length - localsSize - stackSize;
     }
 
     /**
@@ -237,24 +164,6 @@
     }
 
     /**
-     * Loads the local variable at the specified index.
-     *
-     * @param i the index of the local variable to load
-     * @return the instruction that produced the specified local
-     */
-    public Value loadLocal(int i) {
-        assert i < maxLocals : "local variable index out of range: " + i;
-        Value x = values[i];
-        if (x != null) {
-            if (x.isIllegal()) {
-                return null;
-            }
-            assert x.kind.isSingleWord() || values[i + 1] == null || values[i + 1] instanceof Phi;
-        }
-        return x;
-    }
-
-    /**
      * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word},
      * then the next local variable index is also overwritten.
      *
@@ -262,7 +171,7 @@
      * @param x the instruction which produces the value for the local
      */
     public void storeLocal(int i, Value x) {
-        assert i < maxLocals : "local variable index out of range: " + i;
+        assert i < localsSize : "local variable index out of range: " + i;
         invalidateLocal(i);
         values[i] = x;
         if (isDoubleWord(x)) {
@@ -279,25 +188,25 @@
     }
 
     /**
+     * Gets the value in the local variables at the specified index.
+     *
+     * @param i the index into the locals
+     * @return the instruction that produced the value for the specified local
+     */
+    public final Value localAt(int i) {
+        assert i < localsSize : "local variable index out of range: " + i;
+        return values[i];
+    }
+
+    /**
      * Get the value on the stack at the specified stack index.
      *
      * @param i the index into the stack, with {@code 0} being the bottom of the stack
      * @return the instruction at the specified position in the stack
      */
     public final Value stackAt(int i) {
-        assert i < stackIndex;
-        return values[i + maxLocals];
-    }
-
-    /**
-     * Gets the value in the local variables at the specified index.
-     *
-     * @param i the index into the locals
-     * @return the instruction that produced the value for the specified local
-     */
-    public final Value localAt(int i) {
-        assert i < maxLocals : "local variable index out of range: " + i;
-        return values[i];
+        assert i >= 0 && i < (localsSize + stackSize);
+        return values[localsSize + i];
     }
 
     /**
@@ -306,7 +215,8 @@
      * @return the instruction which produced the object at the specified location in the lock stack
      */
     public final Value lockAt(int i) {
-        return locks.get(i);
+        assert i >= 0;
+        return values[localsSize + stackSize + i];
     }
 
     /**
@@ -324,7 +234,7 @@
                     return;
                 }
             }
-            values[maxLocals + i] = new Phi(p.kind, block, -i - 1, graph);
+            values[localsSize + i] = new Phi(p.kind, block, -i - 1, graph);
         }
     }
 
@@ -356,6 +266,7 @@
      * @return the value at index {@code i} which may be {@code null}
      */
     public final Value valueAt(int i) {
+        assert i < (localsSize + stackSize);
         return values[i];
     }
 
@@ -368,7 +279,7 @@
      * @return the number of local variables in this frame
      */
     public final int valuesSize() {
-        return maxLocals + stackIndex;
+        return localsSize + stackSize;
     }
 
     public void checkPhis(BlockBegin block, FrameState other) {
@@ -395,9 +306,9 @@
     }
 
     private void checkSize(FrameState other) {
-        if (other.stackIndex != stackIndex) {
+        if (other.stackSize() != stackSize()) {
             throw new CiBailout("stack sizes do not match");
-        } else if (other.maxLocals != maxLocals) {
+        } else if (other.localsSize != localsSize) {
             throw new CiBailout("local sizes do not match");
         }
     }
@@ -419,25 +330,18 @@
                         values[i] = null;
                         continue;
                     }
-                    if (i < maxLocals) {
+                    if (i < localsSize) {
                         // this a local
                         setupPhiForLocal(block, i, graph);
                     } else {
                         // this is a stack slot
-                        setupPhiForStack(block, i - maxLocals, graph);
+                        setupPhiForStack(block, i - localsSize, graph);
                     }
                 }
             }
         }
     }
 
-    private static boolean typeMismatch(Value x, Value y) {
-        return y == null || x.kind != y.kind;
-    }
-
-    private static boolean isDoubleWord(Value x) {
-        return x != null && x.kind.isDoubleWord();
-    }
 
     /**
      * The interface implemented by a client of {@link FrameState#forEachPhi(BlockBegin, PhiProcedure)} and
@@ -488,27 +392,10 @@
      * @param closure the closure to apply to each value
      */
     public void valuesDo(ValueClosure closure) {
-        valuesDo(this, closure);
-    }
-
-    /**
-     * Iterates over all the values of a given frame state and its callers, including the stack, locals, and locks.
-     * @param closure the closure to apply to each value
-     */
-    public static void valuesDo(FrameState state, ValueClosure closure) {
-        final int max = state.valuesSize();
-        for (int i = 0; i < max; i++) {
-            if (state.values[i] != null) {
-                Value newValue = closure.apply(state.values[i]);
-                state.values[i] = newValue;
-            }
-        }
-        if (state.locks != null) {
-            for (int i = 0; i < state.locks.size(); i++) {
-                Value instr = state.locks.get(i);
-                if (instr != null) {
-                    state.locks.set(i, closure.apply(instr));
-                }
+        for (int i = 0; i < values.length; i++) {
+            if (values[i] != null) {
+                Value newValue = closure.apply(values[i]);
+                values[i] = newValue;
             }
         }
     }
@@ -539,17 +426,17 @@
     public String toString() {
         StringBuilder sb = new StringBuilder();
         String nl = String.format("%n");
-        sb.append("[bci: ").append(this.bci).append("]").append(nl);
-        for (int i = 0; i < this.localsSize(); ++i) {
-            Value value = this.localAt(i);
+        sb.append("[bci: ").append(bci).append("]").append(nl);
+        for (int i = 0; i < localsSize(); ++i) {
+            Value value = localAt(i);
             sb.append(String.format("  local[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value));
         }
-        for (int i = 0; i < this.stackSize(); ++i) {
-            Value value = this.stackAt(i);
+        for (int i = 0; i < stackSize(); ++i) {
+            Value value = stackAt(i);
             sb.append(String.format("  stack[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value));
         }
-        for (int i = 0; i < this.locksSize(); ++i) {
-            Value value = this.lockAt(i);
+        for (int i = 0; i < locksSize(); ++i) {
+            Value value = lockAt(i);
             sb.append(String.format("  lock[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value));
         }
         return sb.toString();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java	Fri May 06 17:08:00 2011 +0200
@@ -0,0 +1,437 @@
+/*
+ * 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.value;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.sun.c1x.graph.*;
+import com.sun.c1x.ir.*;
+import com.sun.cri.ci.*;
+import com.sun.cri.ri.*;
+
+import static com.sun.c1x.value.ValueUtil.*;
+import static java.lang.reflect.Modifier.*;
+
+
+public class FrameStateBuilder {
+
+    private final Graph graph;
+
+    private final Value[] locals;
+    private final Value[] stack;
+    private final ArrayList<Value> locks;
+
+    private int stackIndex;
+
+    public FrameStateBuilder(RiMethod method, Graph graph) {
+        this.graph = graph;
+        this.locals = new Value[method.maxLocals()];
+        this.stack = new Value[method.maxStackSize()];
+
+        int index = 0;
+        if (!isStatic(method.accessFlags())) {
+            // add the receiver and assume it is non null
+            Local local = new Local(method.holder().kind(), index, graph);
+            local.setFlag(Value.Flag.NonNull, true);
+            local.setDeclaredType(method.holder());
+            storeLocal(index, local);
+            index = 1;
+        }
+        RiSignature sig = method.signature();
+        int max = sig.argumentCount(false);
+        RiType accessingClass = method.holder();
+        for (int i = 0; i < max; i++) {
+            RiType type = sig.argumentTypeAt(i, accessingClass);
+            CiKind kind = type.kind().stackKind();
+            Local local = new Local(kind, index, graph);
+            if (type.isResolved()) {
+                local.setDeclaredType(type);
+            }
+            storeLocal(index, local);
+            index += kind.sizeInSlots();
+        }
+        this.locks = new ArrayList<Value>();
+    }
+
+    public void initializeFrom(FrameState other) {
+        assert locals.length == other.localsSize;
+        assert stack.length >= other.stackSize();
+
+        this.stackIndex = other.stackSize();
+        System.arraycopy(other.values, 0, locals, 0, locals.length);
+        System.arraycopy(other.values, other.localsSize(), stack, 0, stackIndex);
+        locks.clear();
+        for (int i = 0; i < other.locksSize(); i++) {
+            locks.add(other.lockAt(i));
+        }
+    }
+
+    public FrameState create(int bci) {
+        return new FrameState(bci, locals, stack, stackIndex, locks);
+    }
+
+    /**
+     * Pushes an instruction onto the stack with the expected type.
+     * @param kind the type expected for this instruction
+     * @param x the instruction to push onto the stack
+     */
+    public void push(CiKind kind, Value x) {
+        assert kind != CiKind.Void;
+        xpush(assertKind(kind, x));
+        if (kind.sizeInSlots() == 2) {
+            xpush(null);
+        }
+    }
+
+    /**
+     * Pushes a value onto the stack without checking the type.
+     * @param x the instruction to push onto the stack
+     */
+    public void xpush(Value x) {
+        stack[stackIndex++] = x;
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is an int.
+     * @param x the instruction to push onto the stack
+     */
+    public void ipush(Value x) {
+        xpush(assertInt(x));
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a float.
+     * @param x the instruction to push onto the stack
+     */
+    public void fpush(Value x) {
+        xpush(assertFloat(x));
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is an object.
+     * @param x the instruction to push onto the stack
+     */
+    public void apush(Value x) {
+        xpush(assertObject(x));
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a word.
+     * @param x the instruction to push onto the stack
+     */
+    public void wpush(Value x) {
+        xpush(assertWord(x));
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a JSR return address.
+     * @param x the instruction to push onto the stack
+     */
+    public void jpush(Value x) {
+        xpush(assertJsr(x));
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a long.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void lpush(Value x) {
+        xpush(assertLong(x));
+        xpush(null);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a double.
+     * @param x the instruction to push onto the stack
+     */
+    public void dpush(Value x) {
+        xpush(assertDouble(x));
+        xpush(null);
+    }
+
+    /**
+     * Pops an instruction off the stack with the expected type.
+     * @param kind the expected type
+     * @return the instruction on the top of the stack
+     */
+    public Value pop(CiKind kind) {
+        if (kind.sizeInSlots() == 2) {
+            xpop();
+        }
+        return assertKind(kind, xpop());
+    }
+
+    /**
+     * Pops a value off of the stack without checking the type.
+     * @return x the instruction popped off the stack
+     */
+    public Value xpop() {
+        return stack[--stackIndex];
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is an int.
+     * @return x the instruction popped off the stack
+     */
+    public Value ipop() {
+        return assertInt(xpop());
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a float.
+     * @return x the instruction popped off the stack
+     */
+    public Value fpop() {
+        return assertFloat(xpop());
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is an object.
+     * @return x the instruction popped off the stack
+     */
+    public Value apop() {
+        return assertObject(xpop());
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a word.
+     * @return x the instruction popped off the stack
+     */
+    public Value wpop() {
+        return assertWord(xpop());
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a JSR return address.
+     * @return x the instruction popped off the stack
+     */
+    public Value jpop() {
+        return assertJsr(xpop());
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a long.
+     * @return x the instruction popped off the stack
+     */
+    public Value lpop() {
+        assertHigh(xpop());
+        return assertLong(xpop());
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a double.
+     * @return x the instruction popped off the stack
+     */
+    public Value dpop() {
+        assertHigh(xpop());
+        return assertDouble(xpop());
+    }
+
+    /**
+     * Pop the specified number of slots off of this stack and return them as an array of instructions.
+     * @param size the number of arguments off of the stack
+     * @return an array containing the arguments off of the stack
+     */
+    public Value[] popArguments(int size) {
+        int base = stackIndex - size;
+        Value[] r = new Value[size];
+        for (int i = 0; i < size; ++i) {
+            assert stack[base + i] != null || stack[base + i - 1].kind.jvmSlots == 2;
+            r[i] = stack[base + i];
+        }
+        stackIndex = base;
+        return r;
+    }
+
+    /**
+     * Truncates this stack to the specified size.
+     * @param size the size to truncate to
+     */
+    public void truncateStack(int size) {
+        stackIndex = size;
+        assert stackIndex >= 0;
+    }
+
+    /**
+     * Clears all values on this stack.
+     */
+    public void clearStack() {
+        stackIndex = 0;
+    }
+
+    /**
+     * Loads the local variable at the specified index.
+     *
+     * @param i the index of the local variable to load
+     * @return the instruction that produced the specified local
+     */
+    public Value loadLocal(int i) {
+        Value x = locals[i];
+        if (x != null) {
+            if (x.isIllegal()) {
+                return null;
+            }
+            assert x.kind.isSingleWord() || locals[i + 1] == null || locals[i + 1] instanceof Phi;
+        }
+        return x;
+    }
+
+    /**
+     * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word},
+     * then the next local variable index is also overwritten.
+     *
+     * @param i the index at which to store
+     * @param x the instruction which produces the value for the local
+     */
+    public void storeLocal(int i, Value x) {
+        locals[i] = x;
+        if (isDoubleWord(x)) {
+            // (tw) if this was a double word then kill i+1
+            locals[i + 1] = null;
+        }
+        if (i > 0) {
+            // if there was a double word at i - 1, then kill it
+            Value p = locals[i - 1];
+            if (isDoubleWord(p)) {
+                locals[i - 1] = null;
+            }
+        }
+    }
+
+    /**
+     * Locks a new object within the specified IRScope.
+     * @param scope the IRScope in which this locking operation occurs
+     * @param obj the object being locked
+     */
+    public void lock(IR ir, Value obj, int totalNumberOfLocks) {
+        locks.add(obj);
+        ir.updateMaxLocks(totalNumberOfLocks);
+    }
+
+    /**
+     * Unlock the lock on the top of the stack.
+     */
+    public void unlock() {
+        locks.remove(locks.size() - 1);
+    }
+
+    /**
+     * Get the value on the stack at the specified stack index.
+     *
+     * @param i the index into the stack, with {@code 0} being the bottom of the stack
+     * @return the instruction at the specified position in the stack
+     */
+    public final Value stackAt(int i) {
+        return stack[i];
+    }
+
+    /**
+     * Gets the value in the local variables at the specified index.
+     *
+     * @param i the index into the locals
+     * @return the instruction that produced the value for the specified local
+     */
+    public final Value localAt(int i) {
+        return locals[i];
+    }
+
+    /**
+     * Retrieves the lock at the specified index in the lock stack.
+     * @param i the index into the lock stack
+     * @return the instruction which produced the object at the specified location in the lock stack
+     */
+    public final Value lockAt(int i) {
+        return locks.get(i);
+    }
+
+    /**
+     * Returns the size of the local variables.
+     *
+     * @return the size of the local variables
+     */
+    public int localsSize() {
+        return locals.length;
+    }
+
+    /**
+     * Gets number of locks held by this frame state.
+     */
+    public int locksSize() {
+        return locks.size();
+    }
+
+    /**
+     * Gets the current size (height) of the stack.
+     */
+    public int stackSize() {
+        return stackIndex;
+    }
+
+    public Iterator<Value> locals() {
+        return new ValueArrayIterator(locals);
+    }
+
+    public Iterator<Value> stack() {
+        return new ValueArrayIterator(locals);
+    }
+
+    public List<Value> locks() {
+        return Collections.unmodifiableList(locks);
+    }
+
+
+    private static class ValueArrayIterator implements Iterator<Value> {
+        private final Value[] array;
+        private int index;
+        private int length;
+
+        public ValueArrayIterator(Value[] array, int length) {
+            assert length <= array.length;
+            this.array = array;
+            this.index = 0;
+        }
+
+        public ValueArrayIterator(Value[] array) {
+            this(array, array.length);
+        }
+
+        @Override
+        public boolean hasNext() {
+            return index < array.length;
+        }
+
+        @Override
+        public Value next() {
+            return array[index++];
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException("cannot remove from array");
+        }
+
+    }
+
+}
--- a/graal/GraalCompiler/src/com/sun/c1x/value/ImmutableFrameState.java	Fri May 06 13:03:33 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +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.sun.c1x.value;
-
-
-public class ImmutableFrameState extends FrameState {
-
-    public ImmutableFrameState(int bci, int maxLocals, int maxStack) {
-        super(bci, maxLocals, maxStack);
-    }
-
-
-}
--- a/graal/GraalCompiler/src/com/sun/c1x/value/MutableFrameState.java	Fri May 06 13:03:33 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,322 +0,0 @@
-/*
- * Copyright (c) 2010, 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.value;
-
-import java.util.*;
-
-import com.sun.c1x.graph.*;
-import com.sun.c1x.ir.*;
-import com.sun.c1x.util.*;
-import com.sun.cri.ci.*;
-
-
-/**
- * The {@code MutableFrameState} class extends abstract {@link FrameState} with methods modifying the frame state.
- * Only {@code MutableFrameState} can be instantiated and thus the object references in which it is stored decide
- * whether it is used as immutable or not. Thus and because they can be shared at different places in the compiler,
- * {@link FrameState}s must not be cast to {@code MutableFrameState}s. Instead, a new copy must be created using
- * {@link FrameState#copy()}.
- * Contrariwise and as an optimization, an instance referenced as {@code MutableFrameState} can be assigned to
- * a variable, field, or method parameter of type {@link FrameState} without creating an immutable copy before
- * (using {@link #immutableCopy(int)}) if the state is not mutated after the assignment.
- */
-public final class MutableFrameState extends FrameState {
-
-    public MutableFrameState(int bci, int maxLocals, int maxStack) {
-        super(bci, maxLocals, maxStack);
-    }
-
-    /**
-     * Clears all values on this stack.
-     */
-    public void clearStack() {
-        stackIndex = 0;
-    }
-
-    public void clearLocals() {
-        for (int i = 0; i < maxLocals; i++) {
-            values[i] = null;
-        }
-    }
-
-    /**
-     * Truncates this stack to the specified size.
-     * @param size the size to truncate to
-     */
-    public void truncateStack(int size) {
-        stackIndex = size;
-        assert stackIndex >= 0;
-    }
-
-    /**
-     * Pushes an instruction onto the stack with the expected type.
-     * @param kind the type expected for this instruction
-     * @param x the instruction to push onto the stack
-     */
-    public void push(CiKind kind, Value x) {
-        assert kind != CiKind.Void;
-        xpush(assertKind(kind, x));
-        if (kind.sizeInSlots() == 2) {
-            xpush(null);
-        }
-    }
-
-    /**
-     * Pushes a value onto the stack without checking the type.
-     * @param x the instruction to push onto the stack
-     */
-    public void xpush(Value x) {
-        assert stackIndex >= 0;
-        assert maxLocals + stackIndex < values.length;
-        values[maxLocals + stackIndex++] = x;
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an int.
-     * @param x the instruction to push onto the stack
-     */
-    public void ipush(Value x) {
-        xpush(assertInt(x));
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a float.
-     * @param x the instruction to push onto the stack
-     */
-    public void fpush(Value x) {
-        xpush(assertFloat(x));
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an object.
-     * @param x the instruction to push onto the stack
-     */
-    public void apush(Value x) {
-        xpush(assertObject(x));
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a word.
-     * @param x the instruction to push onto the stack
-     */
-    public void wpush(Value x) {
-        xpush(assertWord(x));
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a JSR return address.
-     * @param x the instruction to push onto the stack
-     */
-    public void jpush(Value x) {
-        xpush(assertJsr(x));
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a long.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void lpush(Value x) {
-        xpush(assertLong(x));
-        xpush(null);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a double.
-     * @param x the instruction to push onto the stack
-     */
-    public void dpush(Value x) {
-        xpush(assertDouble(x));
-        xpush(null);
-    }
-
-    /**
-     * Pops an instruction off the stack with the expected type.
-     * @param kind the expected type
-     * @return the instruction on the top of the stack
-     */
-    public Value pop(CiKind kind) {
-        if (kind.sizeInSlots() == 2) {
-            xpop();
-        }
-        return assertKind(kind, xpop());
-    }
-
-    /**
-     * Pops a value off of the stack without checking the type.
-     * @return x the instruction popped off the stack
-     */
-    public Value xpop() {
-        assert stackIndex >= 1;
-        return values[maxLocals + --stackIndex];
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is an int.
-     * @return x the instruction popped off the stack
-     */
-    public Value ipop() {
-        return assertInt(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a float.
-     * @return x the instruction popped off the stack
-     */
-    public Value fpop() {
-        return assertFloat(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is an object.
-     * @return x the instruction popped off the stack
-     */
-    public Value apop() {
-        return assertObject(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a word.
-     * @return x the instruction popped off the stack
-     */
-    public Value wpop() {
-        return assertWord(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a JSR return address.
-     * @return x the instruction popped off the stack
-     */
-    public Value jpop() {
-        return assertJsr(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a long.
-     * @return x the instruction popped off the stack
-     */
-    public Value lpop() {
-        assertHigh(xpop());
-        return assertLong(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a double.
-     * @return x the instruction popped off the stack
-     */
-    public Value dpop() {
-        assertHigh(xpop());
-        return assertDouble(xpop());
-    }
-
-    private static Value assertKind(CiKind kind, Value x) {
-        assert x != null && (x.kind == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.kind);
-        return x;
-    }
-
-    private static Value assertLong(Value x) {
-        assert x != null && (x.kind == CiKind.Long);
-        return x;
-    }
-
-    private static Value assertJsr(Value x) {
-        assert x != null && (x.kind == CiKind.Jsr);
-        return x;
-    }
-
-    private static Value assertInt(Value x) {
-        assert x != null && (x.kind == CiKind.Int);
-        return x;
-    }
-
-    private static Value assertFloat(Value x) {
-        assert x != null && (x.kind == CiKind.Float);
-        return x;
-    }
-
-    private static Value assertObject(Value x) {
-        assert x != null && (x.kind == CiKind.Object);
-        return x;
-    }
-
-    private static Value assertWord(Value x) {
-        assert x != null && (x.kind == CiKind.Word);
-        return x;
-    }
-
-    private static Value assertDouble(Value x) {
-        assert x != null && (x.kind == CiKind.Double);
-        return x;
-    }
-
-    /**
-     * Pop the specified number of slots off of this stack and return them as an array of instructions.
-     * @param size the number of arguments off of the stack
-     * @return an array containing the arguments off of the stack
-     */
-    public Value[] popArguments(int size) {
-        int base = stackIndex - size;
-        Value[] r = new Value[size];
-        int y = maxLocals + base;
-        for (int i = 0; i < size; ++i) {
-            assert values[y] != null || values[y - 1].kind.jvmSlots == 2;
-            r[i] = values[y++];
-        }
-        stackIndex = base;
-        assert stackIndex >= 0;
-        return r;
-    }
-
-    /**
-     * Locks a new object within the specified IRScope.
-     * @param scope the IRScope in which this locking operation occurs
-     * @param obj the object being locked
-     */
-    public void lock(IR ir, Value obj, int totalNumberOfLocks) {
-        if (locks == null) {
-            locks = new ArrayList<Value>(4);
-        }
-        locks.add(obj);
-        ir.updateMaxLocks(totalNumberOfLocks);
-    }
-
-    /**
-     * Unlock the lock on the top of the stack.
-     */
-    public void unlock() {
-        locks.remove(locks.size() - 1);
-    }
-
-    /**
-     * Gets an immutable copy of this state.
-     * @param bci the bytecode index of the new frame state
-     */
-    public FrameState immutableCopy(int bci) {
-        return immutableCopy(bci, true, true, true);
-    }
-
-    private static void assertHigh(Value x) {
-        assert x == null;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/ValueUtil.java	Fri May 06 17:08:00 2011 +0200
@@ -0,0 +1,83 @@
+/*
+ * 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.value;
+
+import com.sun.c1x.ir.*;
+import com.sun.cri.ci.*;
+
+
+public class ValueUtil {
+
+    public static Value assertKind(CiKind kind, Value x) {
+        assert x != null && (x.kind == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.kind);
+        return x;
+    }
+
+    public static Value assertLong(Value x) {
+        assert x != null && (x.kind == CiKind.Long);
+        return x;
+    }
+
+    public static Value assertJsr(Value x) {
+        assert x != null && (x.kind == CiKind.Jsr);
+        return x;
+    }
+
+    public static Value assertInt(Value x) {
+        assert x != null && (x.kind == CiKind.Int);
+        return x;
+    }
+
+    public static Value assertFloat(Value x) {
+        assert x != null && (x.kind == CiKind.Float);
+        return x;
+    }
+
+    public static Value assertObject(Value x) {
+        assert x != null && (x.kind == CiKind.Object);
+        return x;
+    }
+
+    public static Value assertWord(Value x) {
+        assert x != null && (x.kind == CiKind.Word);
+        return x;
+    }
+
+    public static Value assertDouble(Value x) {
+        assert x != null && (x.kind == CiKind.Double);
+        return x;
+    }
+
+    public static void assertHigh(Value x) {
+        assert x == null;
+    }
+
+    public static boolean typeMismatch(Value x, Value y) {
+        return y == null || x.kind != y.kind;
+    }
+
+    public static boolean isDoubleWord(Value x) {
+        return x != null && x.kind.isDoubleWord();
+    }
+
+}
--- a/runtests.sh	Fri May 06 13:03:33 2011 +0200
+++ b/runtests.sh	Fri May 06 17:08:00 2011 +0200
@@ -11,4 +11,4 @@
   echo "GRAAL is not defined. It must point to a maxine repository directory."
   exit 1;
 fi
-${JDK7}/bin/java -client -graal -ea -esa -Xcomp -XX:+PrintCompilation -XX:CompileOnly=jtt -Xbootclasspath/p:"${MAXINE}/VM/bin" -Xbootclasspath/p:"${MAXINE}/Base/bin" test.com.sun.max.vm.compiler.JavaTester -verbose=1 -gen-run-scheme=false -run-scheme-package=all ${MAXINE}/VM/test/jtt/bytecode ${MAXINE}/VM/test/jtt/except ${MAXINE}/VM/test/jtt/hotpath ${MAXINE}/VM/test/jtt/jdk ${MAXINE}/VM/test/jtt/lang ${MAXINE}/VM/test/jtt/loop ${MAXINE}/VM/test/jtt/micro ${MAXINE}/VM/test/jtt/optimize ${MAXINE}/VM/test/jtt/reflect ${MAXINE}/VM/test/jtt/threads
+${JDK7}/bin/java -client -graal -ea -esa -Xcomp -XX:+PrintCompilation -XX:CompileOnly=jtt -Xbootclasspath/p:"${MAXINE}/VM/bin" -Xbootclasspath/p:"${MAXINE}/Base/bin" $1 test.com.sun.max.vm.compiler.JavaTester -verbose=1 -gen-run-scheme=false -run-scheme-package=all ${MAXINE}/VM/test/jtt/bytecode ${MAXINE}/VM/test/jtt/except ${MAXINE}/VM/test/jtt/hotpath ${MAXINE}/VM/test/jtt/jdk ${MAXINE}/VM/test/jtt/lang ${MAXINE}/VM/test/jtt/loop ${MAXINE}/VM/test/jtt/micro ${MAXINE}/VM/test/jtt/optimize ${MAXINE}/VM/test/jtt/reflect ${MAXINE}/VM/test/jtt/threads