changeset 22390:aeb7a47e272d

Merge.
author Roland Schatz <roland.schatz@oracle.com>
date Wed, 29 Jul 2015 11:59:18 +0200
parents 992575891f42 (current diff) bdfd42480dc9 (diff)
children 1825ca1a694a
files graal/com.oracle.graal.debug/src/com/oracle/graal/debug/JavaMethodContex.java graal/com.oracle.graal.debug/src/com/oracle/graal/debug/JavaMethodContext.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinarScanResolveDataFlowPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScan.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanEliminateSpillMovePhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanLifetimeAnalysisPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSAMoveResolver.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinarScanResolveDataFlowPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScan.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScanEliminateSpillMovePhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScanLifetimeAnalysisPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSAMoveResolver.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LiveValueSet.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/ValueSet.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSAUtil.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSAUtils.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/IndexedValueMap.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/ValueSet.java mx.graal/mx_graal.py mx.graal/suite.py
diffstat 160 files changed, 7621 insertions(+), 1977 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Wed Jul 29 11:59:18 2015 +0200
@@ -29,6 +29,9 @@
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Ops.*;
 import static java.lang.String.*;
 import static jdk.internal.jvmci.sparc.SPARC.*;
+
+import java.util.*;
+
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.meta.*;
 import jdk.internal.jvmci.sparc.*;
@@ -78,6 +81,10 @@
 
     private static final Ops[] OPS;
     private static final Op2s[] OP2S;
+    private static final Op3s[][] OP3S;
+
+    private ArrayList<Integer> delaySlotOptimizationPoints = new ArrayList<>(5);
+
     static {
         Ops[] ops = Ops.values();
         OPS = new Ops[ops.length];
@@ -89,6 +96,13 @@
         for (Op2s op2 : op2s) {
             OP2S[op2.value] = op2;
         }
+        OP3S = new Op3s[2][64];
+        for (Op3s op3 : Op3s.values()) {
+            if (op3.value >= 1 << 6) {
+                throw new RuntimeException("Error " + op3 + " " + op3.value);
+            }
+            OP3S[op3.op.value & 1][op3.value] = op3;
+        }
     }
 
     public enum Ops {
@@ -238,7 +252,7 @@
         Lddf  (0b10_0011, "lddf", LdstOp),
         Stf   (0b10_0100, "stf", LdstOp),
         Stfsr (0b10_0101, "stfsr", LdstOp),
-        Staf  (0x10_0110, "staf", LdstOp),
+        Staf  (0b10_0110, "staf", LdstOp),
         Stdf  (0b10_0111, "stdf", LdstOp),
 
         Rd    (0b10_1000, "rd", ArithOp),
@@ -257,6 +271,7 @@
         private final Ops op;
 
         private Op3s(int value, String name, Ops op) {
+            assert isImm(value, 6);
             this.value = value;
             this.operator = name;
             this.op = op;
@@ -270,8 +285,21 @@
             return operator;
         }
 
-        public boolean appliesTo(int instructionWord) {
-            return ((instructionWord >>> 19) & 0b1_1111) == value;
+        public boolean throwsException() {
+            if (op == LdstOp) {
+                return true;
+            }
+            switch (this) {
+                case Udiv:
+                case Udivx:
+                case Sdiv:
+                case Sdivx:
+                case Udivcc:
+                case Sdivcc:
+                    return true;
+                default:
+                    return false;
+            }
         }
     }
 
@@ -796,6 +824,574 @@
         }
     }
 
+    /**
+     * Specifies various bit fields used in SPARC instructions.
+     */
+    @SuppressWarnings("unused")
+    public abstract static class BitSpec {
+        private static final BitSpec op = new ContinousBitSpec(31, 30, "op");
+        private static final BitSpec op2 = new ContinousBitSpec(24, 22, "op2");
+        private static final BitSpec op3 = new ContinousBitSpec(24, 19, "op3");
+        private static final BitSpec rd = new ContinousBitSpec(29, 25, "rd");
+        private static final BitSpec rs1 = new ContinousBitSpec(18, 14, "rs1");
+        private static final BitSpec rs2 = new ContinousBitSpec(4, 0, "rs2");
+        private static final BitSpec simm13 = new ContinousBitSpec(12, 0, "simm13");
+        private static final BitSpec imm22 = new ContinousBitSpec(21, 0, "imm22");
+        private static final BitSpec immAsi = new ContinousBitSpec(12, 5, "immASI");
+        private static final BitSpec i = new ContinousBitSpec(13, 13, "i");
+        private static final BitSpec disp19 = new ContinousBitSpec(18, 0, true, "disp19");
+        private static final BitSpec disp22 = new ContinousBitSpec(21, 0, true, "disp22");
+        private static final BitSpec disp30 = new ContinousBitSpec(29, 0, true, "disp30");
+        private static final BitSpec a = new ContinousBitSpec(29, 29, "a");
+        private static final BitSpec p = new ContinousBitSpec(19, 19, "p");
+        private static final BitSpec cond = new ContinousBitSpec(28, 25, "cond");
+        private static final BitSpec rcond = new ContinousBitSpec(27, 25, "rcond");
+        private static final BitSpec cc = new ContinousBitSpec(21, 20, "cc");
+        private static final BitSpec d16hi = new ContinousBitSpec(21, 20, "d16hi");
+        private static final BitSpec d16lo = new ContinousBitSpec(13, 0, "d16lo");
+        private static final BitSpec d16 = new CompositeBitSpec(d16hi, d16lo);
+        // CBCond
+        private static final BitSpec cLo = new ContinousBitSpec(27, 25, "cLo");
+        private static final BitSpec cHi = new ContinousBitSpec(29, 29, "cHi");
+        private static final BitSpec c = new CompositeBitSpec(cHi, cLo);
+        private static final BitSpec cbcond = new ContinousBitSpec(28, 28, "cbcond");
+        private static final BitSpec cc2 = new ContinousBitSpec(21, 21, "cc2");
+        private static final BitSpec d10Lo = new ContinousBitSpec(12, 5, "d10Lo");
+        private static final BitSpec d10Hi = new ContinousBitSpec(20, 19, "d10Hi");
+        private static final BitSpec d10 = new CompositeBitSpec(d10Hi, d10Lo);
+        private static final BitSpec simm5 = new ContinousBitSpec(4, 0, true, "simm5");
+
+        public abstract int setBits(int word, int value);
+
+        public abstract int getBits(int word);
+
+        public abstract int getWidth();
+
+        public abstract boolean valueFits(int value);
+    }
+
+    public static class ContinousBitSpec extends BitSpec {
+        private final int hiBit;
+        private final int lowBit;
+        private final int width;
+        private final boolean signExt;
+        private final int mask;
+        private final String name;
+
+        public ContinousBitSpec(int hiBit, int lowBit, String name) {
+            this(hiBit, lowBit, false, name);
+        }
+
+        public ContinousBitSpec(int hiBit, int lowBit, boolean signExt, String name) {
+            super();
+            this.hiBit = hiBit;
+            this.lowBit = lowBit;
+            this.signExt = signExt;
+            this.width = hiBit - lowBit + 1;
+            mask = ((1 << width) - 1) << lowBit;
+            this.name = name;
+        }
+
+        @Override
+        public int setBits(int word, int value) {
+            assert valueFits(value) : "Value: " + value + " does not fit in " + this;
+            return (word & ~mask) | ((value << lowBit) & mask);
+        }
+
+        @Override
+        public int getBits(int word) {
+            if (signExt) {
+                return ((word & mask) << (31 - hiBit)) >> (32 - width);
+            } else {
+                return (word & mask) >>> lowBit;
+            }
+        }
+
+        @Override
+        public int getWidth() {
+            return width;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%s [%d:%d]", name, hiBit, lowBit);
+        }
+
+        @Override
+        public boolean valueFits(int value) {
+            if (signExt) {
+                return isSimm(value, getWidth());
+            } else {
+                return isImm(value, getWidth());
+            }
+        }
+    }
+
+    public static class CompositeBitSpec extends BitSpec {
+        private final BitSpec left;
+        private final int leftWidth;
+        private final BitSpec right;
+        private final int rightWidth;
+
+        public CompositeBitSpec(BitSpec left, BitSpec right) {
+            super();
+            this.left = left;
+            this.leftWidth = left.getWidth();
+            this.right = right;
+            this.rightWidth = right.getWidth();
+        }
+
+        @Override
+        public int getBits(int word) {
+            int l = left.getBits(word);
+            int r = right.getBits(word);
+            return l << rightWidth | r;
+        }
+
+        @Override
+        public int setBits(int word, int value) {
+            int l = leftBits(value);
+            int r = rightBits(value);
+            return left.setBits(right.setBits(word, r), l);
+        }
+
+        private int leftBits(int value) {
+            return SPARCAssembler.getBits(value, rightWidth + leftWidth, rightWidth);
+        }
+
+        private int rightBits(int value) {
+            return SPARCAssembler.getBits(value, rightWidth - 1, 0);
+        }
+
+        @Override
+        public int getWidth() {
+            return left.getWidth() + right.getWidth();
+        }
+
+        @Override
+        public String toString() {
+            return String.format("CompositeBitSpec[%s, %s]", left, right);
+        }
+
+        @Override
+        public boolean valueFits(int value) {
+            return left.valueFits(leftBits(value)) && right.valueFits(rightBits(value));
+        }
+    }
+
+    public static class BitKey {
+        private final BitSpec spec;
+        private final int value;
+
+        public BitKey(BitSpec spec, int value) {
+            super();
+            this.spec = spec;
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("BitKey %s=%s", spec, value);
+        }
+    }
+
+    /**
+     * Represents a prefix tree of {@link BitSpec} objects to find the most accurate SPARCOp.
+     */
+    public static class BitKeyIndex {
+        private final BitSpec spec;
+        private final Map<Integer, BitKeyIndex> nodes;
+        private SPARCOp op;
+
+        public BitKeyIndex(SPARCOp op) {
+            assert op != null;
+            this.op = op;
+            this.nodes = null;
+            this.spec = null;
+        }
+
+        public BitKeyIndex(BitSpec spec) {
+            assert spec != null;
+            this.op = null;
+            this.nodes = new HashMap<>(4);
+            this.spec = spec;
+        }
+
+        /**
+         * Adds operation to the index.
+         *
+         * @param keys Ordered by the importance
+         * @param operation Operation represented by this list of keys
+         */
+        private void addOp(List<BitKey> keys, SPARCOp operation) {
+            assert keys.size() > 0;
+            BitKey first = keys.get(0);
+            assert first.spec.equals(spec) : first.spec + " " + spec;
+            BitKeyIndex node;
+            if (keys.size() == 1) {
+                if (nodes.containsKey(first.value)) {
+                    node = nodes.get(first.value);
+                    assert node.op == null : node + " " + keys;
+                    node.op = operation;
+                } else {
+                    assert !nodes.containsKey(first.value) : "Index must be unique. Existing key: " + nodes.get(first.value);
+                    node = new BitKeyIndex(operation);
+                }
+            } else {
+                node = nodes.get(first.value);
+                if (node == null) {
+                    node = new BitKeyIndex(keys.get(1).spec);
+                }
+                node.addOp(keys.subList(1, keys.size()), operation);
+            }
+            nodes.put(first.value, node);
+        }
+
+        /**
+         * Finds the best matching {@link SPARCOp} for this instruction.
+         */
+        public SPARCOp find(int inst) {
+            if (nodes != null) {
+                int key = spec.getBits(inst);
+                BitKeyIndex sub = nodes.get(key);
+                if (sub == null) {
+                    if (op != null) {
+                        return op;
+                    } else {
+                        throw new RuntimeException(String.format("%s 0x%x, 0x%x %s", spec, inst, key, nodes));
+                    }
+                }
+                return sub.find(inst);
+            } else {
+                return this.op;
+            }
+        }
+
+        @Override
+        public String toString() {
+            return this.op == null ? this.spec + ": " + this.nodes : this.op.toString();
+        }
+    }
+
+    public static final Bpcc BPCC = new Bpcc(Op2s.Bp);
+    public static final Bpcc FBPCC = new Bpcc(Op2s.Fbp);
+    public static final CBCond CBCOND = new CBCond();
+    public static final Bpr BPR = new Bpr();
+    public static final Br BR = new Br();
+    public static final Sethi SETHI = new Sethi();
+    public static final Op3Op OP3 = new Op3Op();
+    public static final SPARCOp LDST = new SPARCOp(Ops.LdstOp);
+    public static final SPARCOp BRANCH = new SPARCOp(Ops.BranchOp);
+    public static final SPARCOp CALL = new SPARCOp(Ops.CallOp);
+    private static final BitKeyIndex INDEX = new BitKeyIndex(BitSpec.op);
+
+    static {
+        for (SPARCOp op : SPARCOp.OPS) {
+            INDEX.addOp(op.getKeys(), op);
+        }
+    }
+
+    public static SPARCOp getSPARCOp(int inst) {
+        return INDEX.find(inst);
+    }
+
+    /**
+     * Represents a class of SPARC instruction and gives methods to modify its fields.
+     */
+    public static class SPARCOp {
+        private final Ops op;
+        private final BitKey opKey;
+        private List<BitKey> keyFields;
+        private static final List<SPARCOp> OPS = new ArrayList<>();
+
+        public SPARCOp(Ops op) {
+            super();
+            this.op = op;
+            this.opKey = new BitKey(BitSpec.op, op.value);
+            OPS.add(this);
+        }
+
+        protected int setBits(int word) {
+            return BitSpec.op.setBits(word, op.value);
+        }
+
+        public boolean match(int inst) {
+            for (BitKey k : keyFields) {
+                if (k.spec.getBits(inst) != k.value) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        protected List<BitKey> getKeys() {
+            if (keyFields == null) {
+                keyFields = new ArrayList<>(4);
+                keyFields.add(opKey);
+            }
+            return keyFields;
+        }
+
+        public Ops getOp(int inst) {
+            return SPARCAssembler.OPS[BitSpec.op.getBits(inst)];
+        }
+
+        @Override
+        public String toString() {
+            String name = getClass().getName();
+            name = name.substring(name.lastIndexOf(".") + 1);
+            return name + "[op: " + op + "]";
+        }
+    }
+
+    /**
+     * Base class for control transfer operations; provides access to the disp field.
+     */
+    public abstract static class ControlTransferOp extends SPARCOp {
+        private final Op2s op2;
+        private final boolean delaySlot;
+        private final BitSpec disp;
+        private final BitKey op2Key;
+
+        private ControlTransferOp(Ops op, Op2s op2, boolean delaySlot, BitSpec disp) {
+            super(op);
+            this.op2 = op2;
+            this.delaySlot = delaySlot;
+            this.disp = disp;
+            this.op2Key = new BitKey(BitSpec.op2, op2.value);
+        }
+
+        public boolean hasDelaySlot() {
+            return delaySlot;
+        }
+
+        @Override
+        protected int setBits(int word) {
+            return BitSpec.op2.setBits(super.setBits(word), op2.value);
+        }
+
+        protected int setDisp(int inst, SPARCMacroAssembler masm, Label lab) {
+            if (lab.isBound()) {
+                int d = (lab.position() - masm.position()) / 4;
+                return setDisp(inst, d);
+            } else {
+                masm.patchUnbound(lab);
+                return inst;
+            }
+        }
+
+        public int setDisp(int inst, int d) {
+            assert this.match(inst);
+            return this.disp.setBits(inst, d);
+        }
+
+        public boolean isValidDisp(int d) {
+            return this.disp.valueFits(d);
+        }
+
+        public int setAnnul(int inst, boolean a) {
+            return BitSpec.a.setBits(inst, a ? 1 : 0);
+        }
+
+        @Override
+        protected List<BitKey> getKeys() {
+            List<BitKey> keys = super.getKeys();
+            keys.add(op2Key);
+            return keys;
+        }
+
+        public int getDisp(int inst) {
+            return this.disp.getBits(inst);
+        }
+
+        public abstract boolean isAnnulable(int inst);
+
+        public abstract boolean isConditional(int inst);
+    }
+
+    public static class Bpcc extends ControlTransferOp {
+        public Bpcc(Op2s op2) {
+            super(Ops.BranchOp, op2, true, BitSpec.disp19);
+        }
+
+        public void emit(SPARCMacroAssembler masm, CC cc, ConditionFlag cf, Annul annul, BranchPredict p, Label lab) {
+            int inst = setBits(0);
+            inst = BitSpec.a.setBits(inst, annul.flag);
+            inst = BitSpec.cond.setBits(inst, cf.value);
+            inst = BitSpec.cc.setBits(inst, cc.value);
+            inst = BitSpec.p.setBits(inst, p.flag);
+            masm.emitInt(setDisp(inst, masm, lab));
+        }
+
+        @Override
+        public boolean isAnnulable(int inst) {
+            return isConditional(inst);
+        }
+
+        @Override
+        public boolean isConditional(int inst) {
+            int cond = BitSpec.cond.getBits(inst);
+            return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value;
+        }
+    }
+
+    public static class Br extends ControlTransferOp {
+        public Br() {
+            super(Ops.BranchOp, Op2s.Br, true, BitSpec.disp22);
+        }
+
+        @Override
+        public boolean isAnnulable(int inst) {
+            return isConditional(inst);
+        }
+
+        @Override
+        public boolean isConditional(int inst) {
+            int cond = BitSpec.cond.getBits(inst);
+            return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value;
+        }
+    }
+
+    public static class Bpr extends ControlTransferOp {
+        private static final BitKey CBCOND_KEY = new BitKey(BitSpec.cbcond, 0);
+
+        public Bpr() {
+            super(Ops.BranchOp, Op2s.Bpr, true, BitSpec.d16);
+        }
+
+        public void emit(SPARCMacroAssembler masm, RCondition rcond, Annul a, BranchPredict p, Register rs1, Label lab) {
+            int inst = setBits(0);
+            inst = BitSpec.rcond.setBits(inst, rcond.value);
+            inst = BitSpec.a.setBits(inst, a.flag);
+            inst = BitSpec.p.setBits(inst, p.flag);
+            inst = BitSpec.rs1.setBits(inst, rs1.encoding);
+            masm.emitInt(setDisp(inst, masm, lab));
+        }
+
+        @Override
+        protected List<BitKey> getKeys() {
+            List<BitKey> keys = super.getKeys();
+            keys.add(CBCOND_KEY);
+            return keys;
+        }
+
+        @Override
+        public boolean isAnnulable(int inst) {
+            return isConditional(inst);
+        }
+
+        @Override
+        public boolean isConditional(int inst) {
+            int cond = BitSpec.cond.getBits(inst);
+            return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value;
+        }
+    }
+
+    public static final class CBCond extends ControlTransferOp {
+        private static final BitKey CBCOND_KEY = new BitKey(BitSpec.cbcond, 1);
+
+        private CBCond() {
+            super(Ops.BranchOp, Op2s.Bpr, false, BitSpec.d10);
+        }
+
+        @Override
+        protected List<BitKey> getKeys() {
+            List<BitKey> keys = super.getKeys();
+            keys.add(CBCOND_KEY);
+            return keys;
+        }
+
+        public void emit(SPARCMacroAssembler masm, ConditionFlag cf, boolean cc2, Register rs1, Register rs2, Label lab) {
+            int inst = setBits(0, cf, cc2, rs1);
+            inst = BitSpec.rs2.setBits(inst, rs2.encoding);
+            emit(masm, lab, inst);
+        }
+
+        public void emit(SPARCMacroAssembler masm, ConditionFlag cf, boolean cc2, Register rs1, int simm5, Label lab) {
+            int inst = setBits(0, cf, cc2, rs1);
+            inst = BitSpec.simm5.setBits(inst, simm5);
+            emit(masm, lab, inst);
+        }
+
+        private void emit(SPARCMacroAssembler masm, Label lab, int baseInst) {
+            int inst = baseInst;
+            masm.insertNopAfterCBCond();
+            masm.emitInt(setDisp(inst, masm, lab));
+        }
+
+        private int setBits(int base, ConditionFlag cf, boolean cc2, Register rs1) {
+            int inst = super.setBits(base);
+            inst = BitSpec.rs1.setBits(inst, rs1.encoding);
+            inst = BitSpec.cc2.setBits(inst, cc2 ? 1 : 0);
+            inst = BitSpec.c.setBits(inst, cf.value);
+            return BitSpec.cbcond.setBits(inst, 1);
+        }
+
+        @Override
+        public boolean isAnnulable(int inst) {
+            return false;
+        }
+
+        @Override
+        public boolean isConditional(int inst) {
+            return true;
+        }
+    }
+
+    public static class Op2Op extends SPARCOp {
+        private final Op2s op2;
+        private final BitKey op2Key;
+
+        public Op2Op(Ops op, Op2s op2) {
+            super(op);
+            this.op2 = op2;
+            op2Key = new BitKey(BitSpec.op2, op2.value);
+        }
+
+        @Override
+        protected int setBits(int word) {
+            int result = super.setBits(word);
+            return BitSpec.op2.setBits(result, op2.value);
+        }
+
+        @Override
+        protected List<BitKey> getKeys() {
+            List<BitKey> keys = super.getKeys();
+            keys.add(op2Key);
+            return keys;
+        }
+    }
+
+    public static class Sethi extends Op2Op {
+        public Sethi() {
+            super(Ops.BranchOp, Op2s.Sethi);
+        }
+
+        public Register getRS1(int word) {
+            int regNum = BitSpec.rs1.getBits(word);
+            return SPARC.cpuRegisters[regNum];
+        }
+
+        public int getImm22(int word) {
+            return BitSpec.imm22.getBits(word);
+        }
+
+        public boolean isNop(int inst) {
+            return getRS1(inst).equals(g0) && getImm22(inst) == 0;
+        }
+    }
+
+    public static class Op3Op extends SPARCOp {
+        public Op3Op() {
+            super(ArithOp);
+        }
+
+        public Op3s getOp3(int inst) {
+            assert match(inst);
+            return OP3S[ArithOp.value & 1][BitSpec.op3.getBits(inst)];
+        }
+    }
+
     public boolean hasFeature(CPUFeature feature) {
         return ((SPARC) this.target.arch).features.contains(feature);
     }
@@ -897,7 +1493,12 @@
     // @formatter:on
     protected void fmt00(int a, int op2, int b) {
         assert isImm(a, 5) && isImm(op2, 3) && isImm(b, 22) : String.format("a: 0x%x op2: 0x%x b: 0x%x", a, op2, b);
-        this.emitInt(a << 25 | op2 << 22 | b);
+        int word = 0;
+        BitSpec.op.setBits(word, 0);
+        BitSpec.rd.setBits(word, a);
+        BitSpec.op2.setBits(word, op2);
+        BitSpec.imm22.setBits(word, b);
+        emitInt(a << 25 | op2 << 22 | b);
     }
 
     private void op3(Op3s op3, Opfs opf, Register rs1, Register rs2, Register rd) {
@@ -975,7 +1576,11 @@
     }
 
     protected static boolean isCBCond(int inst) {
-        return getOp(inst).equals(Ops.BranchOp) && getOp2(inst).equals(Op2s.Bpr) && getBits(inst, 28, 28) == 1;
+        return isOp2(Ops.BranchOp, Op2s.Bpr, inst) && getBits(inst, 28, 28) == 1;
+    }
+
+    private static boolean isOp2(Ops ops, Op2s op2s, int inst) {
+        return getOp(inst).equals(ops) && getOp2(inst).equals(op2s);
     }
 
     private static Ops getOp(int inst) {
@@ -986,7 +1591,7 @@
         return OP2S[getBits(inst, 24, 22)];
     }
 
-    private static int getBits(int inst, int hiBit, int lowBit) {
+    public static int getBits(int inst, int hiBit, int lowBit) {
         return (inst >> lowBit) & ((1 << (hiBit - lowBit + 1)) - 1);
     }
 
@@ -1033,6 +1638,7 @@
         pos &= (1 << disp) - 1;
         int a = (annul.flag << 4) | cond.getValue();
         int b = (cc.getValue() << 20) | ((predictTaken.flag) << 19) | pos;
+        delaySlotOptimizationPoints.add(position());
         fmt00(a, op2.getValue(), b);
     }
 
@@ -1055,10 +1661,11 @@
         int d16hi = (pos >> 13) << 13;
         int d16lo = d16hi ^ pos;
         int b = (d16hi << 20) | (predictTaken.flag << 19) | (rs1.encoding() << 14) | d16lo;
+        delaySlotOptimizationPoints.add(position());
         fmt00(a, Op2s.Bpr.getValue(), b);
     }
 
-    private int patchUnbound(Label label) {
+    protected int patchUnbound(Label label) {
         label.addPatchAt(position());
         return 0;
     }
@@ -1377,6 +1984,7 @@
     public void fcmp(CC cc, Opfs opf, Register rs1, Register rs2) {
         int a = cc.value;
         int b = opf.value << 5 | rs2.encoding;
+        delaySlotOptimizationPoints.add(position());
         fmt10(a, Fcmp.value, rs1.encoding, b);
     }
 
@@ -1830,4 +2438,69 @@
     public void fpadd32(Register rs1, Register rs2, Register rd) {
         op3(Impdep1, Fpadd32, rs1, rs2, rd);
     }
+
+    /**
+     * Does peephole optimization on code generated by this assembler. This method should be called
+     * at the end of code generation.
+     * <p>
+     * It searches for conditional branch instructions which has nop in the delay slot then looks at
+     * the instruction at branch target; if it is an arithmetic instruction, which does not throw an
+     * exception (e.g. division), it pulls this instruction into the delay slot and increments the
+     * displacement by 1.
+     */
+    public void peephole() {
+        for (int i : delaySlotOptimizationPoints) {
+            optimizeDelaySlot(i);
+        }
+    }
+
+    /**
+     * Optimizes branch instruction <i>b</t> which has a nop in the delay slot. It tries to stuff
+     * the instruction at <i>b</i>s branch target into the delay slot of <i>b</i>, set the annul
+     * flag and increments <i>b</i>s disp field by 1;
+     * <p>
+     * If <i>b</i>s branch target instruction is an unconditional branch <i>t</i>, then it tries to
+     * put <i>t</i>s delayed instruction into the delay slot of <i>b</i> and add the <i>t</i>s disp
+     * field to <i>b</i>s disp field.
+     */
+    private void optimizeDelaySlot(int i) {
+        int delaySlotAbsolute = i + INSTRUCTION_SIZE;
+        int nextInst = getInt(delaySlotAbsolute);
+        SPARCOp nextOp = getSPARCOp(nextInst);
+        if (nextOp instanceof Sethi && ((Sethi) nextOp).isNop(nextInst)) {
+            int inst = getInt(i);
+            SPARCOp op = getSPARCOp(inst);
+            if (op instanceof ControlTransferOp && ((ControlTransferOp) op).hasDelaySlot() && ((ControlTransferOp) op).isAnnulable(inst)) {
+                ControlTransferOp ctOp = (ControlTransferOp) op;
+                int disp = ctOp.getDisp(inst);
+                int branchTargetAbsolute = i + disp * INSTRUCTION_SIZE;
+                int branchTargetInst = getInt(branchTargetAbsolute);
+                SPARCOp branchTargetOp = getSPARCOp(branchTargetInst);
+                if (branchTargetOp instanceof Op3Op) {
+                    Op3s op3 = ((Op3Op) branchTargetOp).getOp3(branchTargetInst);
+                    if (!op3.throwsException()) {
+                        inst = ctOp.setDisp(inst, disp + 1); // Increment the offset
+                        inst = ctOp.setAnnul(inst, true);
+                        emitInt(inst, i);
+                        emitInt(branchTargetInst, delaySlotAbsolute);
+                    }
+                } else if (branchTargetOp instanceof ControlTransferOp && !((ControlTransferOp) branchTargetOp).isConditional(branchTargetInst)) {
+                    // If branchtarget is a unconditional branch
+                    ControlTransferOp branchTargetOpBranch = (ControlTransferOp) branchTargetOp;
+                    int btDisp = branchTargetOpBranch.getDisp(branchTargetInst);
+                    int newDisp = disp + btDisp;
+                    if (ctOp.isValidDisp(newDisp)) { // Test if we don't exceed field size
+                        int instAfter = ctOp.setDisp(inst, newDisp);
+                        instAfter = ctOp.setAnnul(instAfter, true);
+                        branchTargetInst = getInt(branchTargetAbsolute + INSTRUCTION_SIZE);
+                        branchTargetOp = getSPARCOp(branchTargetInst);
+                        if (branchTargetOp instanceof Op3Op && !((Op3Op) branchTargetOp).getOp3(branchTargetInst).throwsException()) {
+                            emitInt(instAfter, i);
+                            emitInt(branchTargetInst, delaySlotAbsolute);
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Wed Jul 29 11:59:18 2015 +0200
@@ -76,48 +76,8 @@
     protected final void patchJumpTarget(int branch, int branchTarget) {
         final int disp = (branchTarget - branch) / 4;
         final int inst = getInt(branch);
-        Op2s op2 = Op2s.byValue((inst & OP2_MASK) >> OP2_SHIFT);
-        int maskBits;
-        int setBits;
-        switch (op2) {
-            case Br:
-            case Fb:
-            case Sethi:
-            case Illtrap:
-                // Disp 22 in the lower 22 bits
-                assert isSimm(disp, 22);
-                setBits = disp << DISP22_SHIFT;
-                maskBits = DISP22_MASK;
-                break;
-            case Fbp:
-            case Bp:
-                // Disp 19 in the lower 19 bits
-                assert isSimm(disp, 19);
-                setBits = disp << DISP19_SHIFT;
-                maskBits = DISP19_MASK;
-                break;
-            case Bpr:
-                if (isCBCond(inst)) {
-                    assert isSimm10(disp) : String.format("%d: instruction: 0x%x", disp, inst);
-                    int d10Split = 0;
-                    d10Split |= (disp & 0b11_0000_0000) << D10HI_SHIFT - 8;
-                    d10Split |= (disp & 0b00_1111_1111) << D10LO_SHIFT;
-                    setBits = d10Split;
-                    maskBits = D10LO_MASK | D10HI_MASK;
-                } else {
-                    assert isSimm(disp, 16);
-                    int d16Split = 0;
-                    d16Split |= (disp & 0b1100_0000_0000_0000) << D16HI_SHIFT - 14;
-                    d16Split |= (disp & 0b0011_1111_1111_1111) << D16LO_SHIFT;
-                    setBits = d16Split;
-                    maskBits = D16HI_MASK | D16LO_MASK;
-                }
-                break;
-            default:
-                throw new InternalError("Unknown op2 " + op2);
-        }
-        int newInst = ~maskBits & inst;
-        newInst |= setBits;
+        ControlTransferOp op = (ControlTransferOp) getSPARCOp(inst);
+        int newInst = op.setDisp(inst, disp);
         emitInt(newInst, branch);
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/BackendOptions.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/BackendOptions.java	Wed Jul 29 11:59:18 2015 +0200
@@ -25,7 +25,7 @@
 import static com.oracle.graal.compiler.common.BackendOptions.UserOptions.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import jdk.internal.jvmci.options.*;
-import jdk.internal.jvmci.options.DerivedOptionValue.*;
+import jdk.internal.jvmci.options.DerivedOptionValue.OptionSupplier;
 
 /**
  * Options to control the backend configuration.
@@ -36,27 +36,44 @@
         // @formatter:off
         @Option(help = "Destruct SSA LIR eagerly (before other LIR phases).", type = OptionType.Debug)
         public static final OptionValue<Boolean> LIREagerSSADestruction = new OptionValue<>(false);
+        @Option(help = "Enable Linear Scan on SSI form.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptSSILinearScan = new OptionValue<>(false);
+        @Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> TraceRA = new OptionValue<>(false);
         // @formatter:on
     }
 
+    /* Enable SSI Construction. */
+    public static final DerivedOptionValue<Boolean> EnableSSIConstruction = new DerivedOptionValue<>(new OptionSupplier<Boolean>() {
+        private static final long serialVersionUID = -7375589337502162545L;
+
+        public Boolean get() {
+            return LIROptSSILinearScan.getValue() || TraceRA.getValue();
+        }
+    });
+
     /* Create SSA LIR during LIR generation. */
     public static final DerivedOptionValue<Boolean> ConstructionSSAlirDuringLirBuilding = new DerivedOptionValue<>(new OptionSupplier<Boolean>() {
         private static final long serialVersionUID = 7657622005438210681L;
 
         public Boolean get() {
-            return SSA_LIR.getValue();
+            return SSA_LIR.getValue() || EnableSSIConstruction.getValue();
         }
     });
 
     public enum LSRAVariant {
         NONSSA_LSAR,
-        SSA_LSRA
+        SSA_LSRA,
+        SSI_LSRA
     }
 
     public static final DerivedOptionValue<LSRAVariant> LinearScanVariant = new DerivedOptionValue<>(new OptionSupplier<LSRAVariant>() {
         private static final long serialVersionUID = 364925071685235153L;
 
         public LSRAVariant get() {
+            if (LIROptSSILinearScan.getValue()) {
+                return LSRAVariant.SSI_LSRA;
+            }
             if (SSA_LIR.getValue() && !LIREagerSSADestruction.getValue()) {
                 return LSRAVariant.SSA_LSRA;
             }
@@ -71,9 +88,14 @@
         public Boolean get() {
             switch (LinearScanVariant.getValue()) {
                 case SSA_LSRA:
+                case SSI_LSRA:
                     return true;
             }
+            if (TraceRA.getValue()) {
+                return true;
+            }
             return false;
         }
     });
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/TraceBuilder.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.alloc;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+
+public final class TraceBuilder<T extends AbstractBlockBase<T>> {
+
+    public static final class TraceBuilderResult<T extends AbstractBlockBase<T>> {
+        private final List<List<T>> traces;
+        private final int[] blockToTrace;
+
+        private TraceBuilderResult(List<List<T>> traces, int[] blockToTrace) {
+            this.traces = traces;
+            this.blockToTrace = blockToTrace;
+        }
+
+        public int getTraceForBlock(AbstractBlockBase<?> block) {
+            return blockToTrace[block.getId()];
+        }
+
+        public List<List<T>> getTraces() {
+            return traces;
+        }
+    }
+
+    /**
+     * Build traces of sequentially executed blocks.
+     */
+    public static <T extends AbstractBlockBase<T>> TraceBuilderResult<T> computeTraces(T startBlock, List<T> blocks) {
+        return new TraceBuilder<>(blocks).build(startBlock);
+    }
+
+    private final PriorityQueue<T> worklist;
+    private final BitSet processed;
+    /**
+     * Contains the number of unprocessed predecessors for every {@link AbstractBlockBase#getId()
+     * block}.
+     */
+    private final int[] blocked;
+    private final int[] blockToTrace;
+
+    private TraceBuilder(List<T> blocks) {
+        processed = new BitSet(blocks.size());
+        worklist = new PriorityQueue<T>(TraceBuilder::compare);
+        blocked = new int[blocks.size()];
+        blockToTrace = new int[blocks.size()];
+        for (T block : blocks) {
+            blocked[block.getId()] = block.getPredecessorCount();
+        }
+    }
+
+    private static <T extends AbstractBlockBase<T>> int compare(T a, T b) {
+        return Double.compare(b.probability(), a.probability());
+    }
+
+    private boolean processed(T b) {
+        return processed.get(b.getId());
+    }
+
+    private TraceBuilderResult<T> build(T startBlock) {
+        try (Scope s = Debug.scope("TraceBuilder"); Indent i = Debug.logAndIndent("start trace building: " + startBlock)) {
+            ArrayList<List<T>> traces = buildTraces(startBlock);
+
+            assert verify(traces);
+            return new TraceBuilderResult<>(traces, blockToTrace);
+        }
+    }
+
+    private boolean verify(ArrayList<List<T>> traces) {
+        assert traces.stream().flatMap(l -> l.stream()).distinct().count() == blocked.length : "Not all blocks assigned to traces!";
+        for (List<T> trace : traces) {
+            T last = null;
+            for (T current : trace) {
+                assert last == null || current.getPredecessors().contains(last);
+                last = current;
+            }
+        }
+        return true;
+    }
+
+    protected ArrayList<List<T>> buildTraces(T startBlock) {
+        ArrayList<List<T>> traces = new ArrayList<>();
+        // add start block
+        worklist.add(startBlock);
+        // process worklist
+        while (!worklist.isEmpty()) {
+            T block = worklist.poll();
+            assert block != null;
+            traces.add(startTrace(block, traces.size()));
+        }
+        return traces;
+    }
+
+    /**
+     * Build a new trace starting at {@code block}.
+     */
+    private List<T> startTrace(T block, int traceNumber) {
+        assert block.getPredecessors().stream().allMatch(this::processed) : "Predecessor unscheduled: " + block.getPredecessors().stream().filter(this::processed).findFirst().get();
+        ArrayList<T> trace = new ArrayList<>();
+        int blockNumber = 0;
+        try (Indent i = Debug.logAndIndent("StartTrace: " + block)) {
+            for (T currentBlock = block; currentBlock != null; currentBlock = selectNext(currentBlock)) {
+                Debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability());
+                processed.set(currentBlock.getId());
+                worklist.remove(currentBlock);
+                trace.add(currentBlock);
+                unblock(currentBlock);
+                currentBlock.setLinearScanNumber(blockNumber++);
+                blockToTrace[currentBlock.getId()] = traceNumber;
+            }
+        }
+        return trace;
+    }
+
+    /**
+     * Decrease the {@link #blocked} count for all predecessors and add them to the worklist once
+     * the count reaches 0.
+     */
+    private void unblock(T currentBlock) {
+        for (T successor : currentBlock.getSuccessors()) {
+            if (!processed(successor)) {
+                int blockCount = --blocked[successor.getId()];
+                assert blockCount >= 0;
+                if (blockCount == 0) {
+                    worklist.add(successor);
+                }
+            }
+        }
+    }
+
+    /**
+     * @return The unprocessed predecessor with the highest probability, or {@code null}.
+     */
+    private T selectNext(T currentBlock) {
+        T next = null;
+        for (T succ : currentBlock.getSuccessors()) {
+            if (!processed(succ) && (next == null || succ.probability() > next.probability())) {
+                next = succ;
+            }
+        }
+        return next;
+    }
+}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/Util.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/Util.java	Wed Jul 29 11:59:18 2015 +0200
@@ -24,8 +24,9 @@
 
 import java.util.*;
 
+import com.oracle.graal.debug.*;
+
 import jdk.internal.jvmci.code.*;
-import jdk.internal.jvmci.debug.*;
 
 /**
  * The {@code Util} class contains a motley collection of utility methods used throughout the
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Jul 29 11:59:18 2015 +0200
@@ -64,8 +64,6 @@
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.code.CallingConvention.Type;
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
-
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.*;
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Wed Jul 29 11:59:18 2015 +0200
@@ -24,8 +24,6 @@
 
 import java.io.*;
 
-import jdk.internal.jvmci.debug.*;
-
 import com.oracle.graal.debug.*;
 
 import org.junit.*;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -64,7 +64,7 @@
             emitBlock(nodeLirBuilder, lirGenRes, (Block) b, graph, schedule.getBlockToNodesMap());
         }
         context.lirGen.beforeRegisterAllocation();
-        assert !ConstructionSSAlirDuringLirBuilding.getValue() || SSAUtils.verifySSAForm(lirGenRes.getLIR());
+        assert !ConstructionSSAlirDuringLirBuilding.getValue() || SSAUtil.verifySSAForm(lirGenRes.getLIR());
     }
 
     private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<Node>> blockMap) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/InstructionPrinter.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/InstructionPrinter.java	Wed Jul 29 11:59:18 2015 +0200
@@ -23,8 +23,8 @@
 package com.oracle.graal.compiler.gen;
 
 import static com.oracle.graal.compiler.gen.InstructionPrinter.InstructionLineColumn.*;
-import jdk.internal.jvmci.debug.*;
 
+import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 
 /**
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Wed Jul 29 11:59:18 2015 +0200
@@ -33,8 +33,6 @@
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
-
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.*;
 
--- a/graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugTimerTest.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugTimerTest.java	Wed Jul 29 11:59:18 2015 +0200
@@ -26,8 +26,6 @@
 
 import java.lang.management.*;
 
-import jdk.internal.jvmci.debug.*;
-
 import com.oracle.graal.debug.*;
 
 import org.junit.*;
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/GraalDebugConfig.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/GraalDebugConfig.java	Wed Jul 29 11:59:18 2015 +0200
@@ -199,8 +199,8 @@
      * @return the {@link JavaMethod} represented by {@code context} or null
      */
     public static JavaMethod asJavaMethod(Object context) {
-        if (context instanceof JavaMethodContex) {
-            return ((JavaMethodContex) context).asJavaMethod();
+        if (context instanceof JavaMethodContext) {
+            return ((JavaMethodContext) context).asJavaMethod();
         }
         return null;
     }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/JavaMethodContex.java	Tue Jul 28 17:35:49 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.debug;
-
-import jdk.internal.jvmci.meta.*;
-
-/**
- * Interface for objects used in Debug {@linkplain Debug#context() context} that can provide a
- * {@link JavaMethod}.
- */
-public interface JavaMethodContex {
-    JavaMethod asJavaMethod();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/JavaMethodContext.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.debug;
+
+import jdk.internal.jvmci.meta.*;
+
+/**
+ * Interface for objects used in Debug {@linkplain Debug#context() context} that can provide a
+ * {@link JavaMethod}.
+ */
+public interface JavaMethodContext {
+    JavaMethod asJavaMethod();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/LogStream.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2009, 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.debug;
+
+import java.io.*;
+
+/**
+ * A utility for printing compiler debug and informational output to an output stream.
+ *
+ * A {@link LogStream} instance maintains an internal buffer that is flushed to the underlying
+ * output stream every time one of the {@code println} methods is invoked, or a newline character (
+ * {@code '\n'}) is written.
+ *
+ * All of the {@code print} and {@code println} methods return the {code LogStream} instance on
+ * which they were invoked. This allows chaining of these calls to mitigate use of String
+ * concatenation by the caller.
+ *
+ * A {@code LogStream} maintains a current {@linkplain #indentationLevel() indentation} level. Each
+ * line of output written to this stream has {@code n} spaces prefixed to it where {@code n} is the
+ * value that would be returned by {@link #indentationLevel()} when the first character of a new
+ * line is written.
+ *
+ * A {@code LogStream} maintains a current {@linkplain #position() position} for the current line
+ * being written. This position can be advanced to a specified position by
+ * {@linkplain #fillTo(int, char) filling} this stream with a given character.
+ */
+public class LogStream {
+
+    /**
+     * Null output stream that simply swallows any output sent to it.
+     */
+    public static final LogStream SINK = new LogStream();
+
+    private static final PrintStream SINK_PS = new PrintStream(new OutputStream() {
+
+        @Override
+        public void write(int b) throws IOException {
+        }
+    });
+
+    private LogStream() {
+        this.ps = null;
+        this.lineBuffer = null;
+    }
+
+    /**
+     * The output stream to which this log stream writes.
+     */
+    private final PrintStream ps;
+
+    private final StringBuilder lineBuffer;
+    private int indentationLevel;
+    private char indentation = ' ';
+    private boolean indentationDisabled;
+
+    public final PrintStream out() {
+        if (ps == null) {
+            return SINK_PS;
+        }
+        return ps;
+    }
+
+    /**
+     * The system dependent line separator.
+     */
+    public static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+    /**
+     * Creates a new log stream.
+     *
+     * @param os the underlying output stream to which prints are sent
+     */
+    public LogStream(OutputStream os) {
+        ps = os instanceof PrintStream ? (PrintStream) os : new PrintStream(os);
+        lineBuffer = new StringBuilder(100);
+    }
+
+    /**
+     * Creates a new log stream that shares the same {@linkplain #ps output stream} as a given
+     * {@link LogStream}.
+     *
+     * @param log a LogStream whose output stream is shared with this one
+     */
+    public LogStream(LogStream log) {
+        ps = log.ps;
+        lineBuffer = new StringBuilder(100);
+    }
+
+    /**
+     * Prepends {@link #indentation} to the current output line until its write position is equal to
+     * the current {@linkplain #indentationLevel()} level.
+     */
+    private void indent() {
+        if (ps != null) {
+            if (!indentationDisabled && indentationLevel != 0) {
+                while (lineBuffer.length() < indentationLevel) {
+                    lineBuffer.append(indentation);
+                }
+            }
+        }
+    }
+
+    private LogStream flushLine(boolean withNewline) {
+        if (ps != null) {
+            if (withNewline) {
+                lineBuffer.append(LINE_SEPARATOR);
+            }
+            ps.print(lineBuffer.toString());
+            ps.flush();
+            lineBuffer.setLength(0);
+        }
+        return this;
+    }
+
+    /**
+     * Flushes the stream. This is done by terminating the current line if it is not at position 0
+     * and then flushing the underlying output stream.
+     */
+    public void flush() {
+        if (ps != null) {
+            if (lineBuffer.length() != 0) {
+                flushLine(false);
+            }
+            ps.flush();
+        }
+    }
+
+    /**
+     * Gets the current column position of this log stream.
+     *
+     * @return the current column position of this log stream
+     */
+    public int position() {
+        return lineBuffer == null ? 0 : lineBuffer.length();
+
+    }
+
+    /**
+     * Gets the current indentation level for this log stream.
+     *
+     * @return the current indentation level for this log stream.
+     */
+    public int indentationLevel() {
+        return indentationLevel;
+    }
+
+    /**
+     * Adjusts the current indentation level of this log stream.
+     *
+     * @param delta
+     */
+    public void adjustIndentation(int delta) {
+        if (delta < 0) {
+            indentationLevel = Math.max(0, indentationLevel + delta);
+        } else {
+            indentationLevel += delta;
+        }
+    }
+
+    /**
+     * Gets the current indentation character of this log stream.
+     */
+    public char indentation() {
+        return indentation;
+    }
+
+    public void disableIndentation() {
+        indentationDisabled = true;
+    }
+
+    public void enableIndentation() {
+        indentationDisabled = false;
+    }
+
+    /**
+     * Sets the character used for indentation.
+     */
+    public void setIndentation(char c) {
+        indentation = c;
+    }
+
+    /**
+     * Advances this stream's {@linkplain #position() position} to a given position by repeatedly
+     * appending a given character as necessary.
+     *
+     * @param position the position to which this stream's position will be advanced
+     * @param filler the character used to pad the stream
+     */
+    public LogStream fillTo(int position, char filler) {
+        if (ps != null) {
+            indent();
+            while (lineBuffer.length() < position) {
+                lineBuffer.append(filler);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Writes a boolean value to this stream as {@code "true"} or {@code "false"}.
+     *
+     * @param b the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(boolean b) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(b);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a boolean value to this stream followed by a {@linkplain #LINE_SEPARATOR line
+     * separator}.
+     *
+     * @param b the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(boolean b) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(b);
+            return flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a character value to this stream.
+     *
+     * @param c the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(char c) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(c);
+            if (c == '\n') {
+                if (lineBuffer.indexOf(LINE_SEPARATOR, lineBuffer.length() - LINE_SEPARATOR.length()) != -1) {
+                    flushLine(false);
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Writes a character value to this stream followed by a {@linkplain #LINE_SEPARATOR line
+     * separator}.
+     *
+     * @param c the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(char c) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(c);
+            flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Prints an int value.
+     *
+     * @param i the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(int i) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(i);
+        }
+        return this;
+    }
+
+    /**
+     * Writes an int value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}.
+     *
+     * @param i the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(int i) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(i);
+            return flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a float value to this stream.
+     *
+     * @param f the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(float f) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(f);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a float value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}
+     * .
+     *
+     * @param f the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(float f) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(f);
+            return flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a long value to this stream.
+     *
+     * @param l the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(long l) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(l);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a long value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}.
+     *
+     * @param l the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(long l) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(l);
+            return flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a double value to this stream.
+     *
+     * @param d the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(double d) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(d);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a double value to this stream followed by a {@linkplain #LINE_SEPARATOR line
+     * separator}.
+     *
+     * @param d the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(double d) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(d);
+            return flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a {@code String} value to this stream. This method ensures that the
+     * {@linkplain #position() position} of this stream is updated correctly with respect to any
+     * {@linkplain #LINE_SEPARATOR line separators} present in {@code s}.
+     *
+     * @param s the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(String s) {
+        if (ps != null) {
+            if (s == null) {
+                indent();
+                lineBuffer.append(s);
+                return this;
+            }
+
+            int index = 0;
+            int next = s.indexOf(LINE_SEPARATOR, index);
+            while (index < s.length()) {
+                indent();
+                if (next > index) {
+                    lineBuffer.append(s.substring(index, next));
+                    flushLine(true);
+                    index = next + LINE_SEPARATOR.length();
+                    next = s.indexOf(LINE_SEPARATOR, index);
+                } else {
+                    lineBuffer.append(s.substring(index));
+                    break;
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Writes a {@code String} value to this stream followed by a {@linkplain #LINE_SEPARATOR line
+     * separator}.
+     *
+     * @param s the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(String s) {
+        if (ps != null) {
+            print(s);
+            flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a formatted string to this stream.
+     *
+     * @param format a format string as described in {@link String#format(String, Object...)}
+     * @param args the arguments to be formatted
+     * @return this {@link LogStream} instance
+     */
+    public LogStream printf(String format, Object... args) {
+        if (ps != null) {
+            print(String.format(format, args));
+        }
+        return this;
+    }
+
+    /**
+     * Writes a {@linkplain #LINE_SEPARATOR line separator} to this stream.
+     *
+     * @return this {@code LogStream} instance
+     */
+    public LogStream println() {
+        if (ps != null) {
+            indent();
+            flushLine(true);
+        }
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Management.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.debug;
+
+import static java.lang.Thread.*;
+
+import java.lang.management.*;
+
+import javax.management.*;
+
+public class Management {
+
+    private static final com.sun.management.ThreadMXBean threadMXBean = Management.initThreadMXBean();
+
+    /**
+     * The amount of memory allocated by
+     * {@link com.sun.management.ThreadMXBean#getThreadAllocatedBytes(long)} itself.
+     */
+    private static final long threadMXBeanOverhead = -getCurrentThreadAllocatedBytes() + getCurrentThreadAllocatedBytes();
+
+    public static long getCurrentThreadAllocatedBytes() {
+        return threadMXBean.getThreadAllocatedBytes(currentThread().getId()) - threadMXBeanOverhead;
+    }
+
+    private static com.sun.management.ThreadMXBean initThreadMXBean() {
+        try {
+            return (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
+        } catch (Error err) {
+            return new UnimplementedBean();
+        }
+    }
+
+    public static ThreadMXBean getThreadMXBean() {
+        return threadMXBean;
+    }
+
+    private static class UnimplementedBean implements ThreadMXBean, com.sun.management.ThreadMXBean {
+
+        public ObjectName getObjectName() {
+            return null;
+        }
+
+        public long getThreadAllocatedBytes(long arg0) {
+            return 0;
+        }
+
+        public long[] getThreadAllocatedBytes(long[] arg0) {
+            return null;
+        }
+
+        public long[] getThreadCpuTime(long[] arg0) {
+            return null;
+        }
+
+        public long[] getThreadUserTime(long[] arg0) {
+            return null;
+        }
+
+        public boolean isThreadAllocatedMemoryEnabled() {
+            return false;
+        }
+
+        public boolean isThreadAllocatedMemorySupported() {
+            return false;
+        }
+
+        public void setThreadAllocatedMemoryEnabled(boolean arg0) {
+        }
+
+        public int getThreadCount() {
+            return 0;
+        }
+
+        public int getPeakThreadCount() {
+            return 0;
+        }
+
+        public long getTotalStartedThreadCount() {
+            return 0;
+        }
+
+        public int getDaemonThreadCount() {
+            return 0;
+        }
+
+        public long[] getAllThreadIds() {
+            return null;
+        }
+
+        public ThreadInfo getThreadInfo(long id) {
+            return null;
+        }
+
+        public ThreadInfo[] getThreadInfo(long[] ids) {
+            return null;
+        }
+
+        public ThreadInfo getThreadInfo(long id, int maxDepth) {
+            return null;
+        }
+
+        public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth) {
+            return null;
+        }
+
+        public boolean isThreadContentionMonitoringSupported() {
+            return false;
+        }
+
+        public boolean isThreadContentionMonitoringEnabled() {
+            return false;
+        }
+
+        public void setThreadContentionMonitoringEnabled(boolean enable) {
+        }
+
+        public long getCurrentThreadCpuTime() {
+            return 0;
+        }
+
+        public long getCurrentThreadUserTime() {
+            return 0;
+        }
+
+        public long getThreadCpuTime(long id) {
+            return 0;
+        }
+
+        public long getThreadUserTime(long id) {
+            return 0;
+        }
+
+        public boolean isThreadCpuTimeSupported() {
+            return false;
+        }
+
+        public boolean isCurrentThreadCpuTimeSupported() {
+            return false;
+        }
+
+        public boolean isThreadCpuTimeEnabled() {
+            return false;
+        }
+
+        public void setThreadCpuTimeEnabled(boolean enable) {
+        }
+
+        public long[] findMonitorDeadlockedThreads() {
+            return null;
+        }
+
+        public void resetPeakThreadCount() {
+        }
+
+        public long[] findDeadlockedThreads() {
+            return null;
+        }
+
+        public boolean isObjectMonitorUsageSupported() {
+            return false;
+        }
+
+        public boolean isSynchronizerUsageSupported() {
+            return false;
+        }
+
+        public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers) {
+            return null;
+        }
+
+        public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers) {
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/TTY.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2009, 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.debug;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.regex.*;
+
+import jdk.internal.jvmci.service.*;
+
+/**
+ * A collection of static methods for printing debug and informational output to a global
+ * {@link LogStream}. The output can be (temporarily) suppressed per thread through use of a
+ * {@linkplain Filter filter}.
+ */
+public class TTY {
+
+    /**
+     * Support for thread-local suppression of {@link TTY}.
+     */
+    public static class Filter {
+
+        private LogStream previous;
+        private final Thread thread = Thread.currentThread();
+
+        /**
+         * Creates an object that will suppress {@link TTY} for the current thread if the given
+         * filter does not match the given object. To revert the suppression state to how it was
+         * before this call, the {@link #remove()} method must be called on the suppression object.
+         *
+         * @param filter the pattern for matching. If {@code null}, then the match is successful. If
+         *            it starts with "~", then a regular expression
+         *            {@linkplain Pattern#matches(String, CharSequence) match} is performed where
+         *            the regular expression is specified by {@code filter} without the "~" prefix.
+         *            Otherwise, a simple {@linkplain String#contains(CharSequence) substring} match
+         *            is performed where {@code filter} is the substring used.
+         * @param object an object whose {@linkplain Object#toString() string} value is matched
+         *            against {@code filter}
+         */
+        public Filter(String filter, Object object) {
+            boolean suppressed = false;
+            if (filter != null) {
+                String input = object.toString();
+                if (filter.startsWith("~")) {
+                    suppressed = !Pattern.matches(filter.substring(1), input);
+                } else {
+                    suppressed = !input.contains(filter);
+                }
+                if (suppressed) {
+                    previous = out();
+                    log.set(LogStream.SINK);
+                }
+            }
+        }
+
+        /**
+         * Creates an object that will suppress {@link TTY} for the current thread. To revert the
+         * suppression state to how it was before this call, the {@link #remove()} method must be
+         * called on this filter object.
+         */
+        public Filter() {
+            previous = out();
+            log.set(LogStream.SINK);
+        }
+
+        /**
+         * Reverts the suppression state of {@link TTY} to how it was before this object was
+         * constructed.
+         */
+        public void remove() {
+            assert thread == Thread.currentThread();
+            if (previous != null) {
+                log.set(previous);
+            }
+        }
+    }
+
+    /**
+     * The {@link PrintStream} to which all non-suppressed output from {@link TTY} is written.
+     */
+    public static final PrintStream out;
+    static {
+        TTYStreamProvider p = Services.loadSingle(TTYStreamProvider.class, false);
+        out = p == null ? System.out : p.getStream();
+    }
+
+    private static final ThreadLocal<LogStream> log = new ThreadLocal<LogStream>() {
+
+        @Override
+        protected LogStream initialValue() {
+            return new LogStream(out);
+        }
+    };
+
+    public static boolean isSuppressed() {
+        return log.get() == LogStream.SINK;
+    }
+
+    /**
+     * Gets the thread-local log stream to which the static methods of this class send their output.
+     * This will either be a global log stream or the global {@linkplain LogStream#SINK sink}
+     * depending on whether any suppression {@linkplain Filter filters} are in effect for the
+     * current thread.
+     */
+    public static LogStream out() {
+        return log.get();
+    }
+
+    /**
+     * @see LogStream#print(String)
+     */
+    public static void print(String s) {
+        out().print(s);
+    }
+
+    /**
+     * @see LogStream#print(int)
+     */
+    public static void print(int i) {
+        out().print(i);
+    }
+
+    /**
+     * @see LogStream#print(long)
+     */
+    public static void print(long i) {
+        out().print(i);
+    }
+
+    /**
+     * @see LogStream#print(char)
+     */
+    public static void print(char c) {
+        out().print(c);
+    }
+
+    /**
+     * @see LogStream#print(boolean)
+     */
+    public static void print(boolean b) {
+        out().print(b);
+    }
+
+    /**
+     * @see LogStream#print(double)
+     */
+    public static void print(double d) {
+        out().print(d);
+    }
+
+    /**
+     * @see LogStream#print(float)
+     */
+    public static void print(float f) {
+        out().print(f);
+    }
+
+    /**
+     * @see LogStream#println(String)
+     */
+    public static void println(String s) {
+        out().println(s);
+    }
+
+    /**
+     * @see LogStream#println()
+     */
+    public static void println() {
+        out().println();
+    }
+
+    /**
+     * @see LogStream#println(int)
+     */
+    public static void println(int i) {
+        out().println(i);
+    }
+
+    /**
+     * @see LogStream#println(long)
+     */
+    public static void println(long l) {
+        out().println(l);
+    }
+
+    /**
+     * @see LogStream#println(char)
+     */
+    public static void println(char c) {
+        out().println(c);
+    }
+
+    /**
+     * @see LogStream#println(boolean)
+     */
+    public static void println(boolean b) {
+        out().println(b);
+    }
+
+    /**
+     * @see LogStream#println(double)
+     */
+    public static void println(double d) {
+        out().println(d);
+    }
+
+    /**
+     * @see LogStream#println(float)
+     */
+    public static void println(float f) {
+        out().println(f);
+    }
+
+    public static void print(String format, Object... args) {
+        out().printf(format, args);
+    }
+
+    public static void println(String format, Object... args) {
+        out().printf(format + "%n", args);
+    }
+
+    public static void fillTo(int i) {
+        out().fillTo(i, ' ');
+    }
+
+    public static void printFields(Class<?> javaClass) {
+        final String className = javaClass.getSimpleName();
+        TTY.println(className + " {");
+        for (final Field field : javaClass.getFields()) {
+            printField(field, false);
+        }
+        TTY.println("}");
+    }
+
+    public static void printField(final Field field, boolean tabbed) {
+        final String fieldName = String.format("%35s", field.getName());
+        try {
+            String prefix = tabbed ? "" : "    " + fieldName + " = ";
+            String postfix = tabbed ? "\t" : "\n";
+            if (field.getType() == int.class) {
+                TTY.print(prefix + field.getInt(null) + postfix);
+            } else if (field.getType() == boolean.class) {
+                TTY.print(prefix + field.getBoolean(null) + postfix);
+            } else if (field.getType() == float.class) {
+                TTY.print(prefix + field.getFloat(null) + postfix);
+            } else if (field.getType() == String.class) {
+                TTY.print(prefix + field.get(null) + postfix);
+            } else if (field.getType() == Map.class) {
+                Map<?, ?> m = (Map<?, ?>) field.get(null);
+                TTY.print(prefix + printMap(m) + postfix);
+            } else {
+                TTY.print(prefix + field.get(null) + postfix);
+            }
+        } catch (IllegalAccessException e) {
+            // do nothing.
+        }
+    }
+
+    private static String printMap(Map<?, ?> m) {
+        StringBuilder sb = new StringBuilder();
+
+        List<String> keys = new ArrayList<>();
+        for (Object key : m.keySet()) {
+            keys.add((String) key);
+        }
+        Collections.sort(keys);
+
+        for (String key : keys) {
+            sb.append(key);
+            sb.append("\t");
+            sb.append(m.get(key));
+            sb.append("\n");
+        }
+
+        return sb.toString();
+    }
+
+    public static void flush() {
+        out().flush();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/TTYStreamProvider.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.debug;
+
+import java.io.*;
+
+/**
+ * Provides a {@link PrintStream} that writes to the underlying log stream of the VM.
+ */
+public interface TTYStreamProvider {
+    PrintStream getStream();
+}
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Wed Jul 29 11:59:18 2015 +0200
@@ -26,8 +26,6 @@
 import java.util.*;
 import java.util.concurrent.*;
 
-import jdk.internal.jvmci.debug.*;
-
 import com.oracle.graal.debug.*;
 
 public final class DebugScope implements Debug.Scope {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/MemUseTrackerImpl.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/MemUseTrackerImpl.java	Wed Jul 29 11:59:18 2015 +0200
@@ -23,8 +23,6 @@
 package com.oracle.graal.debug.internal;
 
 import static com.oracle.graal.debug.DebugCloseable.*;
-import jdk.internal.jvmci.debug.*;
-
 import com.oracle.graal.debug.*;
 
 public final class MemUseTrackerImpl extends AccumulatedDebugValue implements DebugMemUseTracker {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/TimerImpl.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/TimerImpl.java	Wed Jul 29 11:59:18 2015 +0200
@@ -27,8 +27,6 @@
 import java.lang.management.*;
 import java.util.concurrent.*;
 
-import jdk.internal.jvmci.debug.*;
-
 import com.oracle.graal.debug.*;
 
 public final class TimerImpl extends AccumulatedDebugValue implements DebugTimer {
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Wed Jul 29 11:59:18 2015 +0200
@@ -349,6 +349,7 @@
                 SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER));
             }
         }
+        masm.peephole();
     }
 
     private static int calculateConstantSize(LIR lir) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationStatistics.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationStatistics.java	Wed Jul 29 11:59:18 2015 +0200
@@ -30,9 +30,9 @@
 import java.util.*;
 import java.util.concurrent.*;
 
-import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.hotspot.*;
 
+import com.oracle.graal.debug.*;
 import com.sun.management.*;
 
 @SuppressWarnings("unused")
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Jul 29 11:59:18 2015 +0200
@@ -33,7 +33,6 @@
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.compiler.Compiler;
-import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.hotspot.*;
 import jdk.internal.jvmci.hotspot.events.*;
 import jdk.internal.jvmci.hotspot.events.EventProvider.CompilationEvent;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Wed Jul 29 11:59:18 2015 +0200
@@ -35,7 +35,6 @@
 import java.util.stream.*;
 
 import jdk.internal.jvmci.compiler.Compiler;
-import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.hotspot.*;
 import jdk.internal.jvmci.meta.*;
 import jdk.internal.jvmci.options.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DebugValuesPrinter.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DebugValuesPrinter.java	Wed Jul 29 11:59:18 2015 +0200
@@ -30,8 +30,8 @@
 import java.util.stream.*;
 
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
 
+import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.internal.*;
 
 /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Wed Jul 29 11:59:18 2015 +0200
@@ -23,9 +23,9 @@
 package com.oracle.graal.hotspot;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.debug.GraalDebugConfig.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.Options.*;
 import static jdk.internal.jvmci.common.UnsafeAccess.*;
-import static com.oracle.graal.debug.GraalDebugConfig.*;
 import static jdk.internal.jvmci.hotspot.InitTimer.*;
 
 import java.lang.reflect.*;
@@ -34,12 +34,7 @@
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.code.stack.*;
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
-
-import com.oracle.graal.debug.*;
-
 import jdk.internal.jvmci.hotspot.*;
-import jdk.internal.jvmci.hotspot.logging.*;
 import jdk.internal.jvmci.meta.*;
 import jdk.internal.jvmci.options.*;
 import jdk.internal.jvmci.runtime.*;
@@ -49,8 +44,10 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.debug.*;
+import com.oracle.graal.hotspot.logging.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.runtime.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalVMEventListener.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalVMEventListener.java	Wed Jul 29 11:59:18 2015 +0200
@@ -22,12 +22,15 @@
  */
 package com.oracle.graal.hotspot;
 
+import java.lang.reflect.*;
+import java.util.*;
+
 import jdk.internal.jvmci.code.*;
-import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.hotspot.*;
 import jdk.internal.jvmci.service.*;
 
 import com.oracle.graal.debug.*;
+import com.oracle.graal.hotspot.logging.*;
 
 @ServiceProvider(HotSpotVMEventListener.class)
 public class HotSpotGraalVMEventListener implements HotSpotVMEventListener {
@@ -65,4 +68,36 @@
             Debug.log("%s", codeCache.disassemble(installedCode));
         }
     }
+
+    @Override
+    public CompilerToVM completeInitialization(HotSpotJVMCIRuntime runtime, CompilerToVM compilerToVM) {
+        CompilerToVM toVM = compilerToVM;
+        if (CountingProxy.ENABLED) {
+            toVM = CountingProxy.getProxy(CompilerToVM.class, toVM);
+        }
+        if (Logger.ENABLED) {
+            toVM = LoggingProxy.getProxy(CompilerToVM.class, toVM);
+        }
+
+        if (Boolean.valueOf(System.getProperty("jvmci.printconfig"))) {
+            printConfig(runtime.getConfig());
+        }
+
+        return toVM;
+    }
+
+    private static void printConfig(HotSpotVMConfig config) {
+        Field[] fields = config.getClass().getDeclaredFields();
+        Map<String, Field> sortedFields = new TreeMap<>();
+        for (Field f : fields) {
+            f.setAccessible(true);
+            sortedFields.put(f.getName(), f);
+        }
+        for (Field f : sortedFields.values()) {
+            try {
+                Logger.info(String.format("%9s %-40s = %s", f.getType().getSimpleName(), f.getName(), Logger.pretty(f.get(config))));
+            } catch (Exception e) {
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Wed Jul 29 11:59:18 2015 +0200
@@ -29,11 +29,10 @@
 import java.util.concurrent.atomic.*;
 
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
-
 import jdk.internal.jvmci.hotspot.*;
 import jdk.internal.jvmci.options.*;
 
+import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.debug.*;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/CountingProxy.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.logging;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+
+import com.oracle.graal.debug.*;
+
+/**
+ * A java.lang.reflect proxy that hierarchically logs all method invocations along with their
+ * parameters and return values.
+ */
+public class CountingProxy<T> implements InvocationHandler {
+
+    public static final boolean ENABLED = Boolean.valueOf(System.getProperty("jvmci.countcalls"));
+
+    private T delegate;
+
+    private ConcurrentHashMap<Method, AtomicLong> calls = new ConcurrentHashMap<>();
+
+    public CountingProxy(T delegate) {
+        assert ENABLED;
+        TTY.println("Counting proxy for " + delegate.getClass().getSimpleName() + " created");
+        this.delegate = delegate;
+        proxies.add(this);
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        int argCount = args == null ? 0 : args.length;
+        if (method.getParameterTypes().length != argCount) {
+            throw new RuntimeException("wrong parameter count");
+        }
+        final Object result;
+        if (!calls.containsKey(method)) {
+            calls.putIfAbsent(method, new AtomicLong(0));
+        }
+        AtomicLong count = calls.get(method);
+        count.incrementAndGet();
+        try {
+            if (args == null) {
+                result = method.invoke(delegate);
+            } else {
+                result = method.invoke(delegate, args);
+            }
+        } catch (InvocationTargetException e) {
+            throw e.getCause();
+        }
+        return result;
+    }
+
+    public static <T> T getProxy(Class<T> interf, T delegate) {
+        Class<?>[] interfaces = ProxyUtil.getAllInterfaces(delegate.getClass());
+        Object obj = Proxy.newProxyInstance(interf.getClassLoader(), interfaces, new CountingProxy<>(delegate));
+        return interf.cast(obj);
+    }
+
+    private static ArrayList<CountingProxy<?>> proxies = new ArrayList<>();
+
+    static {
+        if (ENABLED) {
+            Runtime.getRuntime().addShutdownHook(new Thread() {
+
+                @Override
+                public void run() {
+                    for (CountingProxy<?> proxy : proxies) {
+                        proxy.print();
+                    }
+                }
+            });
+        }
+    }
+
+    protected void print() {
+        long sum = 0;
+        for (Map.Entry<Method, AtomicLong> entry : calls.entrySet()) {
+            Method method = entry.getKey();
+            long count = entry.getValue().get();
+            sum += count;
+            TTY.println(delegate.getClass().getSimpleName() + "." + method.getName() + ": " + count);
+        }
+        TTY.println(delegate.getClass().getSimpleName() + " calls: " + sum);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/HotSpotTTYStreamProvider.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.logging;
+
+import java.io.*;
+
+import com.oracle.graal.debug.*;
+
+import jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*;
+import jdk.internal.jvmci.service.*;
+
+@ServiceProvider(TTYStreamProvider.class)
+class HotSpotTTYStreamProvider implements TTYStreamProvider {
+
+    public PrintStream getStream() {
+        return Options.LogFile.getStream();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/Logger.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.logging;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+
+import jdk.internal.jvmci.hotspot.*;
+
+/**
+ * Scoped logging class used to display the call hierarchy of {@link CompilerToVM} calls.
+ */
+public class Logger {
+
+    public static final boolean ENABLED = Boolean.valueOf(System.getProperty("jvmci.debug"));
+    private static final int SPACING = 4;
+    private static final ThreadLocal<Logger> loggerTL;
+
+    private Deque<Boolean> openStack = new LinkedList<>();
+    private boolean open = false;
+    private int level = 0;
+
+    private static final PrintStream out;
+
+    static {
+        if (ENABLED) {
+            loggerTL = new ThreadLocal<Logger>() {
+
+                @Override
+                protected Logger initialValue() {
+                    return new Logger();
+                }
+            };
+        } else {
+            loggerTL = null;
+        }
+
+        PrintStream ps = null;
+        String filename = System.getProperty("jvmci.info_file");
+        if (filename != null && !"".equals(filename)) {
+            try {
+                ps = new PrintStream(new FileOutputStream(filename));
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+                ps = null;
+            }
+        }
+        out = ps;
+        if (out != null) {
+            out.println("start: " + new Date());
+        }
+    }
+
+    public static void info(String message) {
+        if (ENABLED) {
+            log(message);
+        } else {
+            TTY.println(message);
+        }
+        if (out != null) {
+            out.println(message);
+            out.flush();
+        }
+    }
+
+    public static void log(String message) {
+        if (ENABLED) {
+            Logger logger = loggerTL.get();
+            for (String line : message.split("\n")) {
+                if (logger.open) {
+                    TTY.println("...");
+                    logger.open = false;
+                }
+                TTY.print(space(logger.level));
+                TTY.println(line);
+            }
+        }
+    }
+
+    public static void startScope(String message) {
+        if (ENABLED) {
+            Logger logger = loggerTL.get();
+            if (logger.open) {
+                TTY.println("...");
+                logger.open = false;
+            }
+            TTY.print(space(logger.level));
+            TTY.print(message);
+            logger.openStack.push(logger.open);
+            logger.open = true;
+            logger.level++;
+        }
+    }
+
+    public static void endScope(String message) {
+        if (ENABLED) {
+            Logger logger = loggerTL.get();
+            logger.level--;
+            if (logger.open) {
+                TTY.println(message);
+            } else {
+                TTY.println(space(logger.level) + "..." + message);
+            }
+            logger.open = logger.openStack.pop();
+        }
+    }
+
+    private static String[] spaces = new String[50];
+
+    private static String space(int count) {
+        assert count >= 0;
+        String result;
+        if (count >= spaces.length || spaces[count] == null) {
+            StringBuilder str = new StringBuilder();
+            for (int i = 0; i < count * SPACING; i++) {
+                str.append(' ');
+            }
+            result = str.toString();
+            if (count < spaces.length) {
+                spaces[count] = result;
+            }
+        } else {
+            result = spaces[count];
+        }
+        return result;
+    }
+
+    public static String pretty(Object value) {
+        if (value == null) {
+            return "null";
+        }
+
+        Class<?> klass = value.getClass();
+        if (value instanceof Void) {
+            return "void";
+        } else if (value instanceof String) {
+            return "\"" + value + "\"";
+        } else if (value instanceof Method) {
+            return "method \"" + ((Method) value).getName() + "\"";
+        } else if (value instanceof Class<?>) {
+            return "class \"" + ((Class<?>) value).getSimpleName() + "\"";
+        } else if (value instanceof Integer) {
+            if ((Integer) value < 10) {
+                return value.toString();
+            }
+            return value + " (0x" + Integer.toHexString((Integer) value) + ")";
+        } else if (value instanceof Long) {
+            if ((Long) value < 10 && (Long) value > -10) {
+                return value + "l";
+            }
+            return value + "l (0x" + Long.toHexString((Long) value) + "l)";
+        } else if (klass.isArray()) {
+            StringBuilder str = new StringBuilder();
+            int dimensions = 0;
+            while (klass.isArray()) {
+                dimensions++;
+                klass = klass.getComponentType();
+            }
+            int length = Array.getLength(value);
+            str.append(klass.getSimpleName()).append('[').append(length).append(']');
+            for (int i = 1; i < dimensions; i++) {
+                str.append("[]");
+            }
+            str.append(" {");
+            for (int i = 0; i < length; i++) {
+                str.append(pretty(Array.get(value, i)));
+                if (i < length - 1) {
+                    str.append(", ");
+                }
+            }
+            str.append('}');
+            return str.toString();
+        }
+
+        return value.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/LoggingProxy.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.logging;
+
+import java.lang.reflect.*;
+
+/**
+ * A java.lang.reflect proxy that hierarchically logs all method invocations along with their
+ * parameters and return values.
+ */
+public class LoggingProxy<T> implements InvocationHandler {
+
+    private T delegate;
+
+    public LoggingProxy(T delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        int argCount = args == null ? 0 : args.length;
+        if (method.getParameterTypes().length != argCount) {
+            throw new RuntimeException("wrong parameter count");
+        }
+        StringBuilder str = new StringBuilder();
+        str.append(method.getReturnType().getSimpleName() + " " + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "(");
+        for (int i = 0; i < argCount; i++) {
+            str.append(i == 0 ? "" : ", ");
+            str.append(Logger.pretty(args[i]));
+        }
+        str.append(")");
+        Logger.startScope(str.toString());
+        final Object result;
+        try {
+            if (args == null) {
+                result = method.invoke(delegate);
+            } else {
+                result = method.invoke(delegate, args);
+            }
+        } catch (InvocationTargetException e) {
+            Logger.endScope(" = Exception " + e.getMessage());
+            throw e.getCause();
+        }
+        Logger.endScope(" = " + Logger.pretty(result));
+        return result;
+    }
+
+    /**
+     * The object returned by this method will implement all interfaces that are implemented by
+     * delegate.
+     */
+    public static <T> T getProxy(Class<T> interf, T delegate) {
+        Class<?>[] interfaces = ProxyUtil.getAllInterfaces(delegate.getClass());
+        Object obj = Proxy.newProxyInstance(interf.getClassLoader(), interfaces, new LoggingProxy<>(delegate));
+        return interf.cast(obj);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/ProxyUtil.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.logging;
+
+import java.util.*;
+
+public final class ProxyUtil {
+
+    public static Class<?>[] getAllInterfaces(Class<?> clazz) {
+        HashSet<Class<?>> interfaces = new HashSet<>();
+        getAllInterfaces(clazz, interfaces);
+        return interfaces.toArray(new Class<?>[interfaces.size()]);
+    }
+
+    private static void getAllInterfaces(Class<?> clazz, HashSet<Class<?>> interfaces) {
+        for (Class<?> iface : clazz.getInterfaces()) {
+            if (!interfaces.contains(iface)) {
+                interfaces.add(iface);
+                getAllInterfaces(iface, interfaces);
+            }
+        }
+        if (clazz.getSuperclass() != null) {
+            getAllInterfaces(clazz.getSuperclass(), interfaces);
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Wed Jul 29 11:59:18 2015 +0200
@@ -57,63 +57,63 @@
         }
     }
 
-    @Snippet(removeAllFrameStates = true)
+    @Snippet
     public static boolean[] booleanArrayClone(boolean[] src) {
         boolean[] result = (boolean[]) NewArrayNode.newUninitializedArray(Boolean.TYPE, src.length);
         ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Boolean);
         return result;
     }
 
-    @Snippet(removeAllFrameStates = true)
+    @Snippet
     public static byte[] byteArrayClone(byte[] src) {
         byte[] result = (byte[]) NewArrayNode.newUninitializedArray(Byte.TYPE, src.length);
         ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Byte);
         return result;
     }
 
-    @Snippet(removeAllFrameStates = true)
+    @Snippet
     public static short[] shortArrayClone(short[] src) {
         short[] result = (short[]) NewArrayNode.newUninitializedArray(Short.TYPE, src.length);
         ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Short);
         return result;
     }
 
-    @Snippet(removeAllFrameStates = true)
+    @Snippet
     public static char[] charArrayClone(char[] src) {
         char[] result = (char[]) NewArrayNode.newUninitializedArray(Character.TYPE, src.length);
         ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Char);
         return result;
     }
 
-    @Snippet(removeAllFrameStates = true)
+    @Snippet
     public static int[] intArrayClone(int[] src) {
         int[] result = (int[]) NewArrayNode.newUninitializedArray(Integer.TYPE, src.length);
         ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Int);
         return result;
     }
 
-    @Snippet(removeAllFrameStates = true)
+    @Snippet
     public static float[] floatArrayClone(float[] src) {
         float[] result = (float[]) NewArrayNode.newUninitializedArray(Float.TYPE, src.length);
         ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Float);
         return result;
     }
 
-    @Snippet(removeAllFrameStates = true)
+    @Snippet
     public static long[] longArrayClone(long[] src) {
         long[] result = (long[]) NewArrayNode.newUninitializedArray(Long.TYPE, src.length);
         ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Long);
         return result;
     }
 
-    @Snippet(removeAllFrameStates = true)
+    @Snippet
     public static double[] doubleArrayClone(double[] src) {
         double[] result = (double[]) NewArrayNode.newUninitializedArray(Double.TYPE, src.length);
         ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Double);
         return result;
     }
 
-    @Snippet(removeAllFrameStates = true)
+    @Snippet
     public static Object[] objectArrayClone(Object[] src) {
         /* Since this snippet is lowered early the array must be initialized */
         Object[] result = (Object[]) DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(src.getClass().getComponentType()), src.length, Kind.Object);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Wed Jul 29 11:59:18 2015 +0200
@@ -464,7 +464,7 @@
                         /*
                          * At least one array is of a known type requiring no store checks, so
                          * assume the other is of the same type. Generally this is working around
-                         * deficiencies in our propation of type information.
+                         * deficiencies in our propagation of type information.
                          */
                         componentKind = predictedKind;
                         if (predictedKind == Kind.Object) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Jul 29 11:59:18 2015 +0200
@@ -113,7 +113,7 @@
         return null;
     }
 
-    private class DebugScopeContext implements JavaMethod, JavaMethodContex {
+    private class DebugScopeContext implements JavaMethod, JavaMethodContext {
         public JavaMethod asJavaMethod() {
             return this;
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParser.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParser.java	Wed Jul 29 11:59:18 2015 +0200
@@ -38,8 +38,6 @@
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
 import jdk.internal.jvmci.compiler.Compiler;
-import jdk.internal.jvmci.debug.*;
-
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Wed Jul 29 11:59:18 2015 +0200
@@ -22,10 +22,6 @@
  */
 package com.oracle.graal.lir.sparc;
 
-import jdk.internal.jvmci.code.*;
-import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.meta.*;
-import jdk.internal.jvmci.sparc.*;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.*;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Annul.*;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.BranchPredict.*;
@@ -35,11 +31,15 @@
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 import static jdk.internal.jvmci.code.ValueUtil.*;
 import static jdk.internal.jvmci.sparc.SPARC.*;
-import static jdk.internal.jvmci.sparc.SPARC.CPUFeature.*;
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.common.*;
+import jdk.internal.jvmci.meta.*;
+import jdk.internal.jvmci.sparc.*;
 
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.gen.*;
@@ -414,7 +414,7 @@
                     Label noOverflow = new Label();
                     masm.sra(asIntReg(dst), 0, tmp);
                     masm.xorcc(SPARC.g0, SPARC.g0, SPARC.g0);
-                    if (masm.hasFeature(CBCOND)) {
+                    if (masm.hasFeature(SPARC.CPUFeature.CBCOND)) {
                         masm.cbcondx(Equal, tmp, asIntReg(dst), noOverflow);
                         // Is necessary, otherwise we will have a penalty of 5 cycles in S3
                         masm.nop();
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCByteSwapOp.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCByteSwapOp.java	Wed Jul 29 11:59:18 2015 +0200
@@ -41,7 +41,7 @@
     @Def({REG, HINT}) protected Value result;
     @Use({REG}) protected Value input;
     @Temp({REG}) protected Value tempIndex;
-    @Use({STACK}) protected StackSlotValue tmpSlot;
+    @Use({STACK, UNINITIALIZED}) protected StackSlotValue tmpSlot;
 
     public SPARCByteSwapOp(LIRGeneratorTool tool, Value result, Value input) {
         super(TYPE, SIZE);
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Wed Jul 29 11:59:18 2015 +0200
@@ -31,13 +31,13 @@
 import static com.oracle.graal.lir.sparc.SPARCMove.*;
 import static jdk.internal.jvmci.code.ValueUtil.*;
 import static jdk.internal.jvmci.sparc.SPARC.*;
-import static jdk.internal.jvmci.sparc.SPARC.CPUFeature.*;
 
 import java.util.*;
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
 import jdk.internal.jvmci.meta.*;
+import jdk.internal.jvmci.sparc.*;
 import jdk.internal.jvmci.sparc.SPARC.CPUFeature;
 
 import com.oracle.graal.asm.*;
@@ -310,12 +310,15 @@
 
     private static boolean isShortBranch(SPARCAssembler asm, int position, LabelHint hint, Label label) {
         int disp = 0;
+        boolean dispValid = true;
         if (label.isBound()) {
             disp = label.position() - position;
         } else if (hint != null && hint.isValid()) {
             disp = hint.getTarget() - hint.getPosition();
+        } else {
+            dispValid = false;
         }
-        if (disp != 0) {
+        if (dispValid) {
             if (disp < 0) {
                 disp -= maximumSelfOffsetInstructions * asm.target.wordSize;
             } else {
@@ -402,7 +405,8 @@
         @Alive({REG, ILLEGAL}) protected Value constantTableBase;
         @Temp({REG}) protected Value scratch;
         private final SwitchStrategy strategy;
-        private final LabelHint[] labelHints;
+        private final Map<Label, LabelHint> labelHints;
+        private final List<Label> conditionalLabels = new ArrayList<>();
 
         public StrategySwitchOp(Value constantTableBase, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
             super(TYPE);
@@ -413,7 +417,7 @@
             this.constantTableBase = constantTableBase;
             this.key = key;
             this.scratch = scratch;
-            this.labelHints = new LabelHint[keyTargets.length];
+            this.labelHints = new HashMap<>();
             assert keyConstants.length == keyTargets.length;
             assert keyConstants.length == strategy.keyProbabilities.length;
         }
@@ -423,9 +427,31 @@
             final Register keyRegister = asRegister(key);
             final Register constantBaseRegister = AllocatableValue.ILLEGAL.equals(constantTableBase) ? g0 : asRegister(constantTableBase);
             BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) {
+                int conditionalLabelPointer = 0;
+
+                /**
+                 * This method caches the generated labels over two assembly passes to get
+                 * information about branch lengths.
+                 */
+                @Override
+                public Label conditionalJump(int index, Condition condition) {
+                    Label label;
+                    if (conditionalLabelPointer <= conditionalLabels.size()) {
+                        label = new Label();
+                        conditionalLabels.add(label);
+                        conditionalLabelPointer = conditionalLabels.size();
+                    } else {
+                        // TODO: (sa) We rely here on the order how the labels are generated during
+                        // code generation; if the order is not stable ower two assembly passes, the
+                        // result can be wrong
+                        label = conditionalLabels.get(conditionalLabelPointer++);
+                    }
+                    conditionalJump(index, condition, label);
+                    return label;
+                }
+
                 @Override
                 protected void conditionalJump(int index, Condition condition, Label target) {
-                    requestHint(masm, index);
                     JavaConstant constant = keyConstants[index];
                     CC conditionCode;
                     Long bits;
@@ -451,10 +477,15 @@
                             throw new JVMCIError("switch only supported for int, long and object");
                     }
                     ConditionFlag conditionFlag = fromCondition(conditionCode, condition, false);
-                    LabelHint hint = labelHints[index];
-                    boolean canUseShortBranch = masm.hasFeature(CBCOND) && hint.isValid() && isShortBranch(masm, masm.position(), hint, target);
+                    LabelHint hint = requestHint(masm, target);
+                    boolean isShortConstant = isSimm5(constant);
+                    int cbCondPosition = masm.position();
+                    if (!isShortConstant) { // Load constant takes one instruction
+                        cbCondPosition += SPARC.INSTRUCTION_SIZE;
+                    }
+                    boolean canUseShortBranch = masm.hasFeature(CPUFeature.CBCOND) && isShortBranch(masm, cbCondPosition, hint, target);
                     if (bits != null && canUseShortBranch) {
-                        if (isSimm5(constant)) {
+                        if (isShortConstant) {
                             if (conditionCode == Icc) {
                                 masm.cbcondw(conditionFlag, keyRegister, (int) (long) bits, target);
                             } else {
@@ -485,8 +516,13 @@
             strategy.run(closure);
         }
 
-        private void requestHint(SPARCMacroAssembler masm, int index) {
-            labelHints[index] = masm.requestLabelHint(keyTargets[index].label());
+        private LabelHint requestHint(SPARCMacroAssembler masm, Label label) {
+            LabelHint hint = labelHints.get(label);
+            if (hint == null) {
+                hint = masm.requestLabelHint(label);
+                labelHints.put(label, hint);
+            }
+            return hint;
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/GenericValueMapTest.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.test;
+
+import static org.junit.Assert.*;
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.code.Register.RegisterCategory;
+import jdk.internal.jvmci.meta.*;
+
+import org.junit.*;
+
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.util.*;
+
+public class GenericValueMapTest {
+
+    @Test
+    public void run0() {
+        RegisterCategory cat = new RegisterCategory("regs");
+
+        RegisterValue reg = new Register(0, 0, "reg0", cat).asValue();
+        Variable var = new Variable(LIRKind.value(Kind.Long), 0);
+        Object obj0 = new Object();
+        Object obj1 = new Object();
+
+        GenericValueMap<Object> map = new GenericValueMap<>();
+
+        assertNull(map.get(reg));
+        assertNull(map.get(var));
+
+        map.put(reg, obj0);
+        map.put(var, obj1);
+
+        assertEquals(obj0, map.get(reg));
+        assertEquals(obj1, map.get(var));
+
+        map.remove(reg);
+        map.remove(var);
+
+        assertNull(map.get(reg));
+        assertNull(map.get(var));
+
+        map.put(reg, obj0);
+        map.put(var, obj1);
+
+        map.put(var, obj0);
+        map.put(reg, obj1);
+
+        assertEquals(obj1, map.get(reg));
+        assertEquals(obj0, map.get(var));
+
+        map.put(reg, null);
+        map.put(var, null);
+
+        assertNull(map.get(reg));
+        assertNull(map.get(var));
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Wed Jul 29 11:59:18 2015 +0200
@@ -31,8 +31,8 @@
 
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.dfa.*;
 import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.util.*;
 
 /**
  * This class represents garbage collection and deoptimization information attached to a LIR
@@ -45,7 +45,7 @@
     public final LabelRef exceptionEdge;
     protected DebugInfo debugInfo;
 
-    private ValueSet liveBasePointers;
+    private IndexedValueMap liveBasePointers;
 
     public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge) {
         this.topFrame = topFrame;
@@ -181,11 +181,11 @@
         debugInfo = new DebugInfo(topFrame, virtualObjects);
     }
 
-    public ValueSet getLiveBasePointers() {
+    public IndexedValueMap getLiveBasePointers() {
         return liveBasePointers;
     }
 
-    public void setLiveBasePointers(ValueSet liveBasePointers) {
+    public void setLiveBasePointers(IndexedValueMap liveBasePointers) {
         this.liveBasePointers = liveBasePointers;
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Wed Jul 29 11:59:18 2015 +0200
@@ -29,11 +29,10 @@
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
-
 import jdk.internal.jvmci.meta.*;
 
 import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.framemap.*;
@@ -132,7 +131,7 @@
                 assert last instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump";
             }
             if (block.getPredecessorCount() > 1) {
-                SSAUtils.verifyPhi(lir, block);
+                SSAUtil.verifyPhi(lir, block);
             }
 
             for (LIRInstruction op : lir.getLIRforBlock(block)) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Interval.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Interval.java	Wed Jul 29 11:59:18 2015 +0200
@@ -30,11 +30,10 @@
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
-
 import jdk.internal.jvmci.meta.*;
 
 import com.oracle.graal.compiler.common.util.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.*;
 
 /**
@@ -292,7 +291,7 @@
     /**
      * Constants used in optimization of spilling of an interval.
      */
-    enum SpillState {
+    public enum SpillState {
         /**
          * Starting state of calculation: no definition found yet.
          */
@@ -569,7 +568,7 @@
         return kind;
     }
 
-    void setKind(LIRKind kind) {
+    public void setKind(LIRKind kind) {
         assert isRegister(operand) || this.kind().equals(LIRKind.Illegal) || this.kind().equals(kind) : "overwriting existing type";
         this.kind = kind;
     }
@@ -578,7 +577,7 @@
         return first;
     }
 
-    int from() {
+    public int from() {
         return first.from;
     }
 
@@ -594,11 +593,11 @@
         return usePosList.size();
     }
 
-    void setLocationHint(Interval interval) {
+    public void setLocationHint(Interval interval) {
         locationHint = interval;
     }
 
-    boolean isSplitParent() {
+    public boolean isSplitParent() {
         return splitParent == this;
     }
 
@@ -647,22 +646,22 @@
         return splitParent().spillState;
     }
 
-    int spillDefinitionPos() {
+    public int spillDefinitionPos() {
         return splitParent().spillDefinitionPos;
     }
 
-    void setSpillState(SpillState state) {
+    public void setSpillState(SpillState state) {
         assert state.ordinal() >= spillState().ordinal() : "state cannot decrease";
         splitParent().spillState = state;
     }
 
-    void setSpillDefinitionPos(int pos) {
-        assert spillState() == SpillState.SpillInDominator || spillDefinitionPos() == -1 : "cannot set the position twice";
+    public void setSpillDefinitionPos(int pos) {
+        assert spillState() == SpillState.SpillInDominator || spillState() == SpillState.NoDefinitionFound || spillDefinitionPos() == -1 : "cannot set the position twice";
         splitParent().spillDefinitionPos = pos;
     }
 
     // returns true if this interval has a shadow copy on the stack that is always correct
-    boolean alwaysInMemory() {
+    public boolean alwaysInMemory() {
         return (splitParent().spillState == SpillState.SpillInDominator || splitParent().spillState == SpillState.StoreAtDefinition || splitParent().spillState == SpillState.StartInMemory) &&
                         !canMaterialize();
     }
@@ -739,7 +738,7 @@
     /**
      * Sets the value which is used for re-materialization.
      */
-    void addMaterializationValue(JavaConstant value) {
+    public void addMaterializationValue(JavaConstant value) {
         if (numMaterializationValuesAdded == 0) {
             materializedValue = value;
         } else {
@@ -1013,7 +1012,7 @@
     int previousUsage(RegisterPriority minRegisterPriority, int from) {
         assert isVariable(operand) : "cannot access use positions for fixed intervals";
 
-        int prev = 0;
+        int prev = -1;
         for (int i = usePosList.size() - 1; i >= 0; --i) {
             int usePos = usePosList.usePos(i);
             if (usePos > from) {
@@ -1026,8 +1025,8 @@
         return prev;
     }
 
-    void addUsePos(int pos, RegisterPriority registerPriority) {
-        assert covers(pos, LIRInstruction.OperandMode.USE) : "use position not covered by live range";
+    public void addUsePos(int pos, RegisterPriority registerPriority) {
+        assert covers(pos, LIRInstruction.OperandMode.USE) : String.format("use position %d not covered by live range of interval %s", pos, this);
 
         // do not add use positions for precolored intervals because they are never used
         if (registerPriority != RegisterPriority.None && isVariable(operand)) {
@@ -1052,7 +1051,7 @@
         }
     }
 
-    void addRange(int from, int to) {
+    public void addRange(int from, int to) {
         assert from < to : "invalid range";
         assert first() == Range.EndMarker || to < first().next.from : "not inserting at begin of interval";
         assert from <= first().to : "not inserting at begin of interval";
@@ -1283,7 +1282,7 @@
         buf.append("} uses{");
 
         // print use positions
-        int prev = 0;
+        int prev = -1;
         for (int i = usePosList.size() - 1; i >= 0; --i) {
             assert prev < usePosList.usePos(i) : "use positions not sorted";
             if (i != usePosList.size() - 1) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Wed Jul 29 11:59:18 2015 +0200
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.lir.LIRValueUtil.*;
+import static com.oracle.graal.lir.phases.LIRPhase.Options.*;
 import static jdk.internal.jvmci.code.CodeUtil.*;
 import static jdk.internal.jvmci.code.ValueUtil.*;
 
@@ -31,13 +32,13 @@
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.*;
 import jdk.internal.jvmci.meta.*;
 import jdk.internal.jvmci.options.*;
 
 import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
@@ -53,25 +54,12 @@
  * >"Optimized Interval Splitting in a Linear Scan Register Allocator"</a> by Christian Wimmer and
  * Hanspeter Moessenboeck.
  */
-class LinearScan {
-
-    final LIRGenerationResult res;
-    final LIR ir;
-    final FrameMapBuilder frameMapBuilder;
-    final RegisterAttributes[] registerAttributes;
-    final Register[] registers;
-    final RegisterAllocationConfig regAllocConfig;
-    private final SpillMoveFactory moveFactory;
-
-    final boolean callKillsRegisters;
-
-    public static final int DOMINATOR_SPILL_MOVE_ID = -2;
-    static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1;
+public class LinearScan {
 
     public static class Options {
         // @formatter:off
         @Option(help = "Enable spill position optimization", type = OptionType.Debug)
-        public static final OptionValue<Boolean> LSRAOptimizeSpillPosition = new OptionValue<>(true);
+        public static final OptionValue<Boolean> LIROptLSRAOptimizeSpillPosition = new NestedBooleanOptionValue(LIROptimization, true);
         // @formatter:on
     }
 
@@ -107,12 +95,22 @@
         public BitSet liveKill;
     }
 
+    public static final int DOMINATOR_SPILL_MOVE_ID = -2;
+    private static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1;
+
+    private final LIR ir;
+    private final FrameMapBuilder frameMapBuilder;
+    private final RegisterAttributes[] registerAttributes;
+    private final Register[] registers;
+    private final RegisterAllocationConfig regAllocConfig;
+    private final SpillMoveFactory moveFactory;
+
     private final BlockMap<BlockData> blockData;
 
     /**
      * List of blocks in linear-scan order. This is only correct as long as the CFG does not change.
      */
-    final List<? extends AbstractBlockBase<?>> sortedBlocks;
+    private final List<? extends AbstractBlockBase<?>> sortedBlocks;
 
     /** @see #intervals() */
     private Interval[] intervals;
@@ -152,8 +150,8 @@
      */
     private final int firstVariableNumber;
 
-    LinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, List<? extends AbstractBlockBase<?>> sortedBlocks) {
-        this.res = res;
+    protected LinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig,
+                    List<? extends AbstractBlockBase<?>> sortedBlocks) {
         this.ir = res.getLIR();
         this.moveFactory = spillMoveFactory;
         this.frameMapBuilder = res.getFrameMapBuilder();
@@ -162,30 +160,24 @@
         this.regAllocConfig = regAllocConfig;
 
         this.registers = target.arch.getRegisters();
-        this.firstVariableNumber = registers.length;
+        this.firstVariableNumber = getRegisters().length;
         this.blockData = new BlockMap<>(ir.getControlFlowGraph());
-
-        /*
-         * If all allocatable registers are caller saved, then no registers are live across a call
-         * site. The register allocator can save time not trying to find a register at a call site.
-         */
-        this.callKillsRegisters = regAllocConfig.getRegisterConfig().areAllAllocatableRegistersCallerSaved();
     }
 
-    int getFirstLirInstructionId(AbstractBlockBase<?> block) {
+    public int getFirstLirInstructionId(AbstractBlockBase<?> block) {
         int result = ir.getLIRforBlock(block).get(0).id();
         assert result >= 0;
         return result;
     }
 
-    int getLastLirInstructionId(AbstractBlockBase<?> block) {
+    public int getLastLirInstructionId(AbstractBlockBase<?> block) {
         List<LIRInstruction> instructions = ir.getLIRforBlock(block);
         int result = instructions.get(instructions.size() - 1).id();
         assert result >= 0;
         return result;
     }
 
-    SpillMoveFactory getSpillMoveFactory() {
+    public SpillMoveFactory getSpillMoveFactory() {
         return moveFactory;
     }
 
@@ -228,7 +220,7 @@
         return firstVariableNumber - 1;
     }
 
-    BlockData getBlockData(AbstractBlockBase<?> block) {
+    public BlockData getBlockData(AbstractBlockBase<?> block) {
         return blockData.get(block);
     }
 
@@ -264,7 +256,7 @@
      * Gets an object describing the attributes of a given register according to this register
      * configuration.
      */
-    RegisterAttributes attributes(Register reg) {
+    public RegisterAttributes attributes(Register reg) {
         return registerAttributes[reg.number];
     }
 
@@ -287,7 +279,7 @@
     /**
      * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
      */
-    Interval[] intervals() {
+    public Interval[] intervals() {
         return intervals;
     }
 
@@ -334,11 +326,11 @@
     }
 
     // access to block list (sorted in linear scan order)
-    int blockCount() {
+    public int blockCount() {
         return sortedBlocks.size();
     }
 
-    AbstractBlockBase<?> blockAt(int index) {
+    public AbstractBlockBase<?> blockAt(int index) {
         return sortedBlocks.get(index);
     }
 
@@ -347,7 +339,7 @@
      * block. These sets do not include any operands allocated as a result of creating
      * {@linkplain #createDerivedInterval(Interval) derived intervals}.
      */
-    int liveSetSize() {
+    public int liveSetSize() {
         return firstDerivedIntervalIndex == -1 ? operandSize() : firstDerivedIntervalIndex;
     }
 
@@ -359,13 +351,13 @@
         return intervals[operandNumber];
     }
 
-    Interval intervalFor(Value operand) {
+    public Interval intervalFor(Value operand) {
         int operandNumber = operandNumber(operand);
         assert operandNumber < intervalsSize;
         return intervals[operandNumber];
     }
 
-    Interval getOrCreateInterval(AllocatableValue operand) {
+    public Interval getOrCreateInterval(AllocatableValue operand) {
         Interval ret = intervalFor(operand);
         if (ret == null) {
             return createInterval(operand);
@@ -407,7 +399,7 @@
      * @param opId an instruction {@linkplain LIRInstruction#id id}
      * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id}
      */
-    LIRInstruction instructionForId(int opId) {
+    public LIRInstruction instructionForId(int opId) {
         assert isEven(opId) : "opId not even";
         LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)];
         assert instr.id() == opId;
@@ -420,7 +412,7 @@
      * @param opId an instruction {@linkplain LIRInstruction#id id}
      * @return the block containing the instruction denoted by {@code opId}
      */
-    AbstractBlockBase<?> blockForId(int opId) {
+    public AbstractBlockBase<?> blockForId(int opId) {
         assert opIdToBlockMap.length > 0 && opId >= 0 && opId <= maxOpId() + 1 : "opId out of range";
         return opIdToBlockMap[opIdToIndex(opId)];
     }
@@ -450,7 +442,7 @@
         abstract boolean apply(Interval i);
     }
 
-    boolean isProcessed(Value operand) {
+    public boolean isProcessed(Value operand) {
         return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable();
     }
 
@@ -515,7 +507,7 @@
         return new Interval.Pair(list1, list2);
     }
 
-    void sortIntervalsBeforeAllocation() {
+    protected void sortIntervalsBeforeAllocation() {
         int sortedLen = 0;
         for (Interval interval : intervals) {
             if (interval != null) {
@@ -585,7 +577,7 @@
 
     // wrapper for Interval.splitChildAtOpId that performs a bailout in product mode
     // instead of returning null
-    Interval splitChildAtOpId(Interval interval, int opId, LIRInstruction.OperandMode mode) {
+    public Interval splitChildAtOpId(Interval interval, int opId, LIRInstruction.OperandMode mode) {
         Interval result = interval.getSplitChildAtOpId(opId, mode, this);
 
         if (result != null) {
@@ -622,8 +614,8 @@
         return attributes(asRegister(operand)).isCallerSave();
     }
 
-    <B extends AbstractBlockBase<B>> void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    SpillMoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) {
 
         /*
          * This is the point to enable debug logging for the whole register allocation.
@@ -638,7 +630,7 @@
 
                 createRegisterAllocationPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
 
-                if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) {
+                if (LinearScan.Options.LIROptLSRAOptimizeSpillPosition.getValue()) {
                     createOptimizeSpillPositionPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
                 }
                 createResolveDataFlowPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
@@ -688,7 +680,7 @@
         return new LinearScanAssignLocationsPhase(this);
     }
 
-    void printIntervals(String label) {
+    public void printIntervals(String label) {
         if (Debug.isLogEnabled()) {
             try (Indent indent = Debug.logAndIndent("intervals %s", label)) {
                 for (Interval interval : intervals) {
@@ -708,7 +700,7 @@
         Debug.dump(Arrays.copyOf(intervals, intervalsSize), label);
     }
 
-    void printLir(String label, @SuppressWarnings("unused") boolean hirValid) {
+    public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) {
         Debug.dump(ir, label);
     }
 
@@ -731,7 +723,7 @@
         }
     }
 
-    void verifyIntervals() {
+    protected void verifyIntervals() {
         try (Indent indent = Debug.logAndIndent("verifying intervals")) {
             int len = intervalsSize;
 
@@ -872,4 +864,28 @@
         }
     }
 
+    public LIR getLIR() {
+        return ir;
+    }
+
+    public FrameMapBuilder getFrameMapBuilder() {
+        return frameMapBuilder;
+    }
+
+    public List<? extends AbstractBlockBase<?>> sortedBlocks() {
+        return sortedBlocks;
+    }
+
+    public Register[] getRegisters() {
+        return registers;
+    }
+
+    public RegisterAllocationConfig getRegisterAllocationConfig() {
+        return regAllocConfig;
+    }
+
+    public boolean callKillsRegisters() {
+        return regAllocConfig.getRegisterConfig().areAllAllocatableRegistersCallerSaved();
+    }
+
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanAssignLocationsPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanAssignLocationsPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -45,7 +45,7 @@
 /**
  * Phase 7: Assign register numbers back to LIR.
  */
-final class LinearScanAssignLocationsPhase extends AllocationPhase {
+public final class LinearScanAssignLocationsPhase extends AllocationPhase {
 
     private final LinearScan allocator;
 
@@ -80,7 +80,7 @@
                      * before the branch instruction. So the split child information for this branch
                      * would be incorrect.
                      */
-                    LIRInstruction instr = allocator.ir.getLIRforBlock(block).get(allocator.ir.getLIRforBlock(block).size() - 1);
+                    LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1);
                     if (instr instanceof StandardOp.JumpOp) {
                         if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) {
                             assert false : String.format(
@@ -125,10 +125,10 @@
              * is a branch, spill moves are inserted before this branch and so the wrong operand
              * would be returned (spill moves at block boundaries are not considered in the live
              * ranges of intervals).
-             *
+             * 
              * Solution: use the first opId of the branch target block instead.
              */
-            final LIRInstruction instr = allocator.ir.getLIRforBlock(block).get(allocator.ir.getLIRforBlock(block).size() - 1);
+            final LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1);
             if (instr instanceof StandardOp.JumpOp) {
                 if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) {
                     tempOpId = allocator.getFirstLirInstructionId(block.getSuccessors().iterator().next());
@@ -208,9 +208,9 @@
 
     private void assignLocations() {
         try (Indent indent = Debug.logAndIndent("assign locations")) {
-            for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
                 try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
-                    assignLocations(allocator.ir.getLIRforBlock(block));
+                    assignLocations(allocator.getLIR().getLIRforBlock(block));
                 }
             }
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -42,7 +42,7 @@
 import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.lir.phases.*;
 
-class LinearScanEliminateSpillMovePhase extends AllocationPhase {
+public class LinearScanEliminateSpillMovePhase extends AllocationPhase {
 
     private static final IntervalPredicate mustStoreAtDefinition = new LinearScan.IntervalPredicate() {
 
@@ -54,7 +54,7 @@
 
     protected final LinearScan allocator;
 
-    LinearScanEliminateSpillMovePhase(LinearScan allocator) {
+    protected LinearScanEliminateSpillMovePhase(LinearScan allocator) {
         this.allocator = allocator;
     }
 
@@ -88,9 +88,9 @@
             }
 
             LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer();
-            for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
                 try (Indent indent1 = Debug.logAndIndent("Handle %s", block)) {
-                    List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block);
+                    List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
                     int numInst = instructions.size();
 
                     // iterate all instructions of the block.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -50,14 +50,14 @@
 import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.lir.phases.*;
 
-class LinearScanLifetimeAnalysisPhase extends AllocationPhase {
+public class LinearScanLifetimeAnalysisPhase extends AllocationPhase {
 
     protected final LinearScan allocator;
 
     /**
      * @param linearScan
      */
-    LinearScanLifetimeAnalysisPhase(LinearScan linearScan) {
+    protected LinearScanLifetimeAnalysisPhase(LinearScan linearScan) {
         allocator = linearScan;
     }
 
@@ -74,7 +74,7 @@
     /**
      * Bit set for each variable that is contained in each loop.
      */
-    BitMap2D intervalInLoop;
+    private BitMap2D intervalInLoop;
 
     boolean isIntervalInLoop(int interval, int loop) {
         return intervalInLoop.at(interval, loop);
@@ -84,7 +84,7 @@
      * Numbers all instructions in all blocks. The numbering follows the
      * {@linkplain ComputeBlockOrder linear scan order}.
      */
-    void numberInstructions() {
+    protected void numberInstructions() {
 
         allocator.initIntervals();
 
@@ -96,8 +96,8 @@
 
         // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node.
         int numInstructions = 0;
-        for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
-            numInstructions += allocator.ir.getLIRforBlock(block).size();
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+            numInstructions += allocator.getLIR().getLIRforBlock(block).size();
         }
 
         // initialize with correct length
@@ -105,10 +105,10 @@
 
         int opId = 0;
         int index = 0;
-        for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
             allocator.initBlockData(block);
 
-            List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block);
+            List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
 
             int numInst = instructions.size();
             for (int j = 0; j < numInst; j++) {
@@ -139,13 +139,13 @@
         intervalInLoop = new BitMap2D(allocator.operandSize(), allocator.numLoops());
 
         // iterate all blocks
-        for (final AbstractBlockBase<?> block : allocator.sortedBlocks) {
+        for (final AbstractBlockBase<?> block : allocator.sortedBlocks()) {
             try (Indent indent = Debug.logAndIndent("compute local live sets for block %s", block)) {
 
                 final BitSet liveGen = new BitSet(liveSize);
                 final BitSet liveKill = new BitSet(liveSize);
 
-                List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block);
+                List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
                 int numInst = instructions.size();
 
                 ValueConsumer useConsumer = (operand, mode, flags) -> {
@@ -249,7 +249,7 @@
          * sets. This is checked by these assertions to be sure about it. The entry block may have
          * incoming values in registers, which is ok.
          */
-        if (isRegister(operand) && block != allocator.ir.getControlFlowGraph().getStartBlock()) {
+        if (isRegister(operand) && block != allocator.getLIR().getControlFlowGraph().getStartBlock()) {
             if (allocator.isProcessed(operand)) {
                 assert liveKill.get(allocator.operandNumber(operand)) : "using fixed register that is not defined in this block";
             }
@@ -260,7 +260,7 @@
      * Performs a backward dataflow analysis to compute global live sets (i.e.
      * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block.
      */
-    void computeGlobalLiveSets() {
+    protected void computeGlobalLiveSets() {
         try (Indent indent = Debug.logAndIndent("compute global live sets")) {
             int numBlocks = allocator.blockCount();
             boolean changeOccurred;
@@ -313,7 +313,7 @@
                             /*
                              * liveIn(block) is the union of liveGen(block) with (liveOut(block) &
                              * !liveKill(block)).
-                             *
+                             * 
                              * Note: liveIn has to be computed only in first iteration or if liveOut
                              * has changed!
                              */
@@ -341,7 +341,7 @@
             }
 
             // check that the liveIn set of the first block is empty
-            AbstractBlockBase<?> startBlock = allocator.ir.getControlFlowGraph().getStartBlock();
+            AbstractBlockBase<?> startBlock = allocator.getLIR().getControlFlowGraph().getStartBlock();
             if (allocator.getBlockData(startBlock).liveIn.cardinality() != 0) {
                 if (DetailedAsserts.getValue()) {
                     reportFailure(numBlocks);
@@ -352,11 +352,11 @@
         }
     }
 
-    private void reportFailure(int numBlocks) {
+    protected void reportFailure(int numBlocks) {
         try (Scope s = Debug.forceLog()) {
             try (Indent indent = Debug.logAndIndent("report failure")) {
 
-                BitSet startBlockLiveIn = allocator.getBlockData(allocator.ir.getControlFlowGraph().getStartBlock()).liveIn;
+                BitSet startBlockLiveIn = allocator.getBlockData(allocator.getLIR().getControlFlowGraph().getStartBlock()).liveIn;
                 try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) {
                     for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
                         Interval interval = allocator.intervalFor(operandNum);
@@ -382,11 +382,11 @@
 
                         Deque<AbstractBlockBase<?>> definedIn = new ArrayDeque<>();
                         HashSet<AbstractBlockBase<?>> usedIn = new HashSet<>();
-                        for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+                        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
                             if (allocator.getBlockData(block).liveGen.get(operandNum)) {
                                 usedIn.add(block);
                                 try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) {
-                                    for (LIRInstruction ins : allocator.ir.getLIRforBlock(block)) {
+                                    for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) {
                                         try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) {
                                             ins.forEachState((liveStateOperand, mode, flags) -> {
                                                 Debug.log("operand=%s", liveStateOperand);
@@ -399,7 +399,7 @@
                             if (allocator.getBlockData(block).liveKill.get(operandNum)) {
                                 definedIn.add(block);
                                 try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) {
-                                    for (LIRInstruction ins : allocator.ir.getLIRforBlock(block)) {
+                                    for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) {
                                         Debug.log("%d: %s", ins.id(), ins);
                                     }
                                 }
@@ -436,12 +436,12 @@
         }
     }
 
-    private void verifyLiveness() {
+    protected void verifyLiveness() {
         /*
          * Check that fixed intervals are not live at block boundaries (live set must be empty at
          * fixed intervals).
          */
-        for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
             for (int j = 0; j <= allocator.maxRegisterNumber(); j++) {
                 assert !allocator.getBlockData(block).liveIn.get(j) : "liveIn  set of fixed register must be empty";
                 assert !allocator.getBlockData(block).liveOut.get(j) : "liveOut set of fixed register must be empty";
@@ -450,7 +450,7 @@
         }
     }
 
-    void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
+    protected void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
         if (!allocator.isProcessed(operand)) {
             return;
         }
@@ -470,7 +470,7 @@
         }
     }
 
-    void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
+    protected void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
         if (!allocator.isProcessed(operand)) {
             return;
         }
@@ -489,7 +489,7 @@
         }
     }
 
-    void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
+    protected void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
         if (!allocator.isProcessed(operand)) {
             return;
         }
@@ -520,7 +520,7 @@
             }
         }
 
-        changeSpillDefinitionPos(interval, defPos);
+        changeSpillDefinitionPos(op, operand, interval, defPos);
         if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) {
             // detection of method-parameters and roundfp-results
             interval.setSpillState(SpillState.StartInMemory);
@@ -536,7 +536,7 @@
      * Optimizes moves related to incoming stack based arguments. The interval for the destination
      * of such moves is assigned the stack slot (which is in the caller's frame) as its spill slot.
      */
-    void handleMethodArguments(LIRInstruction op) {
+    protected void handleMethodArguments(LIRInstruction op) {
         if (op instanceof MoveOp) {
             MoveOp move = (MoveOp) op;
             if (optimizeMethodArgument(move.getInput())) {
@@ -564,7 +564,7 @@
         }
     }
 
-    void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
+    protected void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
         if (flags.contains(OperandFlag.HINT) && LinearScan.isVariableOrRegister(targetValue)) {
 
             op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> {
@@ -591,8 +591,11 @@
 
     /**
      * Eliminates moves from register to stack if the stack slot is known to be correct.
+     *
+     * @param op
+     * @param operand
      */
-    void changeSpillDefinitionPos(Interval interval, int defPos) {
+    protected void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, Interval interval, int defPos) {
         assert interval.isSplitParent() : "can only be called for split parents";
 
         switch (interval.spillState()) {
@@ -651,7 +654,7 @@
      * Determines the priority which with an instruction's input operand will be allocated a
      * register.
      */
-    private static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
+    protected static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
         if (flags.contains(OperandFlag.STACK)) {
             return RegisterPriority.ShouldHaveRegister;
         }
@@ -659,7 +662,7 @@
         return RegisterPriority.MustHaveRegister;
     }
 
-    void buildIntervals() {
+    protected void buildIntervals() {
 
         try (Indent indent = Debug.logAndIndent("build intervals")) {
             InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
@@ -705,7 +708,7 @@
             };
 
             // create a list with all caller-save registers (cpu, fpu, xmm)
-            Register[] callerSaveRegs = allocator.regAllocConfig.getRegisterConfig().getCallerSaveRegisters();
+            Register[] callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters();
 
             // iterate all blocks in reverse order
             for (int i = allocator.blockCount() - 1; i >= 0; i--) {
@@ -713,7 +716,7 @@
                 AbstractBlockBase<?> block = allocator.blockAt(i);
                 try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
 
-                    List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block);
+                    List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
                     final int blockFrom = allocator.getFirstLirInstructionId(block);
                     int blockTo = allocator.getLastLirInstructionId(block);
 
@@ -808,7 +811,7 @@
      *         reload-locations in case the interval of this instruction is spilled. Currently this
      *         can only be a {@link JavaConstant}.
      */
-    static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) {
+    protected static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) {
         if (op instanceof MoveOp) {
             MoveOp move = (MoveOp) op;
             if (move.getInput() instanceof JavaConstant) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -40,7 +40,7 @@
 import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.lir.phases.*;
 
-final class LinearScanOptimizeSpillPositionPhase extends AllocationPhase {
+public final class LinearScanOptimizeSpillPositionPhase extends AllocationPhase {
 
     private static final DebugMetric betterSpillPos = Debug.metric("BetterSpillPosition");
     private static final DebugMetric betterSpillPosWithLowerProbability = Debug.metric("BetterSpillPositionWithLowerProbability");
@@ -60,7 +60,7 @@
 
     private void optimizeSpillPosition() {
         try (Indent indent0 = Debug.logAndIndent("OptimizeSpillPositions")) {
-            LIRInsertionBuffer[] insertionBuffers = new LIRInsertionBuffer[allocator.ir.linearScanOrder().size()];
+            LIRInsertionBuffer[] insertionBuffers = new LIRInsertionBuffer[allocator.getLIR().linearScanOrder().size()];
             for (Interval interval : allocator.intervals()) {
                 optimizeInterval(insertionBuffers, interval);
             }
@@ -118,7 +118,7 @@
             /*
              * The spill block is the begin of the first split child (aka the value is on the
              * stack).
-             * 
+             *
              * The problem is that if spill block has more than one predecessor, the values at the
              * end of the predecessors might differ. Therefore, we would need a spill move in all
              * predecessors. To avoid this we spill in the dominator.
@@ -154,7 +154,7 @@
             if (insertionBuffer == null) {
                 insertionBuffer = new LIRInsertionBuffer();
                 insertionBuffers[spillBlock.getId()] = insertionBuffer;
-                insertionBuffer.init(allocator.ir.getLIRforBlock(spillBlock));
+                insertionBuffer.init(allocator.getLIR().getLIRforBlock(spillBlock));
             }
             int spillOpId = allocator.getFirstLirInstructionId(spillBlock);
             // insert spill move
@@ -189,8 +189,8 @@
         public AbstractBlockBase<?> next() {
             AbstractBlockBase<?> currentBlock = block;
             int nextBlockIndex = block.getLinearScanNumber() + 1;
-            if (nextBlockIndex < allocator.sortedBlocks.size()) {
-                block = allocator.sortedBlocks.get(nextBlockIndex);
+            if (nextBlockIndex < allocator.sortedBlocks().size()) {
+                block = allocator.sortedBlocks().get(nextBlockIndex);
                 if (range.to <= allocator.getFirstLirInstructionId(block)) {
                     range = range.next;
                     if (range == Range.EndMarker) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -31,6 +31,8 @@
 
 import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.alloc.lsra.ssa.*;
+import com.oracle.graal.lir.alloc.lsra.ssi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.lir.phases.*;
@@ -42,6 +44,9 @@
                     RegisterAllocationConfig registerAllocationConfig) {
         final LinearScan allocator;
         switch (LinearScanVariant.getValue()) {
+            case SSI_LSRA:
+                allocator = new SSILinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, linearScanOrder);
+                break;
             case SSA_LSRA:
                 allocator = new SSALinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, linearScanOrder);
                 break;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -33,7 +33,7 @@
 import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.lir.phases.*;
 
-final class LinearScanRegisterAllocationPhase extends AllocationPhase {
+public final class LinearScanRegisterAllocationPhase extends AllocationPhase {
 
     private final LinearScan allocator;
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -41,11 +41,11 @@
  *
  * Insert moves at edges between blocks if intervals have been split.
  */
-class LinearScanResolveDataFlowPhase extends AllocationPhase {
+public class LinearScanResolveDataFlowPhase extends AllocationPhase {
 
     protected final LinearScan allocator;
 
-    LinearScanResolveDataFlowPhase(LinearScan allocator) {
+    protected LinearScanResolveDataFlowPhase(LinearScan allocator) {
         this.allocator = allocator;
     }
 
@@ -55,7 +55,7 @@
         resolveDataFlow();
     }
 
-    void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
+    protected void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
         assert moveResolver.checkEmpty();
         assert midBlock == null ||
                         (midBlock.getPredecessorCount() == 1 && midBlock.getSuccessorCount() == 1 && midBlock.getPredecessors().get(0).equals(fromBlock) && midBlock.getSuccessors().get(0).equals(
@@ -87,7 +87,7 @@
                 Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
             }
 
-            List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(fromBlock);
+            List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(fromBlock);
             LIRInstruction instr = instructions.get(instructions.size() - 1);
             if (instr instanceof StandardOp.JumpOp) {
                 // insert moves before branch
@@ -102,7 +102,7 @@
             }
 
             if (DetailedAsserts.getValue()) {
-                assert allocator.ir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
+                assert allocator.getLIR().getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
 
                 /*
                  * Because the number of predecessor edges matches the number of successor edges,
@@ -114,7 +114,7 @@
                 }
             }
 
-            moveResolver.setInsertPosition(allocator.ir.getLIRforBlock(toBlock), 1);
+            moveResolver.setInsertPosition(allocator.getLIR().getLIRforBlock(toBlock), 1);
         }
     }
 
@@ -122,7 +122,7 @@
      * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals that
      * have been split.
      */
-    void resolveDataFlow() {
+    protected void resolveDataFlow() {
         try (Indent indent = Debug.logAndIndent("resolve data flow")) {
 
             MoveResolver moveResolver = allocator.createMoveResolver();
@@ -136,11 +136,11 @@
     }
 
     protected void optimizeEmptyBlocks(MoveResolver moveResolver, BitSet blockCompleted) {
-        for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
 
             // check if block has only one predecessor and only one successor
             if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) {
-                List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block);
+                List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
                 assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label";
                 assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump";
 
@@ -174,7 +174,7 @@
 
     protected void resolveDataFlow0(MoveResolver moveResolver, BitSet blockCompleted) {
         BitSet alreadyResolved = new BitSet(allocator.blockCount());
-        for (AbstractBlockBase<?> fromBlock : allocator.sortedBlocks) {
+        for (AbstractBlockBase<?> fromBlock : allocator.sortedBlocks()) {
             if (!blockCompleted.get(fromBlock.getLinearScanNumber())) {
                 alreadyResolved.clear();
                 alreadyResolved.or(blockCompleted);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java	Wed Jul 29 11:59:18 2015 +0200
@@ -84,12 +84,12 @@
         super(allocator, unhandledFixedFirst, unhandledAnyFirst);
 
         moveResolver = allocator.createMoveResolver();
-        spillIntervals = Util.uncheckedCast(new List[allocator.registers.length]);
-        for (int i = 0; i < allocator.registers.length; i++) {
+        spillIntervals = Util.uncheckedCast(new List[allocator.getRegisters().length]);
+        for (int i = 0; i < allocator.getRegisters().length; i++) {
             spillIntervals[i] = EMPTY_LIST;
         }
-        usePos = new int[allocator.registers.length];
-        blockPos = new int[allocator.registers.length];
+        usePos = new int[allocator.getRegisters().length];
+        blockPos = new int[allocator.getRegisters().length];
     }
 
     void initUseLists(boolean onlyProcessUsePos) {
@@ -268,7 +268,7 @@
         // numbering of instructions is known.
         // When the block already contains spill moves, the index must be increased until the
         // correct index is reached.
-        List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(opBlock);
+        List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(opBlock);
         int index = (opId - instructions.get(0).id()) >> 1;
         assert instructions.get(index).id() <= opId : "error in calculation";
 
@@ -509,7 +509,8 @@
 
                 try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) {
 
-                    assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition";
+                    assert interval.firstUsage(RegisterPriority.MustHaveRegister) > currentPosition : String.format("interval %s must not have use position before currentPosition %d", interval,
+                                    currentPosition);
 
                     allocator.assignSpillSlot(interval);
                     handleSpillSlot(interval);
@@ -593,7 +594,7 @@
                      * The loop depth of the spilling position is higher then the loop depth at the
                      * definition of the interval. Move write to memory out of loop.
                      */
-                    if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) {
+                    if (LinearScan.Options.LIROptLSRAOptimizeSpillPosition.getValue()) {
                         // find best spill position in dominator the tree
                         interval.setSpillState(SpillState.SpillInDominator);
                     } else {
@@ -611,7 +612,7 @@
             }
 
             case OneSpillStore: {
-                if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) {
+                if (LinearScan.Options.LIROptLSRAOptimizeSpillPosition.getValue()) {
                     // the interval is spilled more then once
                     interval.setSpillState(SpillState.SpillInDominator);
                 } else {
@@ -785,7 +786,7 @@
             int firstShouldHaveUsage = interval.firstUsage(RegisterPriority.ShouldHaveRegister);
             int regNeededUntil = Math.min(firstUsage, interval.from() + 1);
             int intervalTo = interval.to();
-            assert regNeededUntil > 0 && regNeededUntil < Integer.MAX_VALUE : "interval has no use";
+            assert regNeededUntil >= 0 && regNeededUntil < Integer.MAX_VALUE : "interval has no use";
 
             Register reg;
             Register ignore;
@@ -845,7 +846,7 @@
                          * errors
                          */
                         allocator.assignSpillSlot(interval);
-                        Debug.dump(allocator.ir, description);
+                        Debug.dump(allocator.getLIR(), description);
                         allocator.printIntervals(description);
                         throw new OutOfRegistersException("LinearScan: no register found", description);
                     }
@@ -892,7 +893,7 @@
     }
 
     boolean noAllocationPossible(Interval interval) {
-        if (allocator.callKillsRegisters) {
+        if (allocator.callKillsRegisters()) {
             // fast calculation of intervals that can never get a register because the
             // the next instruction is a call that blocks all registers
             // Note: this only works if a call kills all registers
@@ -917,7 +918,7 @@
     }
 
     void initVarsForAlloc(Interval interval) {
-        AllocatableRegisters allocatableRegisters = allocator.regAllocConfig.getAllocatableRegisters(interval.kind().getPlatformKind());
+        AllocatableRegisters allocatableRegisters = allocator.getRegisterAllocationConfig().getAllocatableRegisters(interval.kind().getPlatformKind());
         availableRegs = allocatableRegisters.allocatableRegisters;
         minReg = allocatableRegisters.minRegisterNumber;
         maxReg = allocatableRegisters.maxRegisterNumber;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Wed Jul 29 11:59:18 2015 +0200
@@ -36,14 +36,14 @@
 
 /**
  */
-class MoveResolver {
+public class MoveResolver {
 
     private final LinearScan allocator;
 
     private int insertIdx;
     private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted
 
-    protected final List<Interval> mappingFrom;
+    private final List<Interval> mappingFrom;
     private final List<Value> mappingFromOpr;
     private final List<Interval> mappingTo;
     private boolean multipleReadsAllowed;
@@ -58,6 +58,14 @@
         }
     }
 
+    protected Interval getMappingFrom(int i) {
+        return mappingFrom.get(i);
+    }
+
+    protected int mappingFromSize() {
+        return mappingFrom.size();
+    }
+
     protected int valueBlocked(Value location) {
         if (isRegister(location)) {
             return registerBlocked[asRegister(location).number];
@@ -81,7 +89,7 @@
         return allocator;
     }
 
-    MoveResolver(LinearScan allocator) {
+    protected MoveResolver(LinearScan allocator) {
 
         this.allocator = allocator;
         this.multipleReadsAllowed = false;
@@ -90,12 +98,12 @@
         this.mappingTo = new ArrayList<>(8);
         this.insertIdx = -1;
         this.insertionBuffer = new LIRInsertionBuffer();
-        this.registerBlocked = new int[allocator.registers.length];
+        this.registerBlocked = new int[allocator.getRegisters().length];
     }
 
-    boolean checkEmpty() {
+    protected boolean checkEmpty() {
         assert mappingFrom.size() == 0 && mappingFromOpr.size() == 0 && mappingTo.size() == 0 : "list must be empty before and after processing";
-        for (int i = 0; i < getAllocator().registers.length; i++) {
+        for (int i = 0; i < getAllocator().getRegisters().length; i++) {
             assert registerBlocked[i] == 0 : "register map must be empty before and after processing";
         }
         checkMultipleReads();
@@ -351,7 +359,7 @@
         // one stack slot to another can happen (not allowed by LIRAssembler
         StackSlotValue spillSlot = fromInterval.spillSlot();
         if (spillSlot == null) {
-            spillSlot = getAllocator().frameMapBuilder.allocateSpillSlot(fromInterval.kind());
+            spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
             fromInterval.setSpillSlot(spillSlot);
         }
         spillInterval(spillCandidate, fromInterval, spillSlot);
@@ -420,7 +428,7 @@
         this.insertIdx = newInsertIdx;
     }
 
-    void addMapping(Interval fromInterval, Interval toInterval) {
+    public void addMapping(Interval fromInterval, Interval toInterval) {
 
         if (isIllegal(toInterval.location()) && toInterval.canMaterialize()) {
             if (Debug.isLogEnabled()) {
@@ -446,7 +454,7 @@
         mappingTo.add(toInterval);
     }
 
-    void addMapping(Value fromOpr, Interval toInterval) {
+    public void addMapping(Value fromOpr, Interval toInterval) {
         if (Debug.isLogEnabled()) {
             Debug.log("add move mapping from %s to %s", fromOpr, toInterval);
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/OptimizingLinearScanWalker.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/OptimizingLinearScanWalker.java	Wed Jul 29 11:59:18 2015 +0200
@@ -74,7 +74,7 @@
     @Override
     void walk() {
         try (Scope s = Debug.scope("OptimizingLinearScanWalker")) {
-            for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
                 optimizeBlock(block);
             }
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/RegisterVerifier.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/RegisterVerifier.java	Wed Jul 29 11:59:18 2015 +0200
@@ -120,7 +120,7 @@
 
     protected void printState(Interval[] inputState) {
         for (int i = 0; i < stateSize(); i++) {
-            Register reg = allocator.registers[i];
+            Register reg = allocator.getRegisters()[i];
             assert reg.number == i;
             if (inputState[i] != null) {
                 Debug.log(" %6s %4d  --  %s", reg, inputState[i].operandNumber, inputState[i]);
@@ -202,7 +202,7 @@
     }
 
     void processOperations(AbstractBlockBase<?> block, final Interval[] inputState) {
-        List<LIRInstruction> ops = allocator.ir.getLIRforBlock(block);
+        List<LIRInstruction> ops = allocator.getLIR().getLIRforBlock(block);
         InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
 
             @Override
@@ -242,7 +242,7 @@
             op.visitEachInput(useConsumer);
             // invalidate all caller save registers at calls
             if (op.destroysCallerSavedRegisters()) {
-                for (Register r : allocator.regAllocConfig.getRegisterConfig().getCallerSaveRegisters()) {
+                for (Register r : allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters()) {
                     statePut(inputState, r.asValue(), null);
                 }
             }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinarScanResolveDataFlowPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.alloc.lsra;
-
-import static jdk.internal.jvmci.code.ValueUtil.*;
-
-import java.util.*;
-
-import com.oracle.graal.debug.*;
-import jdk.internal.jvmci.meta.*;
-
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.ssa.*;
-import com.oracle.graal.lir.ssa.SSAUtils.PhiValueVisitor;
-
-class SSALinarScanResolveDataFlowPhase extends LinearScanResolveDataFlowPhase {
-
-    private static final DebugMetric numPhiResolutionMoves = Debug.metric("SSA LSRA[numPhiResolutionMoves]");
-    private static final DebugMetric numStackToStackMoves = Debug.metric("SSA LSRA[numStackToStackMoves]");
-
-    SSALinarScanResolveDataFlowPhase(LinearScan allocator) {
-        super(allocator);
-    }
-
-    @Override
-    void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
-        super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver);
-
-        if (toBlock.getPredecessorCount() > 1) {
-            int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock);
-            int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1;
-
-            AbstractBlockBase<?> phiOutBlock = midBlock != null ? midBlock : fromBlock;
-            List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(phiOutBlock);
-            int phiOutIdx = SSAUtils.phiOutIndex(allocator.ir, phiOutBlock);
-            int phiOutId = midBlock != null ? fromBlockLastInstructionId : instructions.get(phiOutIdx).id();
-            assert phiOutId >= 0;
-
-            PhiValueVisitor visitor = new PhiValueVisitor() {
-
-                public void visit(Value phiIn, Value phiOut) {
-                    assert !isRegister(phiOut) : "phiOut is a register: " + phiOut;
-                    assert !isRegister(phiIn) : "phiIn is a register: " + phiIn;
-                    Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
-                    if (isConstant(phiOut)) {
-                        numPhiResolutionMoves.increment();
-                        moveResolver.addMapping(phiOut, toInterval);
-                    } else {
-                        Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), phiOutId, LIRInstruction.OperandMode.DEF);
-                        if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
-                            numPhiResolutionMoves.increment();
-                            if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) {
-                                moveResolver.addMapping(fromInterval, toInterval);
-                            } else {
-                                numStackToStackMoves.increment();
-                                moveResolver.addMapping(fromInterval, toInterval);
-                            }
-                        }
-                    }
-                }
-            };
-
-            SSAUtils.forEachPhiValuePair(allocator.ir, toBlock, phiOutBlock, visitor);
-            SSAUtils.removePhiOut(allocator.ir, phiOutBlock);
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScan.java	Tue Jul 28 17:35:49 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.alloc.lsra;
-
-import java.util.*;
-
-import jdk.internal.jvmci.code.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.*;
-
-import com.oracle.graal.compiler.common.alloc.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
-import com.oracle.graal.lir.ssa.*;
-
-final class SSALinearScan extends LinearScan {
-
-    SSALinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, List<? extends AbstractBlockBase<?>> sortedBlocks) {
-        super(target, res, spillMoveFactory, regAllocConfig, sortedBlocks);
-    }
-
-    @Override
-    protected MoveResolver createMoveResolver() {
-        SSAMoveResolver moveResolver = new SSAMoveResolver(this);
-        assert moveResolver.checkEmpty();
-        return moveResolver;
-    }
-
-    @Override
-    protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() {
-        return new SSALinearScanLifetimeAnalysisPhase(this);
-    }
-
-    @Override
-    protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() {
-        return new SSALinarScanResolveDataFlowPhase(this);
-    }
-
-    @Override
-    protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() {
-        return new SSALinearScanEliminateSpillMovePhase(this);
-    }
-
-    @Override
-    protected void beforeSpillMoveElimination() {
-        /*
-         * PHI Ins are needed for the RegisterVerifier, otherwise PHIs where the Out and In value
-         * matches (ie. there is no resolution move) are falsely detected as errors.
-         */
-        try (Scope s1 = Debug.scope("Remove Phi In")) {
-            for (AbstractBlockBase<?> toBlock : sortedBlocks) {
-                if (toBlock.getPredecessorCount() > 1) {
-                    SSAUtils.removePhiIn(ir, toBlock);
-                }
-            }
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanEliminateSpillMovePhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.alloc.lsra;
-
-import static com.oracle.graal.compiler.common.BackendOptions.*;
-import static com.oracle.graal.lir.LIRValueUtil.*;
-import static jdk.internal.jvmci.code.ValueUtil.*;
-import com.oracle.graal.debug.*;
-
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.MoveOp;
-
-public class SSALinearScanEliminateSpillMovePhase extends LinearScanEliminateSpillMovePhase {
-
-    SSALinearScanEliminateSpillMovePhase(LinearScan allocator) {
-        super(allocator);
-    }
-
-    @Override
-    protected int firstInstructionOfInterest() {
-        // also look at Labels as they define PHI values
-        return 0;
-    }
-
-    @Override
-    protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) {
-        assert isVariable(move.getResult()) || LinearScanVariant.getValue() == LSRAVariant.SSA_LSRA : "Move should not be produced in a non-SSA compilation: " + move;
-
-        if (super.canEliminateSpillMove(block, move)) {
-            // SSA Linear Scan might introduce moves to stack slots
-            Interval curInterval = allocator.intervalFor(move.getResult());
-            assert !isRegister(curInterval.location()) && curInterval.alwaysInMemory();
-            if (!isPhiResolutionMove(block, move, curInterval)) {
-                assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location();
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean isPhiResolutionMove(AbstractBlockBase<?> block, MoveOp move, Interval toInterval) {
-        assert LinearScanVariant.getValue() == LSRAVariant.SSA_LSRA;
-        if (!toInterval.isSplitParent()) {
-            return false;
-        }
-        if ((toInterval.from() & 1) == 1) {
-            // phi intervals start at even positions.
-            return false;
-        }
-        if (block.getSuccessorCount() != 1) {
-            return false;
-        }
-        LIRInstruction op = allocator.instructionForId(toInterval.from());
-        if (!(op instanceof LabelOp)) {
-            return false;
-        }
-        AbstractBlockBase<?> intStartBlock = allocator.blockForId(toInterval.from());
-        assert allocator.ir.getLIRforBlock(intStartBlock).get(0).equals(op);
-        if (!block.getSuccessors().get(0).equals(intStartBlock)) {
-            return false;
-        }
-        try (Indent indet = Debug.indent()) {
-            Debug.log("Is a move (%s) to phi interval %s", move, toInterval);
-        }
-        return true;
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanLifetimeAnalysisPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.alloc.lsra;
-
-import java.util.*;
-
-import com.oracle.graal.debug.*;
-import jdk.internal.jvmci.meta.*;
-
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority;
-import com.oracle.graal.lir.ssa.*;
-
-public class SSALinearScanLifetimeAnalysisPhase extends LinearScanLifetimeAnalysisPhase {
-
-    SSALinearScanLifetimeAnalysisPhase(LinearScan linearScan) {
-        super(linearScan);
-    }
-
-    @Override
-    void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
-        super.addRegisterHint(op, targetValue, mode, flags, hintAtDef);
-
-        if (hintAtDef && op instanceof LabelOp) {
-            LabelOp label = (LabelOp) op;
-
-            Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue);
-
-            SSAUtils.forEachPhiRegisterHint(allocator.ir, allocator.blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> {
-                if (LinearScan.isVariableOrRegister(registerHint)) {
-                    Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint);
-
-                    setHint(op, to, from);
-                    setHint(op, from, to);
-                }
-            });
-        }
-    }
-
-    private static void setHint(final LIRInstruction op, Interval target, Interval source) {
-        Interval currentHint = target.locationHint(false);
-        if (currentHint == null || currentHint.from() > target.from()) {
-            /*
-             * Update hint if there was none or if the hint interval starts after the hinted
-             * interval.
-             */
-            target.setLocationHint(source);
-            if (Debug.isLogEnabled()) {
-                Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), source.operandNumber, target.operandNumber);
-            }
-        }
-    }
-
-    @Override
-    protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
-        if (op instanceof LabelOp) {
-            LabelOp label = (LabelOp) op;
-            if (label.isPhiIn()) {
-                return RegisterPriority.None;
-            }
-        }
-        return super.registerPriorityOfOutputOperand(op);
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSAMoveResolver.java	Tue Jul 28 17:35:49 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.alloc.lsra;
-
-import static jdk.internal.jvmci.code.ValueUtil.*;
-
-import java.util.*;
-
-import jdk.internal.jvmci.code.*;
-import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.meta.*;
-
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.framemap.*;
-
-final class SSAMoveResolver extends MoveResolver {
-
-    private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
-    private int[] stackBlocked;
-    private final int firstVirtualStackIndex;
-
-    SSAMoveResolver(LinearScan allocator) {
-        super(allocator);
-        FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) allocator.frameMapBuilder;
-        FrameMap frameMap = frameMapBuilderTool.getFrameMap();
-        this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
-        this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
-    }
-
-    @Override
-    boolean checkEmpty() {
-        for (int i = 0; i < stackBlocked.length; i++) {
-            assert stackBlocked[i] == 0 : "stack map must be empty before and after processing";
-        }
-        return super.checkEmpty();
-    }
-
-    @Override
-    protected void checkMultipleReads() {
-        // multiple reads are allowed in SSA LSRA
-    }
-
-    @Override
-    protected void verifyStackSlotMapping() {
-        // relax disjoint stack maps invariant
-    }
-
-    @Override
-    protected boolean areMultipleReadsAllowed() {
-        return true;
-    }
-
-    @Override
-    protected boolean mightBeBlocked(Value location) {
-        if (super.mightBeBlocked(location)) {
-            return true;
-        }
-        if (isStackSlotValue(location)) {
-            return true;
-        }
-        return false;
-    }
-
-    private int getStackArrayIndex(StackSlotValue stackSlotValue) {
-        if (isStackSlot(stackSlotValue)) {
-            return getStackArrayIndex(asStackSlot(stackSlotValue));
-        }
-        if (isVirtualStackSlot(stackSlotValue)) {
-            return getStackArrayIndex(asVirtualStackSlot(stackSlotValue));
-        }
-        throw JVMCIError.shouldNotReachHere("Unhandled StackSlotValue: " + stackSlotValue);
-    }
-
-    private int getStackArrayIndex(StackSlot stackSlot) {
-        int stackIdx;
-        if (stackSlot.isInCallerFrame()) {
-            // incoming stack arguments can be ignored
-            stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX;
-        } else {
-            assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot;
-            int offset = -stackSlot.getRawOffset();
-            assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex);
-            stackIdx = offset;
-        }
-        return stackIdx;
-    }
-
-    private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) {
-        return firstVirtualStackIndex + virtualStackSlot.getId();
-    }
-
-    @Override
-    protected void setValueBlocked(Value location, int direction) {
-        assert direction == 1 || direction == -1 : "out of bounds";
-        if (isStackSlotValue(location)) {
-            int stackIdx = getStackArrayIndex(asStackSlotValue(location));
-            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
-                // incoming stack arguments can be ignored
-                return;
-            }
-            if (stackIdx >= stackBlocked.length) {
-                stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1);
-            }
-            stackBlocked[stackIdx] += direction;
-        } else {
-            super.setValueBlocked(location, direction);
-        }
-    }
-
-    @Override
-    protected int valueBlocked(Value location) {
-        if (isStackSlotValue(location)) {
-            int stackIdx = getStackArrayIndex(asStackSlotValue(location));
-            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
-                // incoming stack arguments are always blocked (aka they can not be written)
-                return 1;
-            }
-            if (stackIdx >= stackBlocked.length) {
-                return 0;
-            }
-            return stackBlocked[stackIdx];
-        }
-        return super.valueBlocked(location);
-    }
-
-    @Override
-    protected LIRInstruction createMove(AllocatableValue fromOpr, AllocatableValue toOpr, AllocatableValue fromLocation, AllocatableValue toLocation) {
-        if (isStackSlotValue(toLocation) && isStackSlotValue(fromLocation)) {
-            return getAllocator().getSpillMoveFactory().createStackMove(toOpr, fromOpr);
-        }
-        return super.createMove(fromOpr, toOpr, fromLocation, toLocation);
-    }
-
-    @Override
-    protected void breakCycle(int spillCandidate) {
-        if (spillCandidate != -1) {
-            super.breakCycle(spillCandidate);
-            return;
-        }
-        assert mappingFrom.size() > 1;
-        // Arbitrarily select the first entry for spilling.
-        int stackSpillCandidate = 0;
-        Interval fromInterval = mappingFrom.get(stackSpillCandidate);
-        assert isStackSlotValue(fromInterval.location());
-        // allocate new stack slot
-        StackSlotValue spillSlot = getAllocator().frameMapBuilder.allocateSpillSlot(fromInterval.kind());
-        spillInterval(stackSpillCandidate, fromInterval, spillSlot);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinarScanResolveDataFlowPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra.ssa;
+
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.ssa.*;
+import com.oracle.graal.lir.ssa.SSAUtil.PhiValueVisitor;
+
+class SSALinarScanResolveDataFlowPhase extends LinearScanResolveDataFlowPhase {
+
+    private static final DebugMetric numPhiResolutionMoves = Debug.metric("SSA LSRA[numPhiResolutionMoves]");
+    private static final DebugMetric numStackToStackMoves = Debug.metric("SSA LSRA[numStackToStackMoves]");
+
+    SSALinarScanResolveDataFlowPhase(LinearScan allocator) {
+        super(allocator);
+    }
+
+    @Override
+    protected void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
+        super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver);
+
+        if (toBlock.getPredecessorCount() > 1) {
+            int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock);
+            int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1;
+
+            AbstractBlockBase<?> phiOutBlock = midBlock != null ? midBlock : fromBlock;
+            List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(phiOutBlock);
+            int phiOutIdx = SSAUtil.phiOutIndex(allocator.getLIR(), phiOutBlock);
+            int phiOutId = midBlock != null ? fromBlockLastInstructionId : instructions.get(phiOutIdx).id();
+            assert phiOutId >= 0;
+
+            PhiValueVisitor visitor = new PhiValueVisitor() {
+
+                public void visit(Value phiIn, Value phiOut) {
+                    assert !isRegister(phiOut) : "phiOut is a register: " + phiOut;
+                    assert !isRegister(phiIn) : "phiIn is a register: " + phiIn;
+                    Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
+                    if (isConstant(phiOut)) {
+                        numPhiResolutionMoves.increment();
+                        moveResolver.addMapping(phiOut, toInterval);
+                    } else {
+                        Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), phiOutId, LIRInstruction.OperandMode.DEF);
+                        if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
+                            numPhiResolutionMoves.increment();
+                            if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) {
+                                moveResolver.addMapping(fromInterval, toInterval);
+                            } else {
+                                numStackToStackMoves.increment();
+                                moveResolver.addMapping(fromInterval, toInterval);
+                            }
+                        }
+                    }
+                }
+            };
+
+            SSAUtil.forEachPhiValuePair(allocator.getLIR(), toBlock, phiOutBlock, visitor);
+            SSAUtil.removePhiOut(allocator.getLIR(), phiOutBlock);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScan.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra.ssa;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.*;
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.ssa.*;
+
+public final class SSALinearScan extends LinearScan {
+
+    public SSALinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig,
+                    List<? extends AbstractBlockBase<?>> sortedBlocks) {
+        super(target, res, spillMoveFactory, regAllocConfig, sortedBlocks);
+    }
+
+    @Override
+    protected MoveResolver createMoveResolver() {
+        SSAMoveResolver moveResolver = new SSAMoveResolver(this);
+        assert moveResolver.checkEmpty();
+        return moveResolver;
+    }
+
+    @Override
+    protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() {
+        return new SSALinearScanLifetimeAnalysisPhase(this);
+    }
+
+    @Override
+    protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() {
+        return new SSALinarScanResolveDataFlowPhase(this);
+    }
+
+    @Override
+    protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() {
+        return new SSALinearScanEliminateSpillMovePhase(this);
+    }
+
+    @Override
+    protected void beforeSpillMoveElimination() {
+        /*
+         * PHI Ins are needed for the RegisterVerifier, otherwise PHIs where the Out and In value
+         * matches (ie. there is no resolution move) are falsely detected as errors.
+         */
+        try (Scope s1 = Debug.scope("Remove Phi In")) {
+            for (AbstractBlockBase<?> toBlock : sortedBlocks()) {
+                if (toBlock.getPredecessorCount() > 1) {
+                    SSAUtil.removePhiIn(getLIR(), toBlock);
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScanEliminateSpillMovePhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra.ssa;
+
+import static com.oracle.graal.compiler.common.BackendOptions.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.alloc.lsra.*;
+
+public class SSALinearScanEliminateSpillMovePhase extends LinearScanEliminateSpillMovePhase {
+
+    SSALinearScanEliminateSpillMovePhase(LinearScan allocator) {
+        super(allocator);
+    }
+
+    @Override
+    protected int firstInstructionOfInterest() {
+        // also look at Labels as they define PHI values
+        return 0;
+    }
+
+    @Override
+    protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) {
+        assert isVariable(move.getResult()) || LinearScanVariant.getValue() == LSRAVariant.SSA_LSRA : "Move should not be produced in a non-SSA compilation: " + move;
+
+        if (super.canEliminateSpillMove(block, move)) {
+            // SSA Linear Scan might introduce moves to stack slots
+            Interval curInterval = allocator.intervalFor(move.getResult());
+            assert !isRegister(curInterval.location()) && curInterval.alwaysInMemory();
+            if (!isPhiResolutionMove(block, move, curInterval)) {
+                assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isPhiResolutionMove(AbstractBlockBase<?> block, MoveOp move, Interval toInterval) {
+        assert LinearScanVariant.getValue() == LSRAVariant.SSA_LSRA;
+        if (!toInterval.isSplitParent()) {
+            return false;
+        }
+        if ((toInterval.from() & 1) == 1) {
+            // phi intervals start at even positions.
+            return false;
+        }
+        if (block.getSuccessorCount() != 1) {
+            return false;
+        }
+        LIRInstruction op = allocator.instructionForId(toInterval.from());
+        if (!(op instanceof LabelOp)) {
+            return false;
+        }
+        AbstractBlockBase<?> intStartBlock = allocator.blockForId(toInterval.from());
+        assert allocator.getLIR().getLIRforBlock(intStartBlock).get(0).equals(op);
+        if (!block.getSuccessors().get(0).equals(intStartBlock)) {
+            return false;
+        }
+        try (Indent indet = Debug.indent()) {
+            Debug.log("Is a move (%s) to phi interval %s", move, toInterval);
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScanLifetimeAnalysisPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra.ssa;
+
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority;
+import com.oracle.graal.lir.ssa.*;
+
+public class SSALinearScanLifetimeAnalysisPhase extends LinearScanLifetimeAnalysisPhase {
+
+    SSALinearScanLifetimeAnalysisPhase(LinearScan linearScan) {
+        super(linearScan);
+    }
+
+    @Override
+    protected void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
+        super.addRegisterHint(op, targetValue, mode, flags, hintAtDef);
+
+        if (hintAtDef && op instanceof LabelOp) {
+            LabelOp label = (LabelOp) op;
+
+            Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue);
+
+            SSAUtil.forEachPhiRegisterHint(allocator.getLIR(), allocator.blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> {
+                if (LinearScan.isVariableOrRegister(registerHint)) {
+                    Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint);
+
+                    setHint(op, to, from);
+                    setHint(op, from, to);
+                }
+            });
+        }
+    }
+
+    public static void setHint(final LIRInstruction op, Interval target, Interval source) {
+        Interval currentHint = target.locationHint(false);
+        if (currentHint == null || currentHint.from() > target.from()) {
+            /*
+             * Update hint if there was none or if the hint interval starts after the hinted
+             * interval.
+             */
+            target.setLocationHint(source);
+            if (Debug.isLogEnabled()) {
+                Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), source.operandNumber, target.operandNumber);
+            }
+        }
+    }
+
+    @Override
+    protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
+        if (op instanceof LabelOp) {
+            LabelOp label = (LabelOp) op;
+            if (label.isPhiIn()) {
+                return RegisterPriority.None;
+            }
+        }
+        return super.registerPriorityOfOutputOperand(op);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSAMoveResolver.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra.ssa;
+
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.common.*;
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.framemap.*;
+
+public final class SSAMoveResolver extends MoveResolver {
+
+    private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
+    private int[] stackBlocked;
+    private final int firstVirtualStackIndex;
+
+    public SSAMoveResolver(LinearScan allocator) {
+        super(allocator);
+        FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) allocator.getFrameMapBuilder();
+        FrameMap frameMap = frameMapBuilderTool.getFrameMap();
+        this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
+        this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
+    }
+
+    @Override
+    public boolean checkEmpty() {
+        for (int i = 0; i < stackBlocked.length; i++) {
+            assert stackBlocked[i] == 0 : "stack map must be empty before and after processing";
+        }
+        return super.checkEmpty();
+    }
+
+    @Override
+    protected void checkMultipleReads() {
+        // multiple reads are allowed in SSA LSRA
+    }
+
+    @Override
+    protected void verifyStackSlotMapping() {
+        // relax disjoint stack maps invariant
+    }
+
+    @Override
+    protected boolean areMultipleReadsAllowed() {
+        return true;
+    }
+
+    @Override
+    protected boolean mightBeBlocked(Value location) {
+        if (super.mightBeBlocked(location)) {
+            return true;
+        }
+        if (isStackSlotValue(location)) {
+            return true;
+        }
+        return false;
+    }
+
+    private int getStackArrayIndex(StackSlotValue stackSlotValue) {
+        if (isStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asStackSlot(stackSlotValue));
+        }
+        if (isVirtualStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asVirtualStackSlot(stackSlotValue));
+        }
+        throw JVMCIError.shouldNotReachHere("Unhandled StackSlotValue: " + stackSlotValue);
+    }
+
+    private int getStackArrayIndex(StackSlot stackSlot) {
+        int stackIdx;
+        if (stackSlot.isInCallerFrame()) {
+            // incoming stack arguments can be ignored
+            stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX;
+        } else {
+            assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot;
+            int offset = -stackSlot.getRawOffset();
+            assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex);
+            stackIdx = offset;
+        }
+        return stackIdx;
+    }
+
+    private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) {
+        return firstVirtualStackIndex + virtualStackSlot.getId();
+    }
+
+    @Override
+    protected void setValueBlocked(Value location, int direction) {
+        assert direction == 1 || direction == -1 : "out of bounds";
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(asStackSlotValue(location));
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments can be ignored
+                return;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1);
+            }
+            stackBlocked[stackIdx] += direction;
+        } else {
+            super.setValueBlocked(location, direction);
+        }
+    }
+
+    @Override
+    protected int valueBlocked(Value location) {
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(asStackSlotValue(location));
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments are always blocked (aka they can not be written)
+                return 1;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                return 0;
+            }
+            return stackBlocked[stackIdx];
+        }
+        return super.valueBlocked(location);
+    }
+
+    @Override
+    protected LIRInstruction createMove(AllocatableValue fromOpr, AllocatableValue toOpr, AllocatableValue fromLocation, AllocatableValue toLocation) {
+        if (isStackSlotValue(toLocation) && isStackSlotValue(fromLocation)) {
+            return getAllocator().getSpillMoveFactory().createStackMove(toOpr, fromOpr);
+        }
+        return super.createMove(fromOpr, toOpr, fromLocation, toLocation);
+    }
+
+    @Override
+    protected void breakCycle(int spillCandidate) {
+        if (spillCandidate != -1) {
+            super.breakCycle(spillCandidate);
+            return;
+        }
+        assert mappingFromSize() > 1;
+        // Arbitrarily select the first entry for spilling.
+        int stackSpillCandidate = 0;
+        Interval fromInterval = getMappingFrom(stackSpillCandidate);
+        assert isStackSlotValue(fromInterval.location());
+        // allocate new stack slot
+        StackSlotValue spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
+        spillInterval(stackSpillCandidate, fromInterval, spillSlot);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssi/SSILinearScan.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra.ssi;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.alloc.lsra.ssa.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.ssi.*;
+
+public final class SSILinearScan extends LinearScan {
+
+    public SSILinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig,
+                    List<? extends AbstractBlockBase<?>> sortedBlocks) {
+        super(target, res, spillMoveFactory, regAllocConfig, sortedBlocks);
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    SpillMoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) {
+        assert SSIVerifier.verify(lirGenRes.getLIR()) : "LIR not in SSI form.";
+        super.allocate(target, lirGenRes, codeEmittingOrder, linearScanOrder, spillMoveFactory, registerAllocationConfig);
+    }
+
+    @Override
+    protected MoveResolver createMoveResolver() {
+        SSAMoveResolver moveResolver = new SSAMoveResolver(this);
+        assert moveResolver.checkEmpty();
+        return moveResolver;
+    }
+
+    @Override
+    protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() {
+        return new SSILinearScanLifetimeAnalysisPhase(this);
+    }
+
+    @Override
+    protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() {
+        return new SSILinearScanResolveDataFlowPhase(this);
+    }
+
+    @Override
+    protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() {
+        return new SSILinearScanEliminateSpillMovePhase(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssi/SSILinearScanEliminateSpillMovePhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra.ssi;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.alloc.lsra.*;
+
+public class SSILinearScanEliminateSpillMovePhase extends LinearScanEliminateSpillMovePhase {
+
+    public SSILinearScanEliminateSpillMovePhase(LinearScan allocator) {
+        super(allocator);
+    }
+
+    @Override
+    protected int firstInstructionOfInterest() {
+        // also look at Labels as they define PHI values
+        return 0;
+    }
+
+    @Override
+    protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) {
+        // TODO (je) do not eliminate spill moves yet!
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssi/SSILinearScanLifetimeAnalysisPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra.ssi;
+
+import static com.oracle.graal.lir.alloc.lsra.ssa.SSALinearScanLifetimeAnalysisPhase.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority;
+import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
+import com.oracle.graal.lir.ssi.*;
+
+public class SSILinearScanLifetimeAnalysisPhase extends LinearScanLifetimeAnalysisPhase {
+
+    public SSILinearScanLifetimeAnalysisPhase(LinearScan linearScan) {
+        super(linearScan);
+    }
+
+    @Override
+    protected void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
+        super.addRegisterHint(op, targetValue, mode, flags, hintAtDef);
+
+        if (hintAtDef && op instanceof LabelOp) {
+            LabelOp label = (LabelOp) op;
+
+            Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue);
+
+            SSIUtil.forEachRegisterHint(allocator.getLIR(), allocator.blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> {
+                if (LinearScan.isVariableOrRegister(registerHint)) {
+                    Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint);
+
+                    setHint(op, to, from);
+                    setHint(op, from, to);
+                }
+            });
+        }
+    }
+
+    @Override
+    protected void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, Interval interval, int defPos) {
+        assert interval.isSplitParent() : "can only be called for split parents";
+
+        switch (interval.spillState()) {
+            case NoDefinitionFound:
+                // assert interval.spillDefinitionPos() == -1 : "must no be set before";
+                interval.setSpillDefinitionPos(defPos);
+                if (!(op instanceof LabelOp)) {
+                    // Do not update state for labels. This will be done afterwards.
+                    interval.setSpillState(SpillState.NoSpillStore);
+                }
+                break;
+
+            case NoSpillStore:
+                assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created";
+                if (defPos < interval.spillDefinitionPos() - 2) {
+                    // second definition found, so no spill optimization possible for this interval
+                    interval.setSpillState(SpillState.NoOptimization);
+                } else {
+                    // two consecutive definitions (because of two-operand LIR form)
+                    assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal";
+                }
+                break;
+
+            case NoOptimization:
+                // nothing to do
+                break;
+
+            default:
+                throw new BailoutException("other states not allowed at this time");
+        }
+    }
+
+    @Override
+    protected void buildIntervals() {
+        super.buildIntervals();
+        for (Interval interval : allocator.intervals()) {
+            if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
+                // there was a definition in a phi/sigma
+                interval.setSpillState(SpillState.NoSpillStore);
+            }
+        }
+    }
+
+    @Override
+    protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
+        if (op instanceof LabelOp) {
+            LabelOp label = (LabelOp) op;
+            if (label.id() != 0) {
+                // skip method header
+                return RegisterPriority.None;
+            }
+        }
+        return super.registerPriorityOfOutputOperand(op);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssi/SSILinearScanResolveDataFlowPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra.ssi;
+
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.ssa.SSAUtil.PhiValueVisitor;
+import com.oracle.graal.lir.ssi.*;
+
+public class SSILinearScanResolveDataFlowPhase extends LinearScanResolveDataFlowPhase {
+
+    private static final DebugMetric numSSIResolutionMoves = Debug.metric("SSI LSRA[numSSIResolutionMoves]");
+    private static final DebugMetric numStackToStackMoves = Debug.metric("SSI LSRA[numStackToStackMoves]");
+
+    public SSILinearScanResolveDataFlowPhase(LinearScan allocator) {
+        super(allocator);
+    }
+
+    @Override
+    protected void resolveDataFlow() {
+        super.resolveDataFlow();
+        /*
+         * Incoming Values are needed for the RegisterVerifier, otherwise SIGMAs/PHIs where the Out
+         * and In value matches (ie. there is no resolution move) are falsely detected as errors.
+         */
+        for (AbstractBlockBase<?> toBlock : allocator.sortedBlocks()) {
+            if (toBlock.getPredecessorCount() != 0) {
+                SSIUtil.removeIncoming(allocator.getLIR(), toBlock);
+            } else {
+                assert allocator.getLIR().getControlFlowGraph().getStartBlock().equals(toBlock);
+            }
+            SSIUtil.removeOutgoing(allocator.getLIR(), toBlock);
+        }
+    }
+
+    @Override
+    protected void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
+        super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver);
+
+        if (midBlock != null) {
+            HashMap<Value, Value> map = CollectionsFactory.newMap();
+            SSIUtil.forEachValuePair(allocator.getLIR(), midBlock, fromBlock, (to, from) -> map.put(to, from));
+
+            MyPhiValueVisitor visitor = new MyPhiValueVisitor(moveResolver, toBlock, fromBlock);
+            SSIUtil.forEachValuePair(allocator.getLIR(), toBlock, midBlock, (to, from) -> {
+                Value phiOut = isConstant(from) ? from : map.get(from);
+                assert phiOut != null : "No entry for " + from;
+                visitor.visit(to, phiOut);
+            });
+        } else {
+            // default case
+            SSIUtil.forEachValuePair(allocator.getLIR(), toBlock, fromBlock, new MyPhiValueVisitor(moveResolver, toBlock, fromBlock));
+        }
+
+    }
+
+    private class MyPhiValueVisitor implements PhiValueVisitor {
+        final MoveResolver moveResolver;
+        final int toId;
+        final int fromId;
+
+        public MyPhiValueVisitor(MoveResolver moveResolver, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> fromBlock) {
+            this.moveResolver = moveResolver;
+            toId = allocator.getFirstLirInstructionId(toBlock);
+            fromId = allocator.getLastLirInstructionId(fromBlock);
+            assert fromId >= 0;
+        }
+
+        public void visit(Value phiIn, Value phiOut) {
+            assert !isRegister(phiOut) : "Out is a register: " + phiOut;
+            assert !isRegister(phiIn) : "In is a register: " + phiIn;
+            if (Value.ILLEGAL.equals(phiIn)) {
+                // The value not needed in this branch.
+                return;
+            }
+            if (isVirtualStackSlot(phiIn) && isVirtualStackSlot(phiOut) && phiIn.equals(phiOut)) {
+                // no need to handle virtual stack slots
+                return;
+            }
+            Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toId, LIRInstruction.OperandMode.DEF);
+            if (isConstant(phiOut)) {
+                numSSIResolutionMoves.increment();
+                moveResolver.addMapping(phiOut, toInterval);
+            } else {
+                Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), fromId, LIRInstruction.OperandMode.DEF);
+                if (fromInterval != toInterval) {
+                    numSSIResolutionMoves.increment();
+                    if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) {
+                        moveResolver.addMapping(fromInterval, toInterval);
+                    } else {
+                        numStackToStackMoves.increment();
+                        moveResolver.addMapping(fromInterval, toInterval);
+                    }
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.trace;
+
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.ssa.SSAUtil.PhiValueVisitor;
+import com.oracle.graal.lir.ssi.*;
+
+public class TraceGlobalMoveResolutionPhase extends AllocationPhase {
+
+    private final TraceBuilderResult<?> resultTraces;
+
+    public TraceGlobalMoveResolutionPhase(TraceBuilderResult<?> resultTraces) {
+        this.resultTraces = resultTraces;
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        resolveGlobalDataFlow(resultTraces, lirGenRes, spillMoveFactory, target.arch);
+    }
+
+    private static <B extends AbstractBlockBase<B>> void resolveGlobalDataFlow(TraceBuilderResult<B> resultTraces, LIRGenerationResult lirGenRes, SpillMoveFactory spillMoveFactory, Architecture arch) {
+        LIR lir = lirGenRes.getLIR();
+        /* Resolve trace global data-flow mismatch. */
+        TraceGlobalMoveResolver moveResolver = new TraceGlobalMoveResolver(lirGenRes, spillMoveFactory, arch);
+        PhiValueVisitor visitor = (Value phiIn, Value phiOut) -> {
+            if (!isIllegal(phiIn) && !TraceGlobalMoveResolver.isMoveToSelf(phiOut, phiIn)) {
+                moveResolver.addMapping(phiOut, (AllocatableValue) phiIn);
+            }
+        };
+
+        try (Indent indent = Debug.logAndIndent("Trace global move resolution")) {
+            for (List<B> trace : resultTraces.getTraces()) {
+                for (AbstractBlockBase<?> fromBlock : trace) {
+                    for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) {
+                        if (resultTraces.getTraceForBlock(fromBlock) != resultTraces.getTraceForBlock(toBlock)) {
+                            try (Indent indent0 = Debug.logAndIndent("Handle trace edge from %s (Trace%d) to %s (Trace%d)", fromBlock, resultTraces.getTraceForBlock(fromBlock), toBlock,
+                                            resultTraces.getTraceForBlock(toBlock))) {
+
+                                final List<LIRInstruction> instructions;
+                                final int insertIdx;
+                                if (fromBlock.getSuccessorCount() == 1) {
+                                    instructions = lir.getLIRforBlock(fromBlock);
+                                    insertIdx = instructions.size() - 1;
+                                } else {
+                                    assert toBlock.getPredecessorCount() == 1;
+                                    instructions = lir.getLIRforBlock(toBlock);
+                                    insertIdx = 1;
+                                }
+
+                                moveResolver.setInsertPosition(instructions, insertIdx);
+                                SSIUtil.forEachValuePair(lir, toBlock, fromBlock, visitor);
+                                moveResolver.resolveAndAppendMoves();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceGlobalMoveResolver.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2009, 2014, 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.lir.alloc.trace;
+
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.common.*;
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+
+/**
+ */
+class TraceGlobalMoveResolver {
+
+    private int insertIdx;
+    private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted
+
+    private final List<Value> mappingFrom;
+    private final List<AllocatableValue> mappingTo;
+    private final int[] registerBlocked;
+    private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
+    private int[] stackBlocked;
+    private final int firstVirtualStackIndex;
+    private final SpillMoveFactory spillMoveFactory;
+    private final FrameMapBuilder frameMapBuilder;
+
+    private void setValueBlocked(Value location, int direction) {
+        assert direction == 1 || direction == -1 : "out of bounds";
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(asStackSlotValue(location));
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments can be ignored
+                return;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1);
+            }
+            stackBlocked[stackIdx] += direction;
+        } else {
+            assert direction == 1 || direction == -1 : "out of bounds";
+            if (isRegister(location)) {
+                registerBlocked[asRegister(location).number] += direction;
+            } else {
+                throw JVMCIError.shouldNotReachHere("unhandled value " + location);
+            }
+        }
+    }
+
+    private int valueBlocked(Value location) {
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(asStackSlotValue(location));
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments are always blocked (aka they can not be written)
+                return 1;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                return 0;
+            }
+            return stackBlocked[stackIdx];
+        }
+        if (isRegister(location)) {
+            return registerBlocked[asRegister(location).number];
+        }
+        throw JVMCIError.shouldNotReachHere("unhandled value " + location);
+    }
+
+    private static boolean areMultipleReadsAllowed() {
+        return true;
+    }
+
+    private boolean hasMappings() {
+        return mappingFrom.size() > 0;
+    }
+
+    private SpillMoveFactory getSpillMoveFactory() {
+        return spillMoveFactory;
+    }
+
+    private Register[] getRegisters() {
+        return frameMapBuilder.getRegisterConfig().getAllocatableRegisters();
+    }
+
+    public TraceGlobalMoveResolver(LIRGenerationResult res, SpillMoveFactory spillMoveFactory, Architecture arch) {
+
+        this.mappingFrom = new ArrayList<>(8);
+        this.mappingTo = new ArrayList<>(8);
+        this.insertIdx = -1;
+        this.insertionBuffer = new LIRInsertionBuffer();
+
+        this.frameMapBuilder = res.getFrameMapBuilder();
+        this.spillMoveFactory = spillMoveFactory;
+        this.registerBlocked = new int[arch.getRegisters().length];
+
+        FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) frameMapBuilder;
+        this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
+
+        FrameMap frameMap = frameMapBuilderTool.getFrameMap();
+        this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
+    }
+
+    private boolean checkEmpty() {
+        for (int i = 0; i < stackBlocked.length; i++) {
+            assert stackBlocked[i] == 0 : "stack map must be empty before and after processing";
+        }
+        assert mappingFrom.size() == 0 && mappingTo.size() == 0 : "list must be empty before and after processing";
+        for (int i = 0; i < getRegisters().length; i++) {
+            assert registerBlocked[i] == 0 : "register map must be empty before and after processing";
+        }
+        return true;
+    }
+
+    private boolean verifyBeforeResolve() {
+        assert mappingFrom.size() == mappingTo.size() : "length must be equal";
+        assert insertIdx != -1 : "insert position not set";
+
+        int i;
+        int j;
+        if (!areMultipleReadsAllowed()) {
+            for (i = 0; i < mappingFrom.size(); i++) {
+                for (j = i + 1; j < mappingFrom.size(); j++) {
+                    assert mappingFrom.get(i) == null || mappingFrom.get(i) != mappingFrom.get(j) : "cannot read from same interval twice";
+                }
+            }
+        }
+
+        for (i = 0; i < mappingTo.size(); i++) {
+            for (j = i + 1; j < mappingTo.size(); j++) {
+                assert mappingTo.get(i) != mappingTo.get(j) : "cannot write to same interval twice";
+            }
+        }
+
+        for (i = 0; i < mappingTo.size(); i++) {
+            Value to = mappingTo.get(i);
+            assert !isStackSlotValue(to) || getStackArrayIndex(asStackSlotValue(to)) != STACK_SLOT_IN_CALLER_FRAME_IDX : "Cannot move to in argument: " + to;
+        }
+
+        HashSet<Value> usedRegs = new HashSet<>();
+        if (!areMultipleReadsAllowed()) {
+            for (i = 0; i < mappingFrom.size(); i++) {
+                Value from = mappingFrom.get(i);
+                if (from != null && !isIllegal(from)) {
+                    boolean unique = usedRegs.add(from);
+                    assert unique : "cannot read from same register twice";
+                }
+            }
+        }
+
+        usedRegs.clear();
+        for (i = 0; i < mappingTo.size(); i++) {
+            Value to = mappingTo.get(i);
+            if (isIllegal(to)) {
+                // After insertion the location may become illegal, so don't check it since multiple
+                // intervals might be illegal.
+                continue;
+            }
+            boolean unique = usedRegs.add(to);
+            assert unique : "cannot write to same register twice";
+        }
+
+        return true;
+    }
+
+    // mark assignedReg and assignedRegHi of the interval as blocked
+    private void block(Value location) {
+        if (mightBeBlocked(location)) {
+            assert areMultipleReadsAllowed() || valueBlocked(location) == 0 : "location already marked as used: " + location;
+            setValueBlocked(location, 1);
+            Debug.log("block %s", location);
+        }
+    }
+
+    // mark assignedReg and assignedRegHi of the interval as unblocked
+    private void unblock(Value location) {
+        if (mightBeBlocked(location)) {
+            assert valueBlocked(location) > 0 : "location already marked as unused: " + location;
+            setValueBlocked(location, -1);
+            Debug.log("unblock %s", location);
+        }
+    }
+
+    /**
+     * Checks if the {@linkplain Interval#location() location} of {@code to} is not blocked or is
+     * only blocked by {@code from}.
+     */
+    private boolean safeToProcessMove(Value fromLocation, Value toLocation) {
+        if (mightBeBlocked(toLocation)) {
+            if ((valueBlocked(toLocation) > 1 || (valueBlocked(toLocation) == 1 && !isMoveToSelf(fromLocation, toLocation)))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean isMoveToSelf(Value from, Value to) {
+        assert to != null;
+        if (to.equals(from)) {
+            return true;
+        }
+        if (from != null && isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) {
+            assert LIRKind.verifyMoveKinds(to.getLIRKind(), from.getLIRKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean mightBeBlocked(Value location) {
+        return isRegister(location) || isStackSlotValue(location);
+    }
+
+    private void createInsertionBuffer(List<LIRInstruction> list) {
+        assert !insertionBuffer.initialized() : "overwriting existing buffer";
+        insertionBuffer.init(list);
+    }
+
+    private void appendInsertionBuffer() {
+        if (insertionBuffer.initialized()) {
+            insertionBuffer.finish();
+        }
+        assert !insertionBuffer.initialized() : "must be uninitialized now";
+
+        insertIdx = -1;
+    }
+
+    private void insertMove(Value fromOperand, AllocatableValue toOperand) {
+        assert !fromOperand.equals(toOperand) : "from and to are equal: " + fromOperand + " vs. " + toOperand;
+        assert LIRKind.verifyMoveKinds(fromOperand.getLIRKind(), fromOperand.getLIRKind()) : "move between different types";
+        assert insertIdx != -1 : "must setup insert position first";
+
+        insertionBuffer.append(insertIdx, createMove(fromOperand, toOperand));
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("insert move from %s to %s at %d", fromOperand, toOperand, insertIdx);
+        }
+    }
+
+    /**
+     * @param fromOpr {@link Interval#operand operand} of the {@code from} interval
+     * @param toOpr {@link Interval#operand operand} of the {@code to} interval
+     */
+    private LIRInstruction createMove(Value fromOpr, AllocatableValue toOpr) {
+        if (isStackSlotValue(toOpr) && isStackSlotValue(fromOpr)) {
+            return getSpillMoveFactory().createStackMove(toOpr, fromOpr);
+        }
+        return getSpillMoveFactory().createMove(toOpr, fromOpr);
+    }
+
+    private void resolveMappings() {
+        try (Indent indent = Debug.logAndIndent("resolveMapping")) {
+            assert verifyBeforeResolve();
+            if (Debug.isLogEnabled()) {
+                printMapping();
+            }
+
+            // Block all registers that are used as input operands of a move.
+            // When a register is blocked, no move to this register is emitted.
+            // This is necessary for detecting cycles in moves.
+            for (int i = mappingFrom.size() - 1; i >= 0; i--) {
+                Value from = mappingFrom.get(i);
+                block(from);
+            }
+
+            int spillCandidate = -1;
+            while (mappingFrom.size() > 0) {
+                boolean processedInterval = false;
+
+                for (int i = mappingFrom.size() - 1; i >= 0; i--) {
+                    Value fromInterval = mappingFrom.get(i);
+                    AllocatableValue toInterval = mappingTo.get(i);
+
+                    Value fromLocation = fromInterval;
+                    AllocatableValue toLocation = toInterval;
+                    if (safeToProcessMove(fromLocation, toLocation)) {
+                        // this interval can be processed because target is free
+                        insertMove(fromLocation, toLocation);
+                        unblock(fromLocation);
+                        mappingFrom.remove(i);
+                        mappingTo.remove(i);
+
+                        processedInterval = true;
+                    } else if (fromInterval != null && isRegister(fromLocation)) {
+                        // this interval cannot be processed now because target is not free
+                        // it starts in a register, so it is a possible candidate for spilling
+                        spillCandidate = i;
+                    }
+                }
+
+                if (!processedInterval) {
+                    breakCycle(spillCandidate);
+                }
+            }
+        }
+
+        // check that all intervals have been processed
+        assert checkEmpty();
+    }
+
+    private void breakCycle(int spillCandidate) {
+        // no move could be processed because there is a cycle in the move list
+        // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
+        assert spillCandidate != -1 : "no interval in register for spilling found";
+
+        // create a new spill interval and assign a stack slot to it
+        Value from = mappingFrom.get(spillCandidate);
+        try (Indent indent = Debug.logAndIndent("BreakCycle: %s", from)) {
+            StackSlotValue spillSlot = frameMapBuilder.allocateSpillSlot(from.getLIRKind());
+            if (Debug.isLogEnabled()) {
+                Debug.log("created new slot for spilling: %s", spillSlot);
+            }
+            // insert a move from register to stack and update the mapping
+            insertMove(from, spillSlot);
+            block(spillSlot);
+            mappingFrom.set(spillCandidate, spillSlot);
+            unblock(from);
+        }
+    }
+
+    private void printMapping() {
+        try (Indent indent = Debug.logAndIndent("Mapping")) {
+            for (int i = mappingFrom.size() - 1; i >= 0; i--) {
+                Debug.log("move %s <- %s", mappingTo.get(i), mappingFrom.get(i));
+            }
+        }
+    }
+
+    public void setInsertPosition(List<LIRInstruction> insertList, int insertIdx) {
+        assert this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set";
+
+        createInsertionBuffer(insertList);
+        this.insertIdx = insertIdx;
+    }
+
+    public void addMapping(Value from, AllocatableValue to) {
+        if (Debug.isLogEnabled()) {
+            Debug.log("add move mapping from %s to %s", from, to);
+        }
+
+        assert !from.equals(to) : "from and to interval equal: " + from;
+        assert LIRKind.verifyMoveKinds(to.getLIRKind(), from.getLIRKind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", from.getLIRKind(), to.getLIRKind(), from, to);
+        mappingFrom.add(from);
+        mappingTo.add(to);
+    }
+
+    public void resolveAndAppendMoves() {
+        if (hasMappings()) {
+            resolveMappings();
+        }
+        appendInsertionBuffer();
+    }
+
+    private int getStackArrayIndex(StackSlotValue stackSlotValue) {
+        if (isStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asStackSlot(stackSlotValue));
+        }
+        if (isVirtualStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asVirtualStackSlot(stackSlotValue));
+        }
+        throw JVMCIError.shouldNotReachHere("Unhandled StackSlotValue: " + stackSlotValue);
+    }
+
+    private int getStackArrayIndex(StackSlot stackSlot) {
+        int stackIdx;
+        if (stackSlot.isInCallerFrame()) {
+            // incoming stack arguments can be ignored
+            stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX;
+        } else {
+            assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot;
+            int offset = -stackSlot.getRawOffset();
+            assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex);
+            stackIdx = offset;
+        }
+        return stackIdx;
+    }
+
+    private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) {
+        return firstVirtualStackIndex + virtualStackSlot.getId();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScan.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.trace;
+
+import static com.oracle.graal.lir.alloc.trace.TraceLinearScan.Options.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.options.*;
+
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.alloc.lsra.ssa.*;
+import com.oracle.graal.lir.alloc.lsra.ssi.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext;
+
+public final class TraceLinearScan extends LinearScan {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Use simplified lifetime analysis.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> TraceRAsimpleLifetimeAnalysis = new OptionValue<>(true);
+        // @formatter:on
+    }
+
+    private final TraceBuilderResult<?> traceBuilderResult;
+
+    public TraceLinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig,
+                    List<? extends AbstractBlockBase<?>> sortedBlocks, TraceBuilderResult<?> traceBuilderResult) {
+        super(target, res, spillMoveFactory, regAllocConfig, sortedBlocks);
+        this.traceBuilderResult = traceBuilderResult;
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    SpillMoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) {
+
+        /*
+         * This is the point to enable debug logging for the whole register allocation.
+         */
+        try (Indent indent = Debug.logAndIndent("LinearScan allocate")) {
+            AllocationContext context = new AllocationContext(spillMoveFactory, registerAllocationConfig);
+
+            createLifetimeAnalysisPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
+
+            try (Scope s = Debug.scope("AfterLifetimeAnalysis", (Object) intervals())) {
+                sortIntervalsBeforeAllocation();
+
+                createRegisterAllocationPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
+
+                if (LinearScan.Options.LIROptLSRAOptimizeSpillPosition.getValue()) {
+                    createOptimizeSpillPositionPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
+                }
+                // resolve intra-trace data-flow
+                LinearScanResolveDataFlowPhase dataFlowPhase = createResolveDataFlowPhase();
+                dataFlowPhase.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
+                Debug.dump(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL, sortedBlocks(), "%s", dataFlowPhase.getName());
+
+                LinearScanAssignLocationsPhase assignPhase = createAssignLocationsPhase();
+                assignPhase.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
+
+                if (DetailedAsserts.getValue()) {
+                    verifyIntervals();
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+    }
+
+    @Override
+    protected MoveResolver createMoveResolver() {
+        SSAMoveResolver moveResolver = new SSAMoveResolver(this);
+        assert moveResolver.checkEmpty();
+        return moveResolver;
+    }
+
+    @Override
+    protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() {
+        if (TraceRAsimpleLifetimeAnalysis.getValue()) {
+            return new TraceSimpleLifetimeAnalysisPhase(this, traceBuilderResult);
+        }
+        return new TraceLinearScanLifetimeAnalysisPhase(this, traceBuilderResult);
+    }
+
+    @Override
+    protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() {
+        return new TraceLinearScanResolveDataFlowPhase(this);
+    }
+
+    @Override
+    protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() {
+        return new SSILinearScanEliminateSpillMovePhase(this);
+    }
+
+    @Override
+    public void printIntervals(String label) {
+        if (Debug.isDumpEnabled(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL)) {
+            super.printIntervals(label);
+        }
+    }
+
+    @Override
+    public void printLir(String label, boolean hirValid) {
+        if (Debug.isDumpEnabled(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL)) {
+            Debug.dump(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL, sortedBlocks(), label);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanLifetimeAnalysisPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.trace;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
+import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.*;
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.common.*;
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority;
+import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
+import com.oracle.graal.lir.alloc.lsra.LinearScan.BlockData;
+import com.oracle.graal.lir.ssi.*;
+
+public class TraceLinearScanLifetimeAnalysisPhase extends LinearScanLifetimeAnalysisPhase {
+
+    private final TraceBuilderResult<?> traceBuilderResult;
+
+    public TraceLinearScanLifetimeAnalysisPhase(LinearScan linearScan, TraceBuilderResult<?> traceBuilderResult) {
+        super(linearScan);
+        this.traceBuilderResult = traceBuilderResult;
+    }
+
+    private boolean sameTrace(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+        return traceBuilderResult.getTraceForBlock(b) == traceBuilderResult.getTraceForBlock(a);
+    }
+
+    private boolean isAllocatedOrCurrent(AbstractBlockBase<?> currentBlock, AbstractBlockBase<?> other) {
+        return traceBuilderResult.getTraceForBlock(other) <= traceBuilderResult.getTraceForBlock(currentBlock);
+    }
+
+    static void setHint(final LIRInstruction op, Interval target, Interval source) {
+        Interval currentHint = target.locationHint(false);
+        if (currentHint == null || currentHint.from() > target.from()) {
+            /*
+             * Update hint if there was none or if the hint interval starts after the hinted
+             * interval.
+             */
+            target.setLocationHint(source);
+            if (Debug.isLogEnabled()) {
+                Debug.log("operation at opId %d: added hint from interval %d (%s) to %d (%s)", op.id(), source.operandNumber, source, target.operandNumber, target);
+            }
+        }
+    }
+
+    @Override
+    protected void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, Interval interval, int defPos) {
+        assert interval.isSplitParent() : "can only be called for split parents";
+
+        switch (interval.spillState()) {
+            case NoDefinitionFound:
+                // assert interval.spillDefinitionPos() == -1 : "must no be set before";
+                interval.setSpillDefinitionPos(defPos);
+                if (!(op instanceof LabelOp)) {
+                    // Do not update state for labels. This will be done afterwards.
+                    interval.setSpillState(SpillState.NoSpillStore);
+                }
+                break;
+
+            case NoSpillStore:
+                assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created";
+                if (defPos < interval.spillDefinitionPos() - 2) {
+                    // second definition found, so no spill optimization possible for this interval
+                    interval.setSpillState(SpillState.NoOptimization);
+                } else {
+                    // two consecutive definitions (because of two-operand LIR form)
+                    assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal";
+                }
+                break;
+
+            case NoOptimization:
+                // nothing to do
+                break;
+
+            default:
+                throw new BailoutException("other states not allowed at this time");
+        }
+    }
+
+    @Override
+    protected void buildIntervals() {
+        super.buildIntervals();
+        postBuildIntervals();
+    }
+
+    protected void postBuildIntervals() {
+        // fix spill state for phi/sigma intervals
+        for (Interval interval : allocator.intervals()) {
+            if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
+                // there was a definition in a phi/sigma
+                interval.setSpillState(SpillState.NoSpillStore);
+            }
+        }
+        if (TraceRAuseInterTraceHints.getValue()) {
+            addInterTraceHints();
+        }
+    }
+
+    private void addInterTraceHints() {
+        // set hints for phi/sigma intervals
+        LIR lir = allocator.getLIR();
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+            LabelOp label = SSIUtil.incoming(lir, block);
+            for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+                if (isAllocatedOrCurrent(block, pred)) {
+                    BlockEndOp outgoing = SSIUtil.outgoing(lir, pred);
+                    for (int i = 0; i < outgoing.getOutgoingSize(); i++) {
+                        Value toValue = label.getIncomingValue(i);
+                        if (!isIllegal(toValue)) {
+                            Value fromValue = outgoing.getOutgoingValue(i);
+                            assert sameTrace(block, pred) || !isVariable(fromValue) : "Unallocated variable: " + fromValue;
+
+                            if (!isStackSlotValue(fromValue) && !isConstant(fromValue)) {
+                                Interval from = allocator.getOrCreateInterval((AllocatableValue) fromValue);
+                                Interval to = allocator.getOrCreateInterval((AllocatableValue) toValue);
+                                setHint(label, to, from);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        /*
+         * Set the first range for fixed intervals to [-1, 0] to avoid intersection with incoming
+         * values.
+         */
+        for (Interval interval : allocator.intervals()) {
+            if (interval != null && isRegister(interval.operand)) {
+                Range range = interval.first();
+                if (range == Range.EndMarker) {
+                    interval.addRange(-1, 0);
+                } else if (range.from == 0 && range.to == 1) {
+                    range.from = -1;
+                    range.to = 0;
+                }
+            }
+        }
+    }
+
+    @Override
+    protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
+        if (op instanceof LabelOp) {
+            // skip method header
+            return RegisterPriority.None;
+        }
+        return super.registerPriorityOfOutputOperand(op);
+    }
+
+    @Override
+    protected void handleMethodArguments(LIRInstruction op) {
+        if (op instanceof MoveOp) {
+            // do not optimize method arguments
+            return;
+        }
+        super.handleMethodArguments(op);
+    }
+
+    /**
+     * Performs a backward dataflow analysis to compute global live sets (i.e.
+     * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block.
+     */
+    @Override
+    protected void computeGlobalLiveSets() {
+        try (Indent indent = Debug.logAndIndent("compute global live sets")) {
+            int numBlocks = allocator.blockCount();
+            boolean changeOccurred;
+            boolean changeOccurredInBlock;
+            int iterationCount = 0;
+            BitSet liveOut = new BitSet(allocator.liveSetSize()); // scratch set for calculations
+
+            /*
+             * Perform a backward dataflow analysis to compute liveOut and liveIn for each block.
+             * The loop is executed until a fixpoint is reached (no changes in an iteration).
+             */
+            do {
+                changeOccurred = false;
+
+                try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) {
+
+                    // iterate all blocks in reverse order
+                    for (int i = numBlocks - 1; i >= 0; i--) {
+                        AbstractBlockBase<?> block = allocator.blockAt(i);
+                        BlockData blockSets = allocator.getBlockData(block);
+
+                        changeOccurredInBlock = false;
+
+                        /* liveOut(block) is the union of liveIn(sux), for successors sux of block. */
+                        int n = block.getSuccessorCount();
+                        if (n > 0) {
+                            liveOut.clear();
+                            // block has successors
+                            if (n > 0) {
+                                for (AbstractBlockBase<?> successor : block.getSuccessors()) {
+                                    if (allocator.sortedBlocks().contains(successor)) {
+                                        liveOut.or(allocator.getBlockData(successor).liveIn);
+                                    }
+                                }
+                            }
+
+                            if (!blockSets.liveOut.equals(liveOut)) {
+                                /*
+                                 * A change occurred. Swap the old and new live out sets to avoid
+                                 * copying.
+                                 */
+                                BitSet temp = blockSets.liveOut;
+                                blockSets.liveOut = liveOut;
+                                liveOut = temp;
+
+                                changeOccurred = true;
+                                changeOccurredInBlock = true;
+                            }
+                        }
+
+                        if (iterationCount == 0 || changeOccurredInBlock) {
+                            /*
+                             * liveIn(block) is the union of liveGen(block) with (liveOut(block) &
+                             * !liveKill(block)).
+                             *
+                             * Note: liveIn has to be computed only in first iteration or if liveOut
+                             * has changed!
+                             */
+                            BitSet liveIn = blockSets.liveIn;
+                            liveIn.clear();
+                            liveIn.or(blockSets.liveOut);
+                            liveIn.andNot(blockSets.liveKill);
+                            liveIn.or(blockSets.liveGen);
+
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("block %d: livein = %s,  liveout = %s", block.getId(), liveIn, blockSets.liveOut);
+                            }
+                        }
+                    }
+                    iterationCount++;
+
+                    if (changeOccurred && iterationCount > 50) {
+                        throw new BailoutException("too many iterations in computeGlobalLiveSets");
+                    }
+                }
+            } while (changeOccurred);
+
+            if (DetailedAsserts.getValue()) {
+                verifyLiveness();
+            }
+
+            // check that the liveIn set of the first block is empty
+            AbstractBlockBase<?> startBlock = allocator.blockAt(0);
+            if (allocator.getBlockData(startBlock).liveIn.cardinality() != 0) {
+                if (DetailedAsserts.getValue()) {
+                    reportFailure(numBlocks);
+                }
+                // bailout if this occurs in product mode.
+                throw new JVMCIError("liveIn set of first block must be empty: " + allocator.getBlockData(startBlock).liveIn);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanResolveDataFlowPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.trace;
+
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.ssa.SSAUtil.PhiValueVisitor;
+import com.oracle.graal.lir.ssi.*;
+
+public class TraceLinearScanResolveDataFlowPhase extends LinearScanResolveDataFlowPhase {
+
+    private static final DebugMetric numSSIResolutionMoves = Debug.metric("SSI LSRA[numSSIResolutionMoves]");
+    private static final DebugMetric numStackToStackMoves = Debug.metric("SSI LSRA[numStackToStackMoves]");
+
+    public TraceLinearScanResolveDataFlowPhase(LinearScan allocator) {
+        super(allocator);
+    }
+
+    @Override
+    protected void optimizeEmptyBlocks(MoveResolver moveResolver, BitSet blockCompleted) {
+        // do not optimize
+    }
+
+    @Override
+    protected void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
+        assert midBlock == null;
+        if (containedInTrace(fromBlock) && containedInTrace(toBlock)) {
+            super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver);
+            SSIUtil.forEachValuePair(allocator.getLIR(), toBlock, fromBlock, new MyPhiValueVisitor(moveResolver, toBlock, fromBlock));
+        }
+
+    }
+
+    private boolean containedInTrace(AbstractBlockBase<?> block) {
+        return allocator.sortedBlocks().contains(block);
+    }
+
+    private class MyPhiValueVisitor implements PhiValueVisitor {
+        final MoveResolver moveResolver;
+        final int toId;
+        final int fromId;
+
+        public MyPhiValueVisitor(MoveResolver moveResolver, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> fromBlock) {
+            this.moveResolver = moveResolver;
+            toId = allocator.getFirstLirInstructionId(toBlock);
+            fromId = allocator.getLastLirInstructionId(fromBlock);
+            assert fromId >= 0;
+        }
+
+        public void visit(Value phiIn, Value phiOut) {
+            assert !isRegister(phiOut) : "Out is a register: " + phiOut;
+            assert !isRegister(phiIn) : "In is a register: " + phiIn;
+            if (Value.ILLEGAL.equals(phiIn)) {
+                // The value not needed in this branch.
+                return;
+            }
+            if (isVirtualStackSlot(phiIn) && isVirtualStackSlot(phiOut) && phiIn.equals(phiOut)) {
+                // no need to handle virtual stack slots
+                return;
+            }
+            Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toId, LIRInstruction.OperandMode.DEF);
+            if (isConstant(phiOut)) {
+                numSSIResolutionMoves.increment();
+                moveResolver.addMapping(phiOut, toInterval);
+            } else {
+                Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), fromId, LIRInstruction.OperandMode.DEF);
+                if (fromInterval != toInterval) {
+                    numSSIResolutionMoves.increment();
+                    if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) {
+                        moveResolver.addMapping(fromInterval, toInterval);
+                    } else {
+                        numStackToStackMoves.increment();
+                        moveResolver.addMapping(fromInterval, toInterval);
+                    }
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceRegisterAllocationPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.trace;
+
+import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.*;
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.options.*;
+
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.ssi.*;
+
+public class TraceRegisterAllocationPhase extends AllocationPhase {
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Use inter-trace register hints.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> TraceRAuseInterTraceHints = new OptionValue<>(true);
+        @Option(help = "Use special allocator for trivial blocks.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> TraceRAtrivialBlockAllocator = new OptionValue<>(true);
+        // @formatter:on
+    }
+
+    static final int TRACE_DUMP_LEVEL = 3;
+    private static final DebugMetric trivialTracesMetric = Debug.metric("TraceRA[trivialTraces]");
+    private static final DebugMetric tracesMetric = Debug.metric("TraceRA[traces]");
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        LIR lir = lirGenRes.getLIR();
+        assert SSIVerifier.verify(lir) : "LIR not in SSI form.";
+        B startBlock = linearScanOrder.get(0);
+        assert startBlock.equals(lir.getControlFlowGraph().getStartBlock());
+        TraceBuilderResult<B> resultTraces = TraceBuilder.computeTraces(startBlock, linearScanOrder);
+
+        Debug.dump(lir, "Before TraceRegisterAllocation");
+        int traceNumber = 0;
+        for (List<B> trace : resultTraces.getTraces()) {
+            try (Indent i = Debug.logAndIndent("Allocating Trace%d: %s", traceNumber, trace); Scope s = Debug.scope("AllocateTrace", trace)) {
+                tracesMetric.increment();
+                if (trivialTracesMetric.isEnabled() && isTrivialTrace(lir, trace)) {
+                    trivialTracesMetric.increment();
+                }
+                Debug.dump(TRACE_DUMP_LEVEL, trace, "Trace" + traceNumber + ": " + trace);
+                if (TraceRAtrivialBlockAllocator.getValue() && isTrivialTrace(lir, trace)) {
+                    new TraceTrivialAllocator(resultTraces).apply(target, lirGenRes, codeEmittingOrder, trace, new AllocationContext(spillMoveFactory, registerAllocationConfig), false);
+                } else {
+                    TraceLinearScan allocator = new TraceLinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, trace, resultTraces);
+                    allocator.allocate(target, lirGenRes, codeEmittingOrder, linearScanOrder, spillMoveFactory, registerAllocationConfig);
+                }
+                Debug.dump(TRACE_DUMP_LEVEL, trace, "After Trace" + traceNumber + ": " + trace);
+                traceNumber++;
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+            unnumberInstructions(trace, lir);
+        }
+        Debug.dump(lir, "After trace allocation");
+
+        new TraceGlobalMoveResolutionPhase(resultTraces).apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, new AllocationContext(spillMoveFactory, registerAllocationConfig));
+
+        if (replaceStackToStackMoves(lir, spillMoveFactory)) {
+            Debug.dump(lir, "After fixing stack to stack moves");
+        }
+        /*
+         * Incoming Values are needed for the RegisterVerifier, otherwise SIGMAs/PHIs where the Out
+         * and In value matches (ie. there is no resolution move) are falsely detected as errors.
+         */
+        for (AbstractBlockBase<?> toBlock : lir.getControlFlowGraph().getBlocks()) {
+            if (toBlock.getPredecessorCount() != 0) {
+                SSIUtil.removeIncoming(lir, toBlock);
+            } else {
+                assert lir.getControlFlowGraph().getStartBlock().equals(toBlock);
+            }
+            SSIUtil.removeOutgoing(lir, toBlock);
+        }
+    }
+
+    static boolean isTrivialTrace(LIR lir, List<? extends AbstractBlockBase<?>> trace) {
+        return trace.size() == 1 && lir.getLIRforBlock(trace.iterator().next()).size() == 2;
+    }
+
+    /**
+     * Fixup stack to stack moves introduced by stack arguments.
+     *
+     * TODO (je) find a better solution.
+     */
+    private static boolean replaceStackToStackMoves(LIR lir, SpillMoveFactory spillMoveFactory) {
+        boolean changed = false;
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            for (int i = 0; i < instructions.size(); i++) {
+                LIRInstruction inst = instructions.get(i);
+
+                if (inst instanceof MoveOp) {
+                    MoveOp move = (MoveOp) inst;
+                    if (isStackSlotValue(move.getInput()) && isStackSlotValue(move.getResult())) {
+                        instructions.set(i, spillMoveFactory.createStackMove(move.getResult(), move.getInput()));
+                        changed = true;
+                    }
+                }
+            }
+        }
+        return changed;
+    }
+
+    private static void unnumberInstructions(List<? extends AbstractBlockBase<?>> trace, LIR lir) {
+        trace.stream().flatMap(b -> lir.getLIRforBlock(b).stream()).forEach(op -> op.setId(-1));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceSimpleLifetimeAnalysisPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.trace;
+
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority;
+import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+
+public class TraceSimpleLifetimeAnalysisPhase extends TraceLinearScanLifetimeAnalysisPhase {
+
+    public TraceSimpleLifetimeAnalysisPhase(LinearScan allocator, TraceBuilderResult<?> traceBuilderResult) {
+        super(allocator, traceBuilderResult);
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        numberInstructions();
+        allocator.printLir("Before register allocation", true);
+        buildIntervals();
+    }
+
+    @Override
+    protected void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
+        if (!allocator.isProcessed(operand)) {
+            return;
+        }
+        if (isRegister(operand)) {
+            super.addUse(operand, from, to, registerPriority, kind);
+            return;
+        }
+
+        Interval interval = allocator.getOrCreateInterval(operand);
+        if (!kind.equals(LIRKind.Illegal)) {
+            interval.setKind(kind);
+        }
+
+        Range r = interval.first();
+        if (r == Range.EndMarker) {
+            interval.addRange(from, to);
+        } else if (r.from > from) {
+            r.from = from;
+        }
+
+        // Register use position at even instruction id.
+        interval.addUsePos(to & ~1, registerPriority);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("add use: %s, at %d (%s)", interval, to, registerPriority.name());
+        }
+    }
+
+    @Override
+    protected void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
+        if (!allocator.isProcessed(operand)) {
+            return;
+        }
+        if (isRegister(operand)) {
+            super.addTemp(operand, tempPos, registerPriority, kind);
+            return;
+        }
+
+        Interval interval = allocator.getOrCreateInterval(operand);
+        if (!kind.equals(LIRKind.Illegal)) {
+            interval.setKind(kind);
+        }
+
+        Range r = interval.first();
+        if (r == Range.EndMarker) {
+            interval.addRange(tempPos, tempPos + 1);
+        } else if (r.from > tempPos) {
+            r.from = tempPos;
+        }
+        interval.addUsePos(tempPos, registerPriority);
+        interval.addMaterializationValue(null);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
+        }
+    }
+
+    @Override
+    protected void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
+        if (!allocator.isProcessed(operand)) {
+            return;
+        }
+        if (isRegister(operand)) {
+            super.addDef(operand, op, registerPriority, kind);
+            return;
+        }
+        int defPos = op.id();
+
+        Interval interval = allocator.getOrCreateInterval(operand);
+        if (!kind.equals(LIRKind.Illegal)) {
+            interval.setKind(kind);
+        }
+
+        Range r = interval.first();
+        if (r == Range.EndMarker) {
+            /*
+             * Dead value - make vacuous interval also add register priority for dead intervals
+             */
+            interval.addRange(defPos, defPos + 1);
+            interval.addUsePos(defPos, registerPriority);
+            if (Debug.isLogEnabled()) {
+                Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
+            }
+        } else {
+            /*
+             * Update the starting point (when a range is first created for a use, its start is the
+             * beginning of the current block until a def is encountered).
+             */
+            r.from = defPos;
+            interval.addUsePos(defPos, registerPriority);
+
+        }
+
+        changeSpillDefinitionPos(op, operand, interval, defPos);
+        if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) {
+            // detection of method-parameters and roundfp-results
+            interval.setSpillState(SpillState.StartInMemory);
+        }
+        interval.addMaterializationValue(getMaterializedValue(op, operand, interval));
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
+        }
+    }
+
+    @Override
+    protected void buildIntervals() {
+
+        try (Indent indent = Debug.logAndIndent("build intervals")) {
+            InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, true);
+                }
+            };
+
+            InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            };
+
+            InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    RegisterPriority p = registerPriorityOfInputOperand(flags);
+                    int opId = op.id();
+                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                    addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            };
+
+            InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    int opId = op.id();
+                    RegisterPriority p = registerPriorityOfInputOperand(flags);
+                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                    addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            };
+
+            InstructionValueConsumer stateProc = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    int opId = op.id();
+                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                    addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind());
+                }
+            };
+
+            // create a list with all caller-save registers (cpu, fpu, xmm)
+            Register[] callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters();
+
+            // iterate all blocks in reverse order
+            for (int i = allocator.blockCount() - 1; i >= 0; i--) {
+
+                AbstractBlockBase<?> block = allocator.blockAt(i);
+                // TODO (je) make empty bitset - remove
+                allocator.getBlockData(block).liveIn = new BitSet();
+                allocator.getBlockData(block).liveOut = new BitSet();
+                try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
+
+                    List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
+
+                    /*
+                     * Iterate all instructions of the block in reverse order. definitions of
+                     * intervals are processed before uses.
+                     */
+                    for (int j = instructions.size() - 1; j >= 0; j--) {
+                        final LIRInstruction op = instructions.get(j);
+                        final int opId = op.id();
+
+                        try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) {
+
+                            // add a temp range for each register if operation destroys
+                            // caller-save registers
+                            if (op.destroysCallerSavedRegisters()) {
+                                for (Register r : callerSaveRegs) {
+                                    if (allocator.attributes(r).isAllocatable()) {
+                                        addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal);
+                                    }
+                                }
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("operation destroys all caller-save registers");
+                                }
+                            }
+
+                            op.visitEachOutput(outputConsumer);
+                            op.visitEachTemp(tempConsumer);
+                            op.visitEachAlive(aliveConsumer);
+                            op.visitEachInput(inputConsumer);
+
+                            /*
+                             * Add uses of live locals from interpreter's point of view for proper
+                             * debug information generation. Treat these operands as temp values (if
+                             * the live range is extended to a call site, the value would be in a
+                             * register at the call otherwise).
+                             */
+                            op.visitEachState(stateProc);
+
+                            // special steps for some instructions (especially moves)
+                            handleMethodArguments(op);
+
+                        }
+
+                    } // end of instruction iteration
+                }
+                allocator.printIntervals("After Block " + block);
+            } // end of block iteration
+
+            /*
+             * Add the range [0, 1] to all fixed intervals. the register allocator need not handle
+             * unhandled fixed intervals.
+             */
+            for (Interval interval : allocator.intervals()) {
+                if (interval != null && isRegister(interval.operand)) {
+                    interval.addRange(0, 1);
+                }
+            }
+        }
+        postBuildIntervals();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceTrivialAllocator.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.trace;
+
+import static com.oracle.graal.lir.LIRValueUtil.*;
+import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.ssi.*;
+import com.oracle.graal.lir.util.*;
+
+/**
+ * Allocates a trivial trace i.e. a trace consisting of a single block with no instructions other
+ * than the {@link LabelOp} and the {@link BlockEndOp}.
+ */
+public class TraceTrivialAllocator extends AllocationPhase {
+
+    private final TraceBuilderResult<?> resultTraces;
+
+    public TraceTrivialAllocator(TraceBuilderResult<?> resultTraces) {
+        this.resultTraces = resultTraces;
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> trace, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        LIR lir = lirGenRes.getLIR();
+        assert isTrivialTrace(lir, trace) : "Not a trivial trace! " + trace;
+        B block = trace.iterator().next();
+
+        AbstractBlockBase<?> pred = TraceUtil.getBestTraceInterPredecessor(resultTraces, block);
+
+        VariableVirtualStackValueMap<Variable, Value> variableMap = new VariableVirtualStackValueMap<>(lir.nextVariable(), 0);
+        SSIUtil.forEachValuePair(lir, block, pred, (to, from) -> {
+            if (isVariable(to)) {
+                variableMap.put(asVariable(to), from);
+            }
+        });
+
+        ValueProcedure outputConsumer = (value, mode, flags) -> {
+            if (isVariable(value)) {
+                return variableMap.get(asVariable(value));
+            }
+            return value;
+        };
+
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        for (LIRInstruction op : instructions) {
+
+            op.forEachOutput(outputConsumer);
+            op.forEachTemp(outputConsumer);
+            op.forEachAlive(outputConsumer);
+            op.forEachInput(outputConsumer);
+            op.forEachState(outputConsumer);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceUtil.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.trace;
+
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.compiler.common.cfg.*;
+
+class TraceUtil {
+
+    static AbstractBlockBase<?> getBestTraceInterPredecessor(TraceBuilderResult<?> traceResult, AbstractBlockBase<?> block) {
+        AbstractBlockBase<?> bestPred = null;
+        int bestTraceId = traceResult.getTraceForBlock(block);
+        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+            int predTraceId = traceResult.getTraceForBlock(pred);
+            if (predTraceId < bestTraceId) {
+                bestPred = pred;
+                bestTraceId = predTraceId;
+            }
+        }
+        return bestPred;
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LiveValueSet.java	Tue Jul 28 17:35:49 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.dfa;
-
-import jdk.internal.jvmci.meta.*;
-
-abstract class LiveValueSet<S extends LiveValueSet<S>> {
-
-    public abstract void put(Value v);
-
-    public abstract void remove(Value v);
-
-    public abstract void putAll(S s);
-
-    public abstract S copy();
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarker.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarker.java	Wed Jul 29 11:59:18 2015 +0200
@@ -27,7 +27,9 @@
 import java.util.*;
 
 import jdk.internal.jvmci.code.*;
+
 import com.oracle.graal.debug.*;
+
 import jdk.internal.jvmci.meta.*;
 
 import com.oracle.graal.compiler.common.cfg.*;
@@ -35,8 +37,9 @@
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.util.*;
 
-public abstract class LocationMarker<T extends AbstractBlockBase<T>, S extends LiveValueSet<S>> {
+public abstract class LocationMarker<T extends AbstractBlockBase<T>, S extends ValueSet<S>> {
 
     private final LIR lir;
     private final BlockMap<S> liveInMap;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarkerPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarkerPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -49,105 +49,7 @@
         new Marker<B>(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build();
     }
 
-    private static final class Marker<T extends AbstractBlockBase<T>> extends LocationMarker<T, Marker<T>.RegStackValueSet> {
-
-        private final class RegStackValueSet extends LiveValueSet<Marker<T>.RegStackValueSet> {
-
-            private final ValueSet registers;
-            private final ValueSet stack;
-            private Set<Value> extraStack;
-
-            public RegStackValueSet() {
-                registers = new ValueSet();
-                stack = new ValueSet();
-            }
-
-            private RegStackValueSet(RegStackValueSet s) {
-                registers = new ValueSet(s.registers);
-                stack = new ValueSet(s.stack);
-                if (s.extraStack != null) {
-                    extraStack = new HashSet<>(s.extraStack);
-                }
-            }
-
-            @Override
-            public Marker<T>.RegStackValueSet copy() {
-                return new RegStackValueSet(this);
-            }
-
-            @Override
-            public void put(Value v) {
-                if (isRegister(v)) {
-                    int index = asRegister(v).getReferenceMapIndex();
-                    registers.put(index, v);
-                } else if (isStackSlot(v)) {
-                    int index = frameMap.offsetForStackSlot(asStackSlot(v));
-                    assert index >= 0;
-                    if (index % 4 == 0) {
-                        stack.put(index / 4, v);
-                    } else {
-                        if (extraStack == null) {
-                            extraStack = new HashSet<>();
-                        }
-                        extraStack.add(v);
-                    }
-                }
-            }
-
-            @Override
-            public void putAll(RegStackValueSet v) {
-                registers.putAll(v.registers);
-                stack.putAll(v.stack);
-                if (v.extraStack != null) {
-                    if (extraStack == null) {
-                        extraStack = new HashSet<>();
-                    }
-                    extraStack.addAll(v.extraStack);
-                }
-            }
-
-            @Override
-            public void remove(Value v) {
-                if (isRegister(v)) {
-                    int index = asRegister(v).getReferenceMapIndex();
-                    registers.put(index, null);
-                } else if (isStackSlot(v)) {
-                    int index = frameMap.offsetForStackSlot(asStackSlot(v));
-                    assert index >= 0;
-                    if (index % 4 == 0) {
-                        stack.put(index / 4, null);
-                    } else if (extraStack != null) {
-                        extraStack.remove(v);
-                    }
-                }
-            }
-
-            @SuppressWarnings("unchecked")
-            @Override
-            public boolean equals(Object obj) {
-                if (obj instanceof Marker.RegStackValueSet) {
-                    RegStackValueSet other = (RegStackValueSet) obj;
-                    return registers.equals(other.registers) && stack.equals(other.stack) && Objects.equals(extraStack, other.extraStack);
-                } else {
-                    return false;
-                }
-            }
-
-            @Override
-            public int hashCode() {
-                throw new UnsupportedOperationException();
-            }
-
-            public void addLiveValues(ReferenceMapBuilder refMap) {
-                registers.addLiveValues(refMap);
-                stack.addLiveValues(refMap);
-                if (extraStack != null) {
-                    for (Value v : extraStack) {
-                        refMap.addLiveValue(v);
-                    }
-                }
-            }
-        }
+    static final class Marker<T extends AbstractBlockBase<T>> extends LocationMarker<T, RegStackValueSet> {
 
         private final RegisterAttributes[] registerAttributes;
 
@@ -157,8 +59,8 @@
         }
 
         @Override
-        protected Marker<T>.RegStackValueSet newLiveValueSet() {
-            return new RegStackValueSet();
+        protected RegStackValueSet newLiveValueSet() {
+            return new RegStackValueSet(frameMap);
         }
 
         @Override
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/MarkBasePointersPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/MarkBasePointersPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -34,6 +34,7 @@
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.util.*;
 
 /**
  * Record all derived reference base pointers in a frame state.
@@ -48,16 +49,16 @@
 
     private static final class Marker<T extends AbstractBlockBase<T>> extends LocationMarker<T, Marker<T>.BasePointersSet> {
 
-        private final class BasePointersSet extends LiveValueSet<Marker<T>.BasePointersSet> {
+        private final class BasePointersSet extends ValueSet<Marker<T>.BasePointersSet> {
 
-            private final ValueSet variables;
+            private final IndexedValueMap variables;
 
             public BasePointersSet() {
-                variables = new ValueSet();
+                variables = new IndexedValueMap();
             }
 
             private BasePointersSet(BasePointersSet s) {
-                variables = new ValueSet(s.variables);
+                variables = new IndexedValueMap(s.variables);
             }
 
             @Override
@@ -68,6 +69,7 @@
             @Override
             public void put(Value v) {
                 Variable base = (Variable) v.getLIRKind().getDerivedReferenceBase();
+                assert !base.getLIRKind().isValue();
                 variables.put(base.index, base);
             }
 
@@ -79,6 +81,7 @@
             @Override
             public void remove(Value v) {
                 Variable base = (Variable) v.getLIRKind().getDerivedReferenceBase();
+                assert !base.getLIRKind().isValue();
                 variables.put(base.index, null);
             }
 
@@ -115,7 +118,7 @@
 
         @Override
         protected void processState(LIRInstruction op, LIRFrameState info, BasePointersSet values) {
-            info.setLiveBasePointers(new ValueSet(values.variables));
+            info.setLiveBasePointers(new IndexedValueMap(values.variables));
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/RegStackValueSet.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.dfa;
+
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.util.*;
+
+final class RegStackValueSet extends ValueSet<RegStackValueSet> {
+
+    private final FrameMap frameMap;
+    private final IndexedValueMap registers;
+    private final IndexedValueMap stack;
+    private Set<Value> extraStack;
+
+    public RegStackValueSet(FrameMap frameMap) {
+        this.frameMap = frameMap;
+        registers = new IndexedValueMap();
+        stack = new IndexedValueMap();
+    }
+
+    private RegStackValueSet(FrameMap frameMap, RegStackValueSet s) {
+        this.frameMap = frameMap;
+        registers = new IndexedValueMap(s.registers);
+        stack = new IndexedValueMap(s.stack);
+        if (s.extraStack != null) {
+            extraStack = new HashSet<>(s.extraStack);
+        }
+    }
+
+    @Override
+    public RegStackValueSet copy() {
+        return new RegStackValueSet(frameMap, this);
+    }
+
+    @Override
+    public void put(Value v) {
+        if (!shouldProcessValue(v)) {
+            return;
+        }
+        if (isRegister(v)) {
+            int index = asRegister(v).getReferenceMapIndex();
+            registers.put(index, v);
+        } else if (isStackSlot(v)) {
+            int index = frameMap.offsetForStackSlot(asStackSlot(v));
+            assert index >= 0;
+            if (index % 4 == 0) {
+                stack.put(index / 4, v);
+            } else {
+                if (extraStack == null) {
+                    extraStack = new HashSet<>();
+                }
+                extraStack.add(v);
+            }
+        }
+    }
+
+    @Override
+    public void putAll(RegStackValueSet v) {
+        registers.putAll(v.registers);
+        stack.putAll(v.stack);
+        if (v.extraStack != null) {
+            if (extraStack == null) {
+                extraStack = new HashSet<>();
+            }
+            extraStack.addAll(v.extraStack);
+        }
+    }
+
+    @Override
+    public void remove(Value v) {
+        if (!shouldProcessValue(v)) {
+            return;
+        }
+        if (isRegister(v)) {
+            int index = asRegister(v).getReferenceMapIndex();
+            registers.put(index, null);
+        } else if (isStackSlot(v)) {
+            int index = frameMap.offsetForStackSlot(asStackSlot(v));
+            assert index >= 0;
+            if (index % 4 == 0) {
+                stack.put(index / 4, null);
+            } else if (extraStack != null) {
+                extraStack.remove(v);
+            }
+        }
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof RegStackValueSet) {
+            RegStackValueSet other = (RegStackValueSet) obj;
+            return registers.equals(other.registers) && stack.equals(other.stack) && Objects.equals(extraStack, other.extraStack);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        throw new UnsupportedOperationException();
+    }
+
+    private static boolean shouldProcessValue(Value v) {
+        /*
+         * We always process registers because we have to track the largest register size that is
+         * alive across safepoints in order to save and restore them.
+         */
+        return isRegister(v) || !v.getLIRKind().isValue();
+    }
+
+    public void addLiveValues(ReferenceMapBuilder refMap) {
+        ValueConsumer addLiveValue = new ValueConsumer() {
+            public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                refMap.addLiveValue(value);
+            }
+        };
+        registers.forEach(null, null, null, addLiveValue);
+        stack.forEach(null, null, null, addLiveValue);
+        if (extraStack != null) {
+            for (Value v : extraStack) {
+                refMap.addLiveValue(v);
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/ValueSet.java	Tue Jul 28 17:35:49 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.dfa;
-
-import java.util.*;
-
-import jdk.internal.jvmci.meta.*;
-
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.framemap.*;
-
-public final class ValueSet {
-    private Value[] values;
-
-    ValueSet() {
-        values = Value.NO_VALUES;
-    }
-
-    ValueSet(ValueSet other) {
-        int limit = other.values.length;
-        while (limit > 0) {
-            if (other.values[limit - 1] == null) {
-                limit--;
-                continue;
-            }
-            break;
-        }
-        values = new Value[limit];
-        System.arraycopy(other.values, 0, values, 0, values.length);
-    }
-
-    public Value get(int index) {
-        return values[index];
-    }
-
-    void put(int index, Value value) {
-        if (value != null && value.getLIRKind().isValue()) {
-            return;
-        }
-        if (values.length <= index) {
-            if (value == null) {
-                return;
-            }
-            Value[] newValues = new Value[index + 1];
-            System.arraycopy(values, 0, newValues, 0, values.length);
-            values = newValues;
-            values[index] = value;
-        } else {
-            values[index] = value;
-        }
-    }
-
-    public void putAll(ValueSet stack) {
-        Value[] otherValues = stack.values;
-        int limit = otherValues.length;
-        if (limit > values.length) {
-            while (limit > 0) {
-                if (otherValues[limit - 1] == null) {
-                    limit--;
-                    continue;
-                }
-                break;
-            }
-            if (limit > values.length) {
-                Value[] newValues = new Value[limit];
-                System.arraycopy(values, 0, newValues, 0, values.length);
-                values = newValues;
-            }
-        }
-        for (int i = 0; i < limit; i++) {
-            Value value = otherValues[i];
-            if (value != null) {
-                values[i] = value;
-            }
-        }
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        if (other instanceof ValueSet) {
-            ValueSet that = (ValueSet) other;
-            int limit = Math.min(values.length, that.values.length);
-            for (int i = 0; i < limit; i++) {
-                if (!Objects.equals(values[i], that.values[i])) {
-                    return false;
-                }
-            }
-            for (int i = limit; i < values.length; i++) {
-                if (values[i] != null) {
-                    return false;
-                }
-            }
-            for (int i = limit; i < that.values.length; i++) {
-                if (that.values[i] != null) {
-                    return false;
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    public void addLiveValues(ReferenceMapBuilder refMap) {
-        for (Value v : values) {
-            if (v != null) {
-                refMap.addLiveValue(v);
-            }
-        }
-    }
-
-    public void forEach(LIRInstruction inst, OperandMode mode, EnumSet<OperandFlag> flags, InstructionValueProcedure proc) {
-        for (int i = 0; i < values.length; i++) {
-            if (values[i] != null) {
-                values[i] = proc.doValue(inst, values[i], mode, flags);
-            }
-        }
-    }
-
-    public void forEach(LIRInstruction inst, OperandMode mode, EnumSet<OperandFlag> flags, InstructionValueConsumer consumer) {
-        for (Value v : values) {
-            if (v != null) {
-                consumer.visitValue(inst, v, mode, flags);
-            }
-        }
-    }
-
-    @Override
-    public int hashCode() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder("[");
-        boolean comma = false;
-
-        for (int i = 0; i < values.length; i++) {
-            if (values[i] != null) {
-                if (comma) {
-                    sb.append(", ");
-                } else {
-                    comma = true;
-                }
-
-                sb.append(i);
-                sb.append(": ");
-                sb.append(values[i]);
-            }
-        }
-        sb.append(']');
-        return sb.toString();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/BlockValueMap.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.gen;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+
+public interface BlockValueMap {
+
+    void accessOperand(Value operand, AbstractBlockBase<?> block);
+
+    void defineOperand(Value operand, AbstractBlockBase<?> block);
+
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Wed Jul 29 11:59:18 2015 +0200
@@ -29,8 +29,6 @@
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
-
 import jdk.internal.jvmci.meta.*;
 import jdk.internal.jvmci.options.*;
 
@@ -39,6 +37,7 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.common.spi.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
 import com.oracle.graal.lir.StandardOp.LabelOp;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationStage.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationStage.java	Wed Jul 29 11:59:18 2015 +0200
@@ -22,7 +22,10 @@
  */
 package com.oracle.graal.lir.phases;
 
+import static com.oracle.graal.compiler.common.BackendOptions.UserOptions.*;
+
 import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.alloc.trace.*;
 import com.oracle.graal.lir.dfa.*;
 import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext;
 import com.oracle.graal.lir.stackslotalloc.*;
@@ -30,7 +33,11 @@
 public class AllocationStage extends LIRPhaseSuite<AllocationContext> {
     public AllocationStage() {
         appendPhase(new MarkBasePointersPhase());
-        appendPhase(new LinearScanPhase());
+        if (TraceRA.getValue()) {
+            appendPhase(new TraceRegisterAllocationPhase());
+        } else {
+            appendPhase(new LinearScanPhase());
+        }
 
         // build frame map
         if (LSStackSlotAllocator.Options.LIROptLSStackSlotAllocator.getValue()) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PreAllocationOptimizationStage.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PreAllocationOptimizationStage.java	Wed Jul 29 11:59:18 2015 +0200
@@ -23,11 +23,13 @@
 package com.oracle.graal.lir.phases;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.compiler.common.BackendOptions.*;
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.constopt.*;
 import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
 import com.oracle.graal.lir.ssa.*;
+import com.oracle.graal.lir.ssi.*;
 
 public class PreAllocationOptimizationStage extends LIRPhaseSuite<PreAllocationOptimizationContext> {
     public PreAllocationOptimizationStage() {
@@ -37,5 +39,8 @@
         if (ConstantLoadOptimization.Options.LIROptConstantLoadOptimization.getValue()) {
             appendPhase(new ConstantLoadOptimization());
         }
+        if (EnableSSIConstruction.getValue()) {
+            appendPhase(new SSIConstructionPhase());
+        }
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java	Wed Jul 29 11:59:18 2015 +0200
@@ -51,7 +51,8 @@
         STACK2REG("Reg", "Stack"),
         CONST2REG("Reg", "Const"),
         REG2STACK("Stack", "Reg"),
-        CONST2STACK("Stack", "Const");
+        CONST2STACK("Stack", "Const"),
+        STACK2STACK("Stack", "Stack");
 
         private final String name;
 
@@ -84,6 +85,9 @@
                 if (isConstant(src)) {
                     return CONST2STACK;
                 }
+                if (isStackSlot(src)) {
+                    return STACK2STACK;
+                }
             }
             throw JVMCIError.shouldNotReachHere(String.format("Unrecognized Move: %s dst=%s, src=%s", move, dst, src));
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSADestructionPhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSADestructionPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -48,15 +48,15 @@
 
                 List<LIRInstruction> instructions = lir.getLIRforBlock(pred);
 
-                int insertBefore = SSAUtils.phiOutIndex(lir, pred);
+                int insertBefore = SSAUtil.phiOutIndex(lir, pred);
 
                 PhiResolver resolver = PhiResolver.create(lirGen, new LIRInsertionBuffer(), instructions, insertBefore);
-                SSAUtils.forEachPhiValuePair(lir, block, pred, resolver::move);
+                SSAUtil.forEachPhiValuePair(lir, block, pred, resolver::move);
                 resolver.dispose();
 
-                SSAUtils.removePhiOut(lir, pred);
+                SSAUtil.removePhiOut(lir, pred);
             }
-            SSAUtils.removePhiIn(lir, block);
+            SSAUtil.removePhiIn(lir, block);
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSAUtil.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.ssa;
+
+import java.util.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+
+/**
+ * Utilities for working with Static-Single-Assignment LIR form.
+ *
+ * <h2>Representation of <code>PHI</code>s</h2>
+ *
+ * There is no explicit <code>PHI</code> {@linkplain LIRInstruction}. Instead, they are implemented
+ * as parallel copy that span across a control-flow edge.
+ *
+ * The variables introduced by <code>PHI</code>s of a specific {@linkplain AbstractBlockBase merge
+ * block} are {@linkplain LabelOp#setIncomingValues attached} to the {@linkplain LabelOp} of the
+ * block. The outgoing values from the predecessor are {@link JumpOp#setOutgoingValues input} to the
+ * {@linkplain BlockEndOp} of the predecessor. Because there are no critical edges we know that the
+ * {@link BlockEndOp} of the predecessor has to be a {@link JumpOp}.
+ *
+ * <h3>Example:</h3>
+ *
+ * <pre>
+ * B0 -> B1
+ *   ...
+ *   v0|i = ...
+ *   JUMP ~[v0|i, int[0|0x0]] destination: B0 -> B1
+ * ________________________________________________
+ * 
+ * B2 -> B1
+ *   ...
+ *   v1|i = ...
+ *   v2|i = ...
+ *   JUMP ~[v1|i, v2|i] destination: B2 -> B1
+ * ________________________________________________
+ * 
+ * B1 <- B0,B2
+ *   [v3|i, v4|i] = LABEL
+ *   ...
+ * </pre>
+ */
+public final class SSAUtil {
+
+    public interface PhiValueVisitor {
+        /**
+         * @param phiIn the incoming value at the merge block
+         * @param phiOut the outgoing value from the predecessor block
+         */
+        void visit(Value phiIn, Value phiOut);
+    }
+
+    /**
+     * Visits each phi value pair of an edge, i.e. the outgoing value from the predecessor and the
+     * incoming value to the merge block.
+     */
+    public static void forEachPhiValuePair(LIR lir, AbstractBlockBase<?> merge, AbstractBlockBase<?> pred, PhiValueVisitor visitor) {
+        if (merge.getPredecessorCount() < 2) {
+            return;
+        }
+        assert merge.getPredecessors().contains(pred) : String.format("%s not in predecessor list: %s", pred, merge.getPredecessors());
+        assert pred.getSuccessorCount() == 1 : String.format("Merge predecessor block %s has more than one successor? %s", pred, pred.getSuccessors());
+        assert pred.getSuccessors().get(0) == merge : String.format("Predecessor block %s has wrong successor: %s, should be: %s", pred, pred.getSuccessors().get(0), merge);
+
+        JumpOp jump = phiOut(lir, pred);
+        LabelOp label = phiIn(lir, merge);
+
+        assert label.getIncomingSize() == jump.getOutgoingSize() : String.format("Phi In/Out size mismatch: in=%d vs. out=%d", label.getIncomingSize(), jump.getOutgoingSize());
+
+        for (int i = 0; i < label.getIncomingSize(); i++) {
+            visitor.visit(label.getIncomingValue(i), jump.getOutgoingValue(i));
+        }
+    }
+
+    private static JumpOp phiOut(LIR lir, AbstractBlockBase<?> block) {
+        assert block.getSuccessorCount() == 1;
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        int index = instructions.size() - 1;
+        LIRInstruction op = instructions.get(index);
+        return (JumpOp) op;
+    }
+
+    public static int phiOutIndex(LIR lir, AbstractBlockBase<?> block) {
+        assert block.getSuccessorCount() == 1;
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        int index = instructions.size() - 1;
+        assert instructions.get(index) instanceof JumpOp;
+        return index;
+    }
+
+    private static LabelOp phiIn(LIR lir, AbstractBlockBase<?> block) {
+        assert block.getPredecessorCount() > 1;
+        LabelOp label = (LabelOp) lir.getLIRforBlock(block).get(0);
+        return label;
+    }
+
+    public static void removePhiOut(LIR lir, AbstractBlockBase<?> block) {
+        JumpOp jump = phiOut(lir, block);
+        jump.clearOutgoingValues();
+    }
+
+    public static void removePhiIn(LIR lir, AbstractBlockBase<?> block) {
+        LabelOp label = phiIn(lir, block);
+        label.clearIncomingValues();
+    }
+
+    public static boolean verifySSAForm(LIR lir) {
+        return new SSAVerifier(lir).verify();
+    }
+
+    public static void verifyPhi(LIR lir, AbstractBlockBase<?> merge) {
+        assert merge.getPredecessorCount() > 1;
+        for (AbstractBlockBase<?> pred : merge.getPredecessors()) {
+            forEachPhiValuePair(lir, merge, pred, (phiIn, phiOut) -> {
+                assert phiIn.getLIRKind().equals(phiOut.getLIRKind()) ||
+                                (phiIn.getPlatformKind().equals(phiOut.getPlatformKind()) && phiIn.getLIRKind().isUnknownReference() && phiOut.getLIRKind().isValue());
+            });
+        }
+    }
+
+    public static void forEachPhiRegisterHint(LIR lir, AbstractBlockBase<?> block, LabelOp label, Value targetValue, OperandMode mode, ValueConsumer valueConsumer) {
+        assert mode == OperandMode.DEF : "Wrong operand mode: " + mode;
+        assert lir.getLIRforBlock(block).get(0).equals(label) : String.format("Block %s and Label %s do not match!", block, label);
+
+        if (!label.isPhiIn()) {
+            return;
+        }
+        int idx = indexOfValue(label, targetValue);
+        assert idx >= 0 : String.format("Value %s not in label %s", targetValue, label);
+
+        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+            JumpOp jump = phiOut(lir, pred);
+            Value sourceValue = jump.getOutgoingValue(idx);
+            valueConsumer.visitValue(jump, sourceValue, null, null);
+        }
+
+    }
+
+    private static int indexOfValue(LabelOp label, Value value) {
+        for (int i = 0; i < label.getIncomingSize(); i++) {
+            if (label.getIncomingValue(i).equals(value)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSAUtils.java	Tue Jul 28 17:35:49 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,176 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.ssa;
-
-import java.util.*;
-
-import jdk.internal.jvmci.meta.*;
-
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.lir.StandardOp.JumpOp;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-
-/**
- * Utilities for working with Static-Single-Assignment LIR form.
- *
- * <h2>Representation of <code>PHI</code>s</h2>
- *
- * There is no explicit <code>PHI</code> {@linkplain LIRInstruction}. Instead, they are implemented
- * as parallel copy that span across a control-flow edge.
- *
- * The variables introduced by <code>PHI</code>s of a specific {@linkplain AbstractBlockBase merge
- * block} are {@linkplain LabelOp#setIncomingValues attached} to the {@linkplain LabelOp} of the
- * block. The outgoing values from the predecessor are {@link JumpOp#setOutgoingValues input} to the
- * {@linkplain BlockEndOp} of the predecessor. Because there are no critical edges we know that the
- * {@link BlockEndOp} of the predecessor has to be a {@link JumpOp}.
- *
- * <h3>Example:</h3>
- *
- * <pre>
- * B0 -> B1
- *   ...
- *   v0|i = ...
- *   JUMP ~[v0|i, int[0|0x0]] destination: B0 -> B1
- * ________________________________________________
- * 
- * B2 -> B1
- *   ...
- *   v1|i = ...
- *   v2|i = ...
- *   JUMP ~[v1|i, v2|i] destination: B2 -> B1
- * ________________________________________________
- * 
- * B1 <- B0,B2
- *   [v3|i, v4|i] = LABEL
- *   ...
- * </pre>
- */
-public final class SSAUtils {
-
-    public interface PhiValueVisitor {
-        /**
-         * @param phiIn the incoming value at the merge block
-         * @param phiOut the outgoing value from the predecessor block
-         */
-        void visit(Value phiIn, Value phiOut);
-    }
-
-    /**
-     * Visits each phi value pair of an edge, i.e. the outgoing value from the predecessor and the
-     * incoming value to the merge block.
-     */
-    public static void forEachPhiValuePair(LIR lir, AbstractBlockBase<?> merge, AbstractBlockBase<?> pred, PhiValueVisitor visitor) {
-        if (merge.getPredecessorCount() < 2) {
-            return;
-        }
-        assert merge.getPredecessors().contains(pred) : String.format("%s not in predecessor list: %s", pred, merge.getPredecessors());
-        assert pred.getSuccessorCount() == 1 : String.format("Merge predecessor block %s has more than one successor? %s", pred, pred.getSuccessors());
-        assert pred.getSuccessors().get(0) == merge : String.format("Predecessor block %s has wrong successor: %s, should be: %s", pred, pred.getSuccessors().get(0), merge);
-
-        JumpOp jump = phiOut(lir, pred);
-        LabelOp label = phiIn(lir, merge);
-
-        assert label.getIncomingSize() == jump.getOutgoingSize() : String.format("Phi In/Out size mismatch: in=%d vs. out=%d", label.getIncomingSize(), jump.getOutgoingSize());
-
-        for (int i = 0; i < label.getIncomingSize(); i++) {
-            visitor.visit(label.getIncomingValue(i), jump.getOutgoingValue(i));
-        }
-    }
-
-    private static JumpOp phiOut(LIR lir, AbstractBlockBase<?> block) {
-        assert block.getSuccessorCount() == 1;
-        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-        int index = instructions.size() - 1;
-        LIRInstruction op = instructions.get(index);
-        return (JumpOp) op;
-    }
-
-    public static int phiOutIndex(LIR lir, AbstractBlockBase<?> block) {
-        assert block.getSuccessorCount() == 1;
-        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-        int index = instructions.size() - 1;
-        assert instructions.get(index) instanceof JumpOp;
-        return index;
-    }
-
-    private static LabelOp phiIn(LIR lir, AbstractBlockBase<?> block) {
-        assert block.getPredecessorCount() > 1;
-        LabelOp label = (LabelOp) lir.getLIRforBlock(block).get(0);
-        return label;
-    }
-
-    public static void removePhiOut(LIR lir, AbstractBlockBase<?> block) {
-        JumpOp jump = phiOut(lir, block);
-        jump.clearOutgoingValues();
-    }
-
-    public static void removePhiIn(LIR lir, AbstractBlockBase<?> block) {
-        LabelOp label = phiIn(lir, block);
-        label.clearIncomingValues();
-    }
-
-    public static boolean verifySSAForm(LIR lir) {
-        return new SSAVerifier(lir).verify();
-    }
-
-    public static void verifyPhi(LIR lir, AbstractBlockBase<?> merge) {
-        assert merge.getPredecessorCount() > 1;
-        for (AbstractBlockBase<?> pred : merge.getPredecessors()) {
-            forEachPhiValuePair(lir, merge, pred, (phiIn, phiOut) -> {
-                assert phiIn.getLIRKind().equals(phiOut.getLIRKind()) ||
-                                (phiIn.getPlatformKind().equals(phiOut.getPlatformKind()) && phiIn.getLIRKind().isUnknownReference() && phiOut.getLIRKind().isValue());
-            });
-        }
-    }
-
-    public static void forEachPhiRegisterHint(LIR lir, AbstractBlockBase<?> block, LabelOp label, Value targetValue, OperandMode mode, ValueConsumer valueConsumer) {
-        assert mode == OperandMode.DEF : "Wrong operand mode: " + mode;
-        assert lir.getLIRforBlock(block).get(0).equals(label) : String.format("Block %s and Label %s do not match!", block, label);
-
-        if (!label.isPhiIn()) {
-            return;
-        }
-        int idx = indexOfValue(label, targetValue);
-        assert idx >= 0 : String.format("Value %s not in label %s", targetValue, label);
-
-        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
-            JumpOp jump = phiOut(lir, pred);
-            Value sourceValue = jump.getOutgoingValue(idx);
-            valueConsumer.visitValue(jump, sourceValue, null, null);
-        }
-
-    }
-
-    private static int indexOfValue(LabelOp label, Value value) {
-        for (int i = 0; i < label.getIncomingSize(); i++) {
-            if (label.getIncomingValue(i).equals(value)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssi/SSIBlockValueMapImpl.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.ssi;
+
+import static com.oracle.graal.lir.LIRValueUtil.*;
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.util.*;
+
+public final class SSIBlockValueMapImpl implements BlockValueMap {
+
+    private static final class BlockData {
+
+        /** Mapping from value to index into {@link #incoming}. */
+        private final ValueMap<Value, Integer> valueIndexMap;
+        private final ArrayList<Value> incoming;
+        private final ArrayList<Value> outgoing;
+
+        private BlockData(int initialVariableCapacity, int initialStackSlotCapacity) {
+            valueIndexMap = new VariableVirtualStackValueMap<>(initialVariableCapacity, initialStackSlotCapacity);
+            incoming = new ArrayList<>();
+            outgoing = new ArrayList<>();
+        }
+
+        public Integer getIndex(Value operand) {
+            return valueIndexMap.get(operand);
+        }
+
+        public Value getIncoming(int index) {
+            return incoming.get(index);
+        }
+
+        public void setIncoming(int index, Value value) {
+            incoming.set(index, value);
+        }
+
+        public int addIncoming(Value operand) {
+            assert isVariable(operand) || isVirtualStackSlot(operand) : "Not a variable or vstack: " + operand;
+            int index = incoming.size();
+            incoming.add(Value.ILLEGAL);
+            valueIndexMap.put(operand, index);
+            return index;
+        }
+
+        public boolean contains(Value operand) {
+            return getIndex(operand) != null;
+        }
+
+        public int addOutgoing(Value operand) {
+            int index = outgoing.size();
+            outgoing.add(operand);
+            return index;
+        }
+
+    }
+
+    /** Mapping from value to definition block. */
+    private final ValueMap<Value, AbstractBlockBase<?>> valueToDefBlock;
+    private final BlockMap<BlockData> blockData;
+    private final int initialVariableCapacity;
+    private final int initialStackSlotCapacity;
+
+    public SSIBlockValueMapImpl(AbstractControlFlowGraph<?> cfg, int initialVariableCapacity, int initialStackSlotCapacity) {
+        this.initialVariableCapacity = initialVariableCapacity;
+        this.initialStackSlotCapacity = initialStackSlotCapacity;
+        valueToDefBlock = new VariableVirtualStackValueMap<>(initialVariableCapacity, initialStackSlotCapacity);
+        blockData = new BlockMap<>(cfg);
+    }
+
+    @Override
+    public void accessOperand(Value operand, AbstractBlockBase<?> block) {
+        assert block != null : "block is null";
+        if (operand instanceof CompositeValue) {
+            ((CompositeValue) operand).forEachComponent(null, OperandMode.USE, (op, value, mode, flag) -> {
+                accessOperand(value, block);
+                return value;
+            });
+        } else if (processValue(operand)) {
+            AbstractBlockBase<?> defBlock = getDefinitionBlock(operand);
+            assert defBlock != null : "Value is not defined: " + operand;
+            assert AbstractControlFlowGraph.dominates(defBlock, block) : "Block " + defBlock + " does not dominate " + block;
+            accessRecursive(operand, defBlock, block);
+        }
+    }
+
+    @Override
+    public void defineOperand(Value operand, AbstractBlockBase<?> block) {
+        assert block != null : "block is null";
+        if (processValue(operand)) {
+            AbstractBlockBase<?> defBlock = getDefinitionBlock(operand);
+            if (defBlock == null) {
+                setDefinitionBlock(operand, block);
+            } else {
+                /*
+                 * Redefinition: this can happen for nodes that do not produce a new value but proxy
+                 * another one (PiNode, reinterpret).
+                 */
+                assert AbstractControlFlowGraph.dominates(defBlock, block) : String.format("Definition of %s in %s does not dominate the redefinition %s", operand, defBlock, block);
+            }
+        }
+    }
+
+    private static boolean processValue(Value operand) {
+        return isVariable(operand) || isVirtualStackSlot(operand);
+    }
+
+    // setter getter for internal data structures
+
+    private AbstractBlockBase<?> getDefinitionBlock(Value operand) {
+        return valueToDefBlock.get(operand);
+    }
+
+    private void setDefinitionBlock(Value operand, AbstractBlockBase<?> block) {
+        valueToDefBlock.put(operand, block);
+    }
+
+    private BlockData getOrInit(AbstractBlockBase<?> block) {
+        BlockData data = blockData.get(block);
+        if (data == null) {
+            data = new BlockData(initialVariableCapacity, initialStackSlotCapacity);
+            blockData.put(block, data);
+        }
+        return data;
+    }
+
+    // implementation
+
+    private void accessRecursive(Value operand, AbstractBlockBase<?> defBlock, AbstractBlockBase<?> block) {
+        Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>();
+        worklist.add(block);
+
+        while (!worklist.isEmpty()) {
+            accessRecursive(operand, defBlock, worklist.pollLast(), worklist);
+        }
+    }
+
+    private void accessRecursive(Value operand, AbstractBlockBase<?> defBlock, AbstractBlockBase<?> block, Deque<AbstractBlockBase<?>> worklist) {
+        try (Indent indent = Debug.logAndIndent("get operand %s in block %s", operand, block)) {
+            if (block.equals(defBlock)) {
+                Debug.log("found definition!");
+                return;
+            }
+            BlockData data = getOrInit(block);
+            Integer index = data.getIndex(operand);
+            if (index != null) {
+                // value is live at block begin but might not be initialized
+                Value in = data.getIncoming(index);
+                if (Value.ILLEGAL.equals(in)) {
+                    data.setIncoming(index, operand);
+                    Debug.log("uninitialized incoming value -> initialize!");
+                } else {
+                    Debug.log("incoming value already initialized!");
+                }
+                return;
+            }
+
+            // the value is not yet live a current block
+            int idx = addLiveValueToBlock(operand, block);
+            data.setIncoming(idx, operand);
+
+            for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+                worklist.addLast(pred);
+            }
+        }
+    }
+
+    private int addLiveValueToBlock(Value operand, AbstractBlockBase<?> block) {
+        try (Indent indent = Debug.logAndIndent("add incoming value!")) {
+            int index = -1;
+            for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+                try (Indent indent1 = Debug.logAndIndent("Add outgoing operand to %s", pred)) {
+                    BlockData predData = getOrInit(pred);
+                    int predIndex = predData.addOutgoing(operand);
+
+                    if (index == -1) {
+                        index = predIndex;
+                    } else {
+                        assert predIndex == index;
+                    }
+
+                    for (AbstractBlockBase<?> succ : pred.getSuccessors()) {
+                        Debug.log("Add incoming operand to %s", succ);
+                        BlockData succData = getOrInit(succ);
+                        if (!succData.contains(operand)) {
+                            int succIndex = succData.addIncoming(operand);
+                            assert succIndex == predIndex;
+                        }
+                    }
+                }
+            }
+            Debug.log("new index: %d", index);
+            return index;
+        }
+    }
+
+    // finish
+
+    public void finish(LIRGeneratorTool gen) {
+        Debug.dump(gen.getResult().getLIR(), "Before SSI operands");
+        AbstractControlFlowGraph<?> cfg = gen.getResult().getLIR().getControlFlowGraph();
+        for (AbstractBlockBase<?> block : cfg.getBlocks()) {
+            // set label
+            BlockData data = blockData.get(block);
+            if (data != null) {
+                if (data.incoming != null && data.incoming.size() > 0) {
+                    LabelOp label = getLabel(gen, block);
+                    label.addIncomingValues(data.incoming.toArray(new Value[data.incoming.size()]));
+                }
+                // set block end
+                if (data.outgoing != null && data.outgoing.size() > 0) {
+                    BlockEndOp blockEndOp = getBlockEnd(gen, block);
+                    blockEndOp.addOutgoingValues(data.outgoing.toArray(new Value[data.outgoing.size()]));
+                }
+            }
+        }
+    }
+
+    private static List<LIRInstruction> getLIRforBlock(LIRGeneratorTool gen, AbstractBlockBase<?> block) {
+        return gen.getResult().getLIR().getLIRforBlock(block);
+    }
+
+    private static LabelOp getLabel(LIRGeneratorTool gen, AbstractBlockBase<?> block) {
+        return (LabelOp) getLIRforBlock(gen, block).get(0);
+    }
+
+    private static BlockEndOp getBlockEnd(LIRGeneratorTool gen, AbstractBlockBase<?> block) {
+        List<LIRInstruction> instructions = getLIRforBlock(gen, block);
+        return (BlockEndOp) instructions.get(instructions.size() - 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssi/SSIConstructionPhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.ssi;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.ssa.*;
+
+public final class SSIConstructionPhase extends PreAllocationOptimizationPhase {
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen) {
+        assert SSAUtil.verifySSAForm(lirGenRes.getLIR());
+        LIR lir = lirGenRes.getLIR();
+        new SSIBuilder(lir, lirGenRes.getFrameMapBuilder()).build(lirGen);
+    }
+
+    private static final class SSIBuilder {
+        private final SSIBlockValueMapImpl valueMap;
+        private final LIR lir;
+        private final BitSet processed;
+
+        private SSIBuilder(LIR lir, FrameMapBuilder frameMapBuilder) {
+            this.lir = lir;
+            valueMap = new SSIBlockValueMapImpl(lir.getControlFlowGraph(), lir.nextVariable(), ((FrameMapBuilderTool) frameMapBuilder).getNumberOfStackSlots());
+            processed = new BitSet(lir.getControlFlowGraph().getBlocks().size());
+        }
+
+        private void build(LIRGeneratorTool lirGen) {
+            Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>(lir.getControlFlowGraph().getBlocks());
+            while (!worklist.isEmpty()) {
+                AbstractBlockBase<?> block = worklist.poll();
+                if (!processed.get(block.getId())) {
+                    try (Indent indent = Debug.logAndIndent("Try processing Block %s", block)) {
+                        // check predecessors
+                        boolean reschedule = false;
+                        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+                            if (!processed.get(pred.getId()) && !isLoopBackEdge(pred, block)) {
+                                Debug.log("Schedule predecessor: %s", pred);
+                                worklist.addLast(pred);
+                                reschedule = true;
+                            }
+                        }
+                        if (reschedule) {
+                            Debug.log("Reschedule block %s", block);
+                            worklist.addLast(block);
+                        } else {
+                            processBlock(block);
+                        }
+                    }
+                }
+            }
+            valueMap.finish(lirGen);
+        }
+
+        public void processBlock(AbstractBlockBase<?> block) {
+            assert !processed.get(block.getId()) : "Block already processed " + block;
+            try (Indent indent = Debug.logAndIndent("Process Block %s", block)) {
+                // track values
+                ValueConsumer useConsumer = (value, mode, flags) -> {
+                    if (flags.contains(OperandFlag.UNINITIALIZED)) {
+                        AbstractBlockBase<?> startBlock = lir.getControlFlowGraph().getStartBlock();
+                        Debug.log("Set definition of %s in block %s", value, startBlock);
+                        valueMap.defineOperand(value, startBlock);
+                    } else {
+                        Debug.log("Access %s in block %s", value, block);
+                        valueMap.accessOperand(value, block);
+                    }
+                };
+                ValueConsumer defConsumer = (value, mode, flags) -> {
+                    Debug.log("Set definition of %s in block %s", value, block);
+                    valueMap.defineOperand(value, block);
+                };
+                for (LIRInstruction op : lir.getLIRforBlock(block)) {
+                    // use
+                    op.visitEachInput(useConsumer);
+                    op.visitEachAlive(useConsumer);
+                    op.visitEachState(useConsumer);
+                    // def
+                    op.visitEachTemp(defConsumer);
+                    op.visitEachOutput(defConsumer);
+                }
+                processed.set(block.getId());
+            }
+        }
+
+        private static boolean isLoopBackEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
+            return from.isLoopEnd() && to.isLoopHeader() && from.getLoop().equals(to.getLoop());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssi/SSIUtil.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.ssi;
+
+import java.util.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.ssa.SSAUtil.*;
+
+/**
+ * Utilities for working with Static-Single-Information LIR form.
+ *
+ * <h2>Representation of &phi; and &sigma;</h2>
+ *
+ * There are no explicit &phi;/&sigma; {@link LIRInstruction}s. Instead, they are implemented as
+ * parallel copy that spans across a control-flow edge.
+ *
+ * The variables introduced by &phi;/&sigma; of a specific {@linkplain AbstractBlockBase block} are
+ * {@linkplain LabelOp#setIncomingValues attached} to the {@link LabelOp} of the block. The outgoing
+ * values from the predecessor are {@linkplain BlockEndOp#setOutgoingValues input} to the
+ * {@link BlockEndOp} of the predecessor.
+ *
+ * When it does not matter whether we are talking about a &phi; or a &sigma; we call the values that
+ * are defined by a label {@linkplain LabelOp#setIncomingValues incoming} and the values that are
+ * input to the {@link BlockEndOp} of the predecessor {@linkplain BlockEndOp#setOutgoingValues
+ * outgoing}.
+ *
+ * <h2>Implementation Details</h2>
+ *
+ * For our purposes we want a <em>maximal</em> SSI form, which means that all values that are alive
+ * across basic block boundaries are gated with a &phi;/&sigma;. In other words the outgoing and
+ * incoming values of the {@link BlockEndOp} and {@link LabelOp} are equivalent to the live-out and
+ * live-in set of the corresponding block.
+ *
+ * As a side effect variables are local to a block. We reuse the name of the predecessor if they
+ * represent the same value (i.e. not a real &phi; definition).
+ *
+ * <h2>Examples</h2>
+ *
+ * <h3>Merge (&phi;)</h3>
+ *
+ * <pre>
+ * B0 -> B1
+ *   ...
+ *   v0|i = ...
+ *   JUMP ~[v0|i, int[0|0x0]] destination: B0 -> B1
+ * ________________________________________________
+ *
+ * B2 -> B1
+ *   ...
+ *   v1|i = ...
+ *   v2|i = ...
+ *   JUMP ~[v1|i, v2|i] destination: B2 -> B1
+ * ________________________________________________
+ *
+ * B1 <- B0,B2
+ *   [v3|i, v4|i] = LABEL
+ *   ...
+ * </pre>
+ *
+ * Note: the outgoing values of a block can contain constants (see <code>B0</code>).
+ *
+ * <h3>Split (&sigma;)</h3>
+ *
+ * <pre>
+ * B0 -> B1,B2
+ *   ...
+ *   v0|i = ...
+ *   v1|i = ...
+ *   v2|i = ...
+ *   TEST (x: v1|i, y: v1|i)
+ *   BRANCH ~[v2|i, v0|j] condition: <, true: B1 false: B2
+ * ________________________________________________
+ *
+ * B1 <- B0
+ *   [-, v0|j] = LABEL
+ *   ...
+ * ________________________________________________
+ *
+ * B2 <- B0
+ *   [v2|i, v0|j] = LABEL
+ *   ...
+ * </pre>
+ *
+ * Note: If a incoming value is not needed in a branch it is {@link Value#ILLEGAL ignored} (see
+ * <code>B1<code>).
+ */
+public final class SSIUtil {
+
+    public static BlockEndOp outgoing(LIR lir, AbstractBlockBase<?> block) {
+        return (BlockEndOp) outgoingInst(lir, block);
+    }
+
+    public static LIRInstruction outgoingInst(LIR lir, AbstractBlockBase<?> block) {
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        int index = instructions.size() - 1;
+        LIRInstruction op = instructions.get(index);
+        return op;
+    }
+
+    public static LabelOp incoming(LIR lir, AbstractBlockBase<?> block) {
+        return (LabelOp) incomingInst(lir, block);
+    }
+
+    private static LIRInstruction incomingInst(LIR lir, AbstractBlockBase<?> block) {
+        return lir.getLIRforBlock(block).get(0);
+    }
+
+    public static void removeIncoming(LIR lir, AbstractBlockBase<?> block) {
+        incoming(lir, block).clearIncomingValues();
+    }
+
+    public static void removeOutgoing(LIR lir, AbstractBlockBase<?> block) {
+        outgoing(lir, block).clearOutgoingValues();
+    }
+
+    /**
+     * Visits each SIGMA/PHI value pair of an edge, i.e. the outgoing value from the predecessor and
+     * the incoming value to the merge block.
+     */
+    public static void forEachValuePair(LIR lir, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> fromBlock, PhiValueVisitor visitor) {
+        assert toBlock.getPredecessors().contains(fromBlock) : String.format("%s not in predecessor list: %s", fromBlock, toBlock.getPredecessors());
+        assert fromBlock.getSuccessorCount() == 1 || toBlock.getPredecessorCount() == 1 : String.format("Critical Edge? %s has %d successors and %s has %d predecessors", fromBlock,
+                        fromBlock.getSuccessorCount(), toBlock, toBlock.getPredecessorCount());
+        assert fromBlock.getSuccessors().contains(toBlock) : String.format("Predecessor block %s has wrong successor: %s, should contain: %s", fromBlock, fromBlock.getSuccessors(), toBlock);
+
+        BlockEndOp blockEnd = outgoing(lir, fromBlock);
+        LabelOp label = incoming(lir, toBlock);
+
+        assert label.getIncomingSize() == blockEnd.getOutgoingSize() : String.format("In/Out size mismatch: in=%d vs. out=%d, blocks %s vs. %s", label.getIncomingSize(), blockEnd.getOutgoingSize(),
+                        toBlock, fromBlock);
+
+        for (int i = 0; i < label.getIncomingSize(); i++) {
+            visitor.visit(label.getIncomingValue(i), blockEnd.getOutgoingValue(i));
+        }
+    }
+
+    public static void forEachRegisterHint(LIR lir, AbstractBlockBase<?> block, LabelOp label, Value targetValue, OperandMode mode, ValueConsumer valueConsumer) {
+        assert mode == OperandMode.DEF : "Wrong operand mode: " + mode;
+        assert lir.getLIRforBlock(block).get(0).equals(label) : String.format("Block %s and Label %s do not match!", block, label);
+
+        if (!label.isPhiIn()) {
+            return;
+        }
+        int idx = indexOfValue(label, targetValue);
+        assert idx >= 0 : String.format("Value %s not in label %s", targetValue, label);
+
+        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+            BlockEndOp blockEnd = outgoing(lir, pred);
+            Value sourceValue = blockEnd.getOutgoingValue(idx);
+            valueConsumer.visitValue((LIRInstruction) blockEnd, sourceValue, null, null);
+        }
+
+    }
+
+    private static int indexOfValue(LabelOp label, Value value) {
+        for (int i = 0; i < label.getIncomingSize(); i++) {
+            if (label.getIncomingValue(i).equals(value)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssi/SSIVerifier.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.ssi;
+
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+
+public final class SSIVerifier {
+
+    public static boolean verify(LIR lir) {
+        return new SSIVerifier(lir).verify();
+    }
+
+    private final LIR lir;
+
+    private SSIVerifier(LIR lir) {
+        this.lir = lir;
+    }
+
+    private boolean verify() {
+        try (Scope s = Debug.scope("SSIVerifier", lir)) {
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+                doBlock(block);
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+        return true;
+    }
+
+    private void doBlock(AbstractBlockBase<?> block) {
+        for (AbstractBlockBase<?> succ : block.getSuccessors()) {
+            verifyEdge(block, succ);
+        }
+        verifyInstructions(block);
+    }
+
+    private void verifyEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
+        BlockEndOp out = SSIUtil.outgoing(lir, from);
+        LabelOp in = SSIUtil.incoming(lir, to);
+        int outgoingSize = out.getOutgoingSize();
+        int incomingSize = in.getIncomingSize();
+        assert outgoingSize == incomingSize : String.format("Outgoing size %d and incoming size %d do not match", outgoingSize, incomingSize);
+
+        for (int i = 0; i < outgoingSize; i++) {
+            Value incomingValue = in.getIncomingValue(i);
+            Value outgoingValue = out.getOutgoingValue(i);
+            LIRKind inLIRKind = incomingValue.getLIRKind();
+            LIRKind outLIRKind = outgoingValue.getLIRKind();
+            assert LIRKind.verifyMoveKinds(inLIRKind, outLIRKind) || incomingValue.equals(Value.ILLEGAL) : String.format("Outgoing LIRKind %s (%s) an and incoming LIRKind %s (%s) do not match",
+                            outgoingValue, outLIRKind, incomingValue, inLIRKind);
+        }
+    }
+
+    private void verifyInstructions(AbstractBlockBase<?> block) {
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        HashMap<Value, LIRInstruction> defined = new HashMap<>();
+
+        InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
+            public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (checkUsage(value)) {
+                    assert defined.containsKey(value) || flags.contains(OperandFlag.UNINITIALIZED) : String.format("Value %s is used by instruction %s in block %s but not defined.", value,
+                                    instruction, block);
+                }
+            }
+        };
+        InstructionValueConsumer stateConsumer = new InstructionValueConsumer() {
+            public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (checkUsage(value)) {
+                    /*
+                     * TODO (je): There are undefined stack values used for locks. Ignore them for
+                     * the time being.
+                     */
+                    assert defined.containsKey(value) || isVirtualStackSlot(value) : String.format("Value %s is used in state of instruction %s in block %s but not defined.", value, instruction,
+                                    block);
+                }
+            }
+        };
+
+        InstructionValueConsumer defConsumer = new InstructionValueConsumer() {
+            public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (trackDefinition(value)) {
+                    assert !defined.containsKey(value) : String.format("Value %s is redefined by instruction %s in block %s but already defined by %s.", value, instruction, block, defined.get(value));
+                    defined.put(value, instruction);
+                }
+            }
+        };
+
+        for (LIRInstruction op : instructions) {
+            op.visitEachAlive(useConsumer);
+            op.visitEachInput(useConsumer);
+            op.visitEachState(stateConsumer);
+
+            op.visitEachTemp(defConsumer);
+            op.visitEachOutput(defConsumer);
+        }
+    }
+
+    private static boolean trackDefinition(Value value) {
+        if (isRegister(value)) {
+            // registers can be redefined
+            return false;
+        }
+        if (value.equals(Value.ILLEGAL)) {
+            // Don't care about illegal values
+            return false;
+        }
+        return true;
+    }
+
+    private static boolean checkUsage(Value value) {
+        if (value instanceof Constant) {
+            // Constants do not need to be defined
+            return false;
+        }
+        if (isRegister(value)) {
+            // Assume fixed registers are correct
+            return false;
+        }
+        if (value.equals(Value.ILLEGAL)) {
+            // Don't care about illegal values
+            return false;
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/GenericValueMap.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.util;
+
+import java.util.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.*;
+
+public final class GenericValueMap<T> extends ValueMap<Value, T> {
+
+    private final Map<Value, T> data;
+
+    public GenericValueMap() {
+        data = CollectionsFactory.newMap();
+    }
+
+    @Override
+    public T get(Value value) {
+        return data.get(value);
+    }
+
+    @Override
+    public void remove(Value value) {
+        data.remove(value);
+    }
+
+    @Override
+    public void put(Value value, T object) {
+        data.put(value, object);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/IndexedValueMap.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.util;
+
+import java.util.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+
+public final class IndexedValueMap {
+    private Value[] values;
+
+    public IndexedValueMap() {
+        values = Value.NO_VALUES;
+    }
+
+    public IndexedValueMap(IndexedValueMap other) {
+        int limit = other.values.length;
+        while (limit > 0) {
+            if (other.values[limit - 1] == null) {
+                limit--;
+                continue;
+            }
+            break;
+        }
+        values = new Value[limit];
+        System.arraycopy(other.values, 0, values, 0, values.length);
+    }
+
+    public Value get(int index) {
+        return values[index];
+    }
+
+    public void put(int index, Value value) {
+        if (values.length <= index) {
+            if (value == null) {
+                return;
+            }
+            Value[] newValues = new Value[index + 1];
+            System.arraycopy(values, 0, newValues, 0, values.length);
+            values = newValues;
+            values[index] = value;
+        } else {
+            values[index] = value;
+        }
+    }
+
+    public void putAll(IndexedValueMap stack) {
+        Value[] otherValues = stack.values;
+        int limit = otherValues.length;
+        if (limit > values.length) {
+            while (limit > 0) {
+                if (otherValues[limit - 1] == null) {
+                    limit--;
+                    continue;
+                }
+                break;
+            }
+            if (limit > values.length) {
+                Value[] newValues = new Value[limit];
+                System.arraycopy(values, 0, newValues, 0, values.length);
+                values = newValues;
+            }
+        }
+        for (int i = 0; i < limit; i++) {
+            Value value = otherValues[i];
+            if (value != null) {
+                values[i] = value;
+            }
+        }
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof IndexedValueMap) {
+            IndexedValueMap that = (IndexedValueMap) other;
+            int limit = Math.min(values.length, that.values.length);
+            for (int i = 0; i < limit; i++) {
+                if (!Objects.equals(values[i], that.values[i])) {
+                    return false;
+                }
+            }
+            for (int i = limit; i < values.length; i++) {
+                if (values[i] != null) {
+                    return false;
+                }
+            }
+            for (int i = limit; i < that.values.length; i++) {
+                if (that.values[i] != null) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public void forEach(LIRInstruction inst, OperandMode mode, EnumSet<OperandFlag> flags, InstructionValueProcedure proc) {
+        for (int i = 0; i < values.length; i++) {
+            if (values[i] != null) {
+                values[i] = proc.doValue(inst, values[i], mode, flags);
+            }
+        }
+    }
+
+    public void forEach(LIRInstruction inst, OperandMode mode, EnumSet<OperandFlag> flags, InstructionValueConsumer consumer) {
+        for (Value v : values) {
+            if (v != null) {
+                consumer.visitValue(inst, v, mode, flags);
+            }
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("[");
+        boolean comma = false;
+
+        for (int i = 0; i < values.length; i++) {
+            if (values[i] != null) {
+                if (comma) {
+                    sb.append(", ");
+                } else {
+                    comma = true;
+                }
+
+                sb.append(i);
+                sb.append(": ");
+                sb.append(values[i]);
+            }
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/ValueMap.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.util;
+
+import jdk.internal.jvmci.meta.*;
+
+/**
+ * A map interface to map {@link Value}s to other objects.
+ */
+public abstract class ValueMap<K extends Value, T> {
+
+    /**
+     * Gets the object associated with {@code value} or {@code null} if there is no such mapping.
+     */
+    public abstract T get(K value);
+
+    /**
+     * Removes the object associated with {@code value} from the map.
+     */
+    public abstract void remove(K value);
+
+    /**
+     * Associates {@code object} with {@code value}.
+     */
+    public abstract void put(K value, T object);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/ValueSet.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.util;
+
+import jdk.internal.jvmci.meta.*;
+
+public abstract class ValueSet<S extends ValueSet<S>> {
+
+    public abstract void put(Value v);
+
+    public abstract void remove(Value v);
+
+    public abstract void putAll(S s);
+
+    public abstract S copy();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/VariableVirtualStackValueMap.java	Wed Jul 29 11:59:18 2015 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.util;
+
+import static com.oracle.graal.lir.LIRValueUtil.*;
+import static jdk.internal.jvmci.code.ValueUtil.*;
+import jdk.internal.jvmci.common.*;
+import jdk.internal.jvmci.meta.*;
+
+public class VariableVirtualStackValueMap<K extends Value, T> extends ValueMap<K, T> {
+
+    private final Object[] variables;
+    private final Object[] slots;
+
+    public VariableVirtualStackValueMap(int initialVariableCapacity, int initialStackSlotCapacity) {
+        variables = new Object[initialVariableCapacity];
+        slots = new Object[initialStackSlotCapacity];
+    }
+
+    @Override
+    public T get(K value) {
+        if (isVariable(value)) {
+            return get(variables, asVariable(value).index);
+        }
+        if (isVirtualStackSlot(value)) {
+            return get(slots, asVirtualStackSlot(value).getId());
+        }
+        throw JVMCIError.shouldNotReachHere("Unsupported Value: " + value);
+    }
+
+    @Override
+    public void remove(K value) {
+        if (isVariable(value)) {
+            remove(variables, asVariable(value).index);
+        } else if (isVirtualStackSlot(value)) {
+            remove(slots, asVirtualStackSlot(value).getId());
+        } else {
+            throw JVMCIError.shouldNotReachHere("Unsupported Value: " + value);
+        }
+    }
+
+    @Override
+    public void put(K value, T object) {
+        if (isVariable(value)) {
+            put(variables, asVariable(value).index, object);
+        } else if (isVirtualStackSlot(value)) {
+            put(slots, asVirtualStackSlot(value).getId(), object);
+        } else {
+            throw JVMCIError.shouldNotReachHere("Unsupported Value: " + value);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> T get(Object[] array, int index) {
+        if (index >= array.length) {
+            return null;
+        }
+        return (T) array[index];
+    }
+
+    private static void remove(Object[] array, int index) {
+        if (index >= array.length) {
+            return;
+        }
+        array[index] = null;
+    }
+
+    private static <T> Object[] put(Object[] array, int index, T object) {
+        if (index >= array.length) {
+            Object[] newArray = new Object[index + 1];
+            System.arraycopy(array, 0, newArray, 0, array.length);
+            newArray[index] = object;
+            return newArray;
+        }
+        array[index] = object;
+        return null;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * A node that changes the type of its input, usually narrowing it. For example, a GuardedValueNode
@@ -72,9 +73,9 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            tool.replaceWithVirtual(state.getVirtualObject());
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            tool.replaceWithVirtual((VirtualObjectNode) alias);
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * A node that changes the type of its input, usually narrowing it. For example, a {@link PiNode}
@@ -90,9 +91,12 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual && StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
-            tool.replaceWithVirtual(state.getVirtualObject());
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            if (StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(virtual.type())) {
+                tool.replaceWithVirtual(virtual);
+            }
         }
     }
 
@@ -107,18 +111,15 @@
             return object();
         }
         if (getGuard() != null) {
-            for (Node use : getGuard().asNode().usages()) {
-                if (use instanceof PiNode) {
-                    PiNode otherPi = (PiNode) use;
-                    if (object() == otherPi.object() && stamp().equals(otherPi.stamp())) {
-                        /*
-                         * Two PiNodes with the same guard and same result, so return the one with
-                         * the more precise piStamp.
-                         */
-                        Stamp newStamp = piStamp.join(otherPi.piStamp);
-                        if (newStamp.equals(otherPi.piStamp)) {
-                            return otherPi;
-                        }
+            for (PiNode otherPi : getGuard().asNode().usages().filter(PiNode.class)) {
+                if (object() == otherPi.object() && stamp().equals(otherPi.stamp())) {
+                    /*
+                     * Two PiNodes with the same guard and same result, so return the one with the
+                     * more precise piStamp.
+                     */
+                    Stamp newStamp = piStamp.join(otherPi.piStamp);
+                    if (newStamp.equals(otherPi.piStamp)) {
+                        return otherPi;
                     }
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Wed Jul 29 11:59:18 2015 +0200
@@ -42,7 +42,7 @@
  * A graph that contains at least one distinguished node : the {@link #start() start} node. This
  * node is the start of the control flow of the graph.
  */
-public class StructuredGraph extends Graph implements JavaMethodContex {
+public class StructuredGraph extends Graph implements JavaMethodContext {
 
     /**
      * The different stages of the compilation of a {@link Graph} regarding the status of
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 @NodeInfo(nameTemplate = "Proxy({i#value})")
 public final class ValueProxyNode extends ProxyNode implements Canonicalizable, Virtualizable, ValueProxy {
@@ -58,9 +59,9 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(value);
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            tool.replaceWithVirtual(state.getVirtualObject());
+        ValueNode alias = tool.getAlias(value);
+        if (alias instanceof VirtualObjectNode) {
+            tool.replaceWithVirtual((VirtualObjectNode) alias);
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -68,8 +68,10 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        if (tool.getObjectState(getValue()) != null) {
-            tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
+        ValueNode alias = tool.getAlias(getValue());
+        TriState fold = tryFold(alias.stamp());
+        if (fold != TriState.UNKNOWN) {
+            tool.replaceWithValue(LogicConstantNode.forBoolean(fold.isTrue(), graph()));
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -34,6 +34,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 @NodeInfo(shortName = "==")
 public final class ObjectEqualsNode extends PointerEqualsNode implements Virtualizable {
@@ -71,13 +72,13 @@
         return super.canonicalizeSymmetricConstant(tool, constant, nonConstant, mirrored);
     }
 
-    private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) {
-        if (!state.getVirtualObject().hasIdentity() && state.getVirtualObject().entryKind(0) == Kind.Boolean) {
+    private void virtualizeNonVirtualComparison(VirtualObjectNode virtual, ValueNode other, VirtualizerTool tool) {
+        if (!virtual.hasIdentity() && virtual.entryKind(0) == Kind.Boolean) {
             if (other.isConstant()) {
                 JavaConstant otherUnboxed = tool.getConstantReflectionProvider().unboxPrimitive(other.asJavaConstant());
                 if (otherUnboxed != null && otherUnboxed.getKind() == Kind.Boolean) {
                     int expectedValue = otherUnboxed.asBoolean() ? 1 : 0;
-                    IntegerEqualsNode equals = new IntegerEqualsNode(state.getEntry(0), ConstantNode.forInt(expectedValue, graph()));
+                    IntegerEqualsNode equals = new IntegerEqualsNode(tool.getEntry(virtual, 0), ConstantNode.forInt(expectedValue, graph()));
                     tool.addNode(equals);
                     tool.replaceWithValue(equals);
                 } else {
@@ -92,43 +93,42 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State stateX = tool.getObjectState(getX());
-        State stateY = tool.getObjectState(getY());
-        boolean xVirtual = stateX != null && stateX.getState() == EscapeState.Virtual;
-        boolean yVirtual = stateY != null && stateY.getState() == EscapeState.Virtual;
+        ValueNode xAlias = tool.getAlias(getX());
+        ValueNode yAlias = tool.getAlias(getY());
+
+        VirtualObjectNode xVirtual = xAlias instanceof VirtualObjectNode ? (VirtualObjectNode) xAlias : null;
+        VirtualObjectNode yVirtual = yAlias instanceof VirtualObjectNode ? (VirtualObjectNode) yAlias : null;
 
-        if (xVirtual && !yVirtual) {
-            virtualizeNonVirtualComparison(stateX, stateY != null ? stateY.getMaterializedValue() : getY(), tool);
-        } else if (!xVirtual && yVirtual) {
-            virtualizeNonVirtualComparison(stateY, stateX != null ? stateX.getMaterializedValue() : getX(), tool);
-        } else if (xVirtual && yVirtual) {
-            boolean xIdentity = stateX.getVirtualObject().hasIdentity();
-            boolean yIdentity = stateY.getVirtualObject().hasIdentity();
-            if (xIdentity ^ yIdentity) {
+        if (xVirtual != null && yVirtual == null) {
+            virtualizeNonVirtualComparison(xVirtual, yAlias, tool);
+        } else if (xVirtual == null && yVirtual != null) {
+            virtualizeNonVirtualComparison(yVirtual, xAlias, tool);
+        } else if (xVirtual != null && yVirtual != null) {
+            if (xVirtual.hasIdentity() ^ yVirtual.hasIdentity()) {
                 /*
                  * One of the two objects has identity, the other doesn't. In code, this looks like
                  * "Integer.valueOf(a) == new Integer(b)", which is always false.
-                 *
+                 * 
                  * In other words: an object created via valueOf can never be equal to one created
                  * by new in the same compilation unit.
                  */
                 tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
-            } else if (!xIdentity && !yIdentity) {
-                ResolvedJavaType type = stateX.getVirtualObject().type();
-                if (type.equals(stateY.getVirtualObject().type())) {
+            } else if (!xVirtual.hasIdentity() && !yVirtual.hasIdentity()) {
+                ResolvedJavaType type = xVirtual.type();
+                if (type.equals(yVirtual.type())) {
                     MetaAccessProvider metaAccess = tool.getMetaAccessProvider();
                     if (type.equals(metaAccess.lookupJavaType(Integer.class)) || type.equals(metaAccess.lookupJavaType(Long.class))) {
                         // both are virtual without identity: check contents
-                        assert stateX.getVirtualObject().entryCount() == 1 && stateY.getVirtualObject().entryCount() == 1;
-                        assert stateX.getVirtualObject().entryKind(0).getStackKind() == Kind.Int || stateX.getVirtualObject().entryKind(0) == Kind.Long;
-                        IntegerEqualsNode equals = new IntegerEqualsNode(stateX.getEntry(0), stateY.getEntry(0));
+                        assert xVirtual.entryCount() == 1 && yVirtual.entryCount() == 1;
+                        assert xVirtual.entryKind(0).getStackKind() == Kind.Int || xVirtual.entryKind(0) == Kind.Long;
+                        IntegerEqualsNode equals = new IntegerEqualsNode(tool.getEntry(xVirtual, 0), tool.getEntry(yVirtual, 0));
                         tool.addNode(equals);
                         tool.replaceWithValue(equals);
                     }
                 }
             } else {
                 // both are virtual with identity: check if they refer to the same object
-                tool.replaceWithValue(LogicConstantNode.forBoolean(stateX == stateY, graph()));
+                tool.replaceWithValue(LogicConstantNode.forBoolean(xVirtual == yVirtual, graph()));
             }
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * This is a special version of the dynamic counter node that removes itself as soon as it's the
@@ -55,8 +56,8 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(checkedValue);
-        if (state != null && state.getState() == EscapeState.Virtual) {
+        ValueNode alias = tool.getAlias(checkedValue);
+        if (alias instanceof VirtualObjectNode) {
             tool.delete();
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -76,13 +76,13 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        ValueNode v = tool.getReplacedValue(getValue());
+        ValueNode alias = tool.getAlias(getValue());
         ResolvedJavaType type = StampTool.typeOrNull(stamp());
 
         VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind);
         assert newVirtual.getFields().length == 1;
 
-        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, Collections.<MonitorIdNode> emptyList(), false);
+        tool.createVirtualObject(newVirtual, new ValueNode[]{alias}, Collections.<MonitorIdNode> emptyList(), false);
         tool.replaceWithVirtual(newVirtual);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GetClassNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GetClassNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * Loads an object's class (i.e., this node can be created for {@code object.getClass()}).
@@ -87,9 +88,10 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
-        if (state != null) {
-            Constant javaClass = state.getVirtualObject().type().getJavaClass();
+        ValueNode alias = tool.getAlias(getObject());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            Constant javaClass = virtual.type().getJavaClass();
             tool.replaceWithValue(ConstantNode.forConstant(stamp(), javaClass, tool.getMetaAccessProvider(), graph()));
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -22,8 +22,8 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import jdk.internal.jvmci.meta.Assumptions.AssumptionResult;
 import jdk.internal.jvmci.meta.*;
-import jdk.internal.jvmci.meta.Assumptions.*;
 
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -116,10 +116,10 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(value);
-        if (state != null) {
-            Constant constantHub = state.getVirtualObject().type().getObjectHub();
-            tool.replaceWithValue(ConstantNode.forConstant(stamp(), constantHub, tool.getMetaAccessProvider(), graph()));
+        ValueNode alias = tool.getAlias(getValue());
+        ResolvedJavaType type = findSynonymType(graph(), tool.getMetaAccessProvider(), alias);
+        if (type != null) {
+            tool.replaceWithValue(ConstantNode.forConstant(stamp(), type.getObjectHub(), tool.getMetaAccessProvider(), graph()));
         }
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
 
 @NodeInfo
 public final class UnboxNode extends FixedWithNextNode implements Virtualizable, Lowerable, Canonicalizable.Unary<ValueNode> {
@@ -68,12 +69,13 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(getValue());
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            ResolvedJavaType objectType = state.getVirtualObject().type();
+        ValueNode alias = tool.getAlias(getValue());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            ResolvedJavaType objectType = virtual.type();
             ResolvedJavaType expectedType = tool.getMetaAccessProvider().lookupJavaType(boxingKind.toBoxedJavaClass());
             if (objectType.equals(expectedType)) {
-                tool.replaceWithValue(state.getEntry(0));
+                tool.replaceWithValue(tool.getEntry(virtual, 0));
             }
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * The {@code UnsafeCastNode} produces the same value as its input, but with a different type. It
@@ -92,9 +93,12 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual && StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
-            tool.replaceWithVirtual(state.getVirtualObject());
+        ValueNode alias = tool.getAlias(object);
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            if (StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(virtual.type())) {
+                tool.replaceWithVirtual(virtual);
+            }
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * Load of a value from a location specified as an offset relative to an object. No null check is
@@ -60,16 +61,17 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object());
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            ValueNode offsetValue = tool.getReplacedValue(offset());
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            ValueNode offsetValue = tool.getAlias(offset());
             if (offsetValue.isConstant()) {
                 long off = offsetValue.asJavaConstant().asLong();
-                int entryIndex = state.getVirtualObject().entryIndexForOffset(off, accessKind());
+                int entryIndex = virtual.entryIndexForOffset(off, accessKind());
 
                 if (entryIndex != -1) {
-                    ValueNode entry = state.getEntry(entryIndex);
-                    Kind entryKind = state.getVirtualObject().entryKind(entryIndex);
+                    ValueNode entry = tool.getEntry(virtual, entryIndex);
+                    Kind entryKind = virtual.entryKind(entryIndex);
                     if (entry.getKind() == getKind() || entryKind == accessKind()) {
                         tool.replaceWith(entry);
                     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * Store of a value at a location specified as an offset relative to an object. No null check is
@@ -79,26 +80,27 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object());
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            ValueNode indexValue = tool.getReplacedValue(offset());
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            ValueNode indexValue = tool.getAlias(offset());
             if (indexValue.isConstant()) {
                 long off = indexValue.asJavaConstant().asLong();
-                int entryIndex = state.getVirtualObject().entryIndexForOffset(off, accessKind());
+                int entryIndex = virtual.entryIndexForOffset(off, accessKind());
                 if (entryIndex != -1) {
-                    Kind entryKind = state.getVirtualObject().entryKind(entryIndex);
-                    ValueNode entry = state.getEntry(entryIndex);
+                    Kind entryKind = virtual.entryKind(entryIndex);
+                    ValueNode entry = tool.getEntry(virtual, entryIndex);
                     if (entry.getKind() == value.getKind() || entryKind == accessKind()) {
-                        tool.setVirtualEntry(state, entryIndex, value(), true);
+                        tool.setVirtualEntry(virtual, entryIndex, value(), true);
                         tool.delete();
                     } else {
                         if ((accessKind() == Kind.Long || accessKind() == Kind.Double) && entryKind == Kind.Int) {
-                            int nextIndex = state.getVirtualObject().entryIndexForOffset(off + 4, entryKind);
+                            int nextIndex = virtual.entryIndexForOffset(off + 4, entryKind);
                             if (nextIndex != -1) {
-                                Kind nextKind = state.getVirtualObject().entryKind(nextIndex);
+                                Kind nextKind = virtual.entryKind(nextIndex);
                                 if (nextKind == Kind.Int) {
-                                    tool.setVirtualEntry(state, entryIndex, value(), true);
-                                    tool.setVirtualEntry(state, nextIndex, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()), true);
+                                    tool.setVirtualEntry(virtual, entryIndex, value(), true);
+                                    tool.setVirtualEntry(virtual, nextIndex, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()), true);
                                     tool.delete();
                                 }
                             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph.
@@ -94,13 +95,14 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        if (anchored != null && !(anchored instanceof AbstractBeginNode)) {
-            State state = tool.getObjectState(anchored);
-            if (state == null || state.getState() != EscapeState.Virtual) {
-                return;
+        if (anchored == null || anchored instanceof AbstractBeginNode) {
+            tool.delete();
+        } else {
+            ValueNode alias = tool.getAlias(anchored);
+            if (alias instanceof VirtualObjectNode) {
+                tool.delete();
             }
         }
-        tool.delete();
     }
 
     public void removeAnchoredNode() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -136,10 +136,14 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(array());
-        if (state != null) {
-            assert state.getVirtualObject().type().isArray();
-            tool.replaceWithValue(ConstantNode.forInt(state.getVirtualObject().entryCount(), graph()));
+        ValueNode alias = tool.getAlias(array());
+        ValueNode length = GraphUtil.arrayLength(alias);
+        if (length != null) {
+            ValueNode lengthAlias = tool.getAlias(length);
+            if (!lengthAlias.isAlive()) {
+                lengthAlias = graph().addOrUnique(lengthAlias);
+            }
+            tool.replaceWithValue(lengthAlias);
         }
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -240,11 +240,9 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            if (type.isAssignableFrom(state.getVirtualObject().type())) {
-                tool.replaceWithVirtual(state.getVirtualObject());
-            }
+        ValueNode alias = tool.getAlias(object);
+        if (tryFold(alias.stamp()) == TriState.TRUE) {
+            tool.replaceWith(alias);
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -164,9 +164,10 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(getValue());
-        if (state != null) {
-            tool.replaceWithValue(LogicConstantNode.forBoolean(type().isAssignableFrom(state.getVirtualObject().type()), graph()));
+        ValueNode alias = tool.getAlias(getValue());
+        TriState fold = tryFold(alias.stamp());
+        if (fold != TriState.UNKNOWN) {
+            tool.replaceWithValue(LogicConstantNode.forBoolean(fold.isTrue(), graph()));
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -121,11 +121,11 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object());
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            int fieldIndex = ((VirtualInstanceNode) state.getVirtualObject()).fieldIndex(field());
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            int fieldIndex = ((VirtualInstanceNode) alias).fieldIndex(field());
             if (fieldIndex != -1) {
-                tool.replaceWith(state.getEntry(fieldIndex));
+                tool.replaceWith(tool.getEntry((VirtualObjectNode) alias, fieldIndex));
             }
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * The {@code LoadIndexedNode} represents a read from an element of an array.
@@ -79,12 +80,13 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State arrayState = tool.getObjectState(array());
-        if (arrayState != null && arrayState.getState() == EscapeState.Virtual) {
-            ValueNode indexValue = tool.getReplacedValue(index());
+        ValueNode alias = tool.getAlias(array());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualArrayNode virtual = (VirtualArrayNode) alias;
+            ValueNode indexValue = tool.getAlias(index());
             int idx = indexValue.isConstant() ? indexValue.asJavaConstant().asInt() : -1;
-            if (idx >= 0 && idx < arrayState.getVirtualObject().entryCount()) {
-                tool.replaceWith(arrayState.getEntry(idx));
+            if (idx >= 0 && idx < virtual.entryCount()) {
+                tool.replaceWith(tool.getEntry(virtual, idx));
             }
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * The {@code MonitorEnterNode} represents the acquisition of a monitor.
@@ -55,10 +56,13 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object());
-        if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
-            state.addLock(getMonitorId());
-            tool.delete();
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            if (virtual.hasIdentity()) {
+                tool.addLock(virtual, getMonitorId());
+                tool.delete();
+            }
         }
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * The {@code MonitorExitNode} represents a monitor release. If it is the release of the monitor of
@@ -79,12 +80,15 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object());
         // the monitor exit for a synchronized method should never be virtualized
-        if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
-            MonitorIdNode removedLock = state.removeLock();
-            assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId();
-            tool.delete();
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            if (virtual.hasIdentity()) {
+                MonitorIdNode removedLock = tool.removeLock(virtual);
+                assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId();
+                tool.delete();
+            }
         }
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -74,9 +74,9 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        ValueNode replacedLength = tool.getReplacedValue(length());
-        if (replacedLength.asConstant() != null) {
-            final int constantLength = replacedLength.asJavaConstant().asInt();
+        ValueNode lengthAlias = tool.getAlias(length());
+        if (lengthAlias.asConstant() != null) {
+            int constantLength = lengthAlias.asJavaConstant().asInt();
             if (constantLength >= 0 && constantLength < tool.getMaximumEntryCount()) {
                 ValueNode[] state = new ValueNode[constantLength];
                 ConstantNode defaultForKind = constantLength == 0 ? null : defaultElementValue();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * The {@code MonitorEnterNode} represents the acquisition of a monitor. The object needs already be
@@ -61,10 +62,13 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object());
-        if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
-            state.addLock(getMonitorId());
-            tool.delete();
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            if (virtual.hasIdentity()) {
+                tool.addLock(virtual, getMonitorId());
+                tool.delete();
+            }
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * This node is used to perform the finalizer registration at the end of the java.lang.Object
@@ -94,8 +95,8 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(getValue());
-        if (state != null && !state.getVirtualObject().type().hasFinalizer()) {
+        ValueNode alias = tool.getAlias(getValue());
+        if (alias instanceof VirtualObjectNode && !((VirtualObjectNode) alias).type().hasFinalizer()) {
             tool.delete();
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -72,11 +72,12 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object());
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            int fieldIndex = ((VirtualInstanceNode) state.getVirtualObject()).fieldIndex(field());
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualInstanceNode virtual = (VirtualInstanceNode) alias;
+            int fieldIndex = virtual.fieldIndex(field());
             if (fieldIndex != -1) {
-                tool.setVirtualEntry(state, fieldIndex, value(), false);
+                tool.setVirtualEntry(virtual, fieldIndex, value(), false);
                 tool.delete();
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * The {@code StoreIndexedNode} represents a write to an array element.
@@ -66,15 +67,16 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State arrayState = tool.getObjectState(array());
-        if (arrayState != null && arrayState.getState() == EscapeState.Virtual) {
-            ValueNode indexValue = tool.getReplacedValue(index());
+        ValueNode alias = tool.getAlias(array());
+        if (alias instanceof VirtualObjectNode) {
+            ValueNode indexValue = tool.getAlias(index());
             int idx = indexValue.isConstant() ? indexValue.asJavaConstant().asInt() : -1;
-            if (idx >= 0 && idx < arrayState.getVirtualObject().entryCount()) {
-                ResolvedJavaType componentType = arrayState.getVirtualObject().type().getComponentType();
+            VirtualArrayNode virtual = (VirtualArrayNode) alias;
+            if (idx >= 0 && idx < virtual.entryCount()) {
+                ResolvedJavaType componentType = virtual.type().getComponentType();
                 if (componentType.isPrimitive() || StampTool.isPointerAlwaysNull(value) || componentType.getSuperclass() == null ||
                                 (StampTool.typeOrNull(value) != null && componentType.isAssignableFrom(StampTool.typeOrNull(value)))) {
-                    tool.setVirtualEntry(arrayState, idx, value(), false);
+                    tool.setVirtualEntry(virtual, idx, value(), false);
                     tool.delete();
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -47,6 +47,7 @@
         this.type = type;
         assert type != null;
         assert type.isConcrete() || type.isArray();
+        assert ((ObjectStamp) object.stamp()).nonNull();
     }
 
     public static LogicNode create(ResolvedJavaType type, ValueNode object) {
@@ -71,7 +72,6 @@
             return this;
         }
         ObjectStamp objectStamp = (ObjectStamp) forValue.stamp();
-        assert objectStamp.nonNull();
 
         ResolvedJavaType stampType = objectStamp.type();
         if (stampType != null) {
@@ -123,9 +123,10 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(getValue());
-        if (state != null) {
-            tool.replaceWithValue(LogicConstantNode.forBoolean(type().equals(state.getVirtualObject().type()), graph()));
+        ValueNode alias = tool.getAlias(getValue());
+        TriState state = tryFold(alias.stamp());
+        if (state != TriState.UNKNOWN) {
+            tool.replaceWithValue(LogicConstantNode.forBoolean(state.isTrue(), graph()));
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Wed Jul 29 11:59:18 2015 +0200
@@ -22,10 +22,6 @@
  */
 package com.oracle.graal.nodes.spi;
 
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.virtual.*;
-
 /**
  * This interface allows a node to convey information about what its effect would be if some of its
  * inputs were virtualized. The {@link #virtualize(VirtualizerTool)} method will only be called for
@@ -34,30 +30,6 @@
  */
 public interface Virtualizable {
 
-    public static enum EscapeState {
-        Virtual,
-        Materialized
-    }
-
-    public abstract static class State {
-
-        public abstract EscapeState getState();
-
-        public abstract VirtualObjectNode getVirtualObject();
-
-        public abstract ValueNode getEntry(int index);
-
-        public abstract void addLock(MonitorIdNode monitorId);
-
-        public abstract MonitorIdNode removeLock();
-
-        public abstract ValueNode getMaterializedValue();
-
-        public abstract void setEnsureVirtualized(boolean ensureVirtualized);
-
-        public abstract boolean getEnsureVirtualized();
-    }
-
     /**
      * A node class can implement this method to convey information about what its effect would be
      * if some of its inputs were virtualized. All modifications must be made through the supplied
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Wed Jul 29 11:59:18 2015 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.Virtualizable.State;
 import com.oracle.graal.nodes.virtual.*;
 
 /**
@@ -72,45 +71,43 @@
     void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks, boolean ensureVirtualized);
 
     /**
-     * Queries the current state of the given value: if it is virtualized (thread-local and the
-     * compiler knows all entries) or not.
+     * Returns a VirtualObjectNode if the given value is aliased with a virtual object that is still
+     * virtual, the materialized value of the given value is aliased with a virtual object that was
+     * materialized, the replacement if the give value was replaced, otherwise the given value.
      *
-     * @param value the value whose state should be queried.
-     * @return the {@link State} representing the value if it has been virtualized at some point,
-     *         null otherwise.
+     * Replacements via {@link #replaceWithValue(ValueNode)} are not immediately committed. This
+     * method can be used to determine if a value was replaced by another one (e.g., a load field by
+     * the loaded value).
      */
-    State getObjectState(ValueNode value);
+    ValueNode getAlias(ValueNode value);
 
     /**
      * Sets the entry (field or array element) with the given index in the virtualized object.
      *
-     * @param state the state.
      * @param index the index to be set.
      * @param value the new value for the given index.
      * @param unsafe if true, then mismatching value {@link Kind}s will be accepted.
      */
-    void setVirtualEntry(State state, int index, ValueNode value, boolean unsafe);
+    void setVirtualEntry(VirtualObjectNode virtualObject, int index, ValueNode value, boolean unsafe);
 
-    // scalar replacement
+    ValueNode getEntry(VirtualObjectNode virtualObject, int index);
+
+    void addLock(VirtualObjectNode virtualObject, MonitorIdNode monitorId);
 
-    /**
-     * Replacements via {@link #replaceWithValue(ValueNode)} are not immediately committed. This
-     * method can be used to determine if a value was replaced by another one (e.g., a load field by
-     * the loaded value).
-     *
-     * @param original the original input value.
-     * @return the replacement value, or the original value if there is no replacement.
-     */
-    ValueNode getReplacedValue(ValueNode original);
+    MonitorIdNode removeLock(VirtualObjectNode virtualObject);
+
+    void setEnsureVirtualized(VirtualObjectNode virtualObject, boolean ensureVirtualized);
+
+    boolean getEnsureVirtualized(VirtualObjectNode virtualObject);
 
     // operations on the current node
 
     /**
      * Deletes the current node and replaces it with the given virtualized object.
      *
-     * @param virtual the virtualized object that should replace the current node.
+     * @param virtualObject the virtualized object that should replace the current node.
      */
-    void replaceWithVirtual(VirtualObjectNode virtual);
+    void replaceWithVirtual(VirtualObjectNode virtualObject);
 
     /**
      * Deletes the current node and replaces it with the given value.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -44,14 +44,15 @@
     }
 
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            if (state.getVirtualObject() instanceof VirtualBoxingNode) {
-                Throwable exception = new VerificationError("ensureVirtual is not valid for boxing objects: %s", state.getVirtualObject().type().getName());
+        ValueNode alias = tool.getAlias(object);
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            if (virtual instanceof VirtualBoxingNode) {
+                Throwable exception = new VerificationError("ensureVirtual is not valid for boxing objects: %s", virtual.type().getName());
                 throw GraphUtil.approxSourceException(this, exception);
             }
             if (!localOnly) {
-                state.setEnsureVirtualized(true);
+                tool.setEnsureVirtualized(virtual, true);
             }
             tool.delete();
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -35,12 +35,32 @@
 
     public static final NodeClass<VirtualObjectNode> TYPE = NodeClass.create(VirtualObjectNode.class);
     protected boolean hasIdentity;
+    private int objectId = -1;
 
     protected VirtualObjectNode(NodeClass<? extends VirtualObjectNode> c, ResolvedJavaType type, boolean hasIdentity) {
         super(c, StampFactory.exactNonNull(type));
         this.hasIdentity = hasIdentity;
     }
 
+    public final int getObjectId() {
+        return objectId;
+    }
+
+    public final void resetObjectId() {
+        this.objectId = -1;
+    }
+
+    public final void setObjectId(int objectId) {
+        assert objectId != -1;
+        this.objectId = objectId;
+    }
+
+    @Override
+    protected void afterClone(Node other) {
+        super.afterClone(other);
+        resetObjectId();
+    }
+
     /**
      * The type of object described by this {@link VirtualObjectNode}. In case of arrays, this is
      * the array type (and not the component type).
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Wed Jul 29 11:59:18 2015 +0200
@@ -31,8 +31,6 @@
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
-
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Wed Jul 29 11:59:18 2015 +0200
@@ -543,7 +543,7 @@
         }
 
         // print use positions
-        int prev = 0;
+        int prev = -1;
         UsePosList usePosList = interval.usePosList();
         for (int i = usePosList.size() - 1; i >= 0; --i) {
             assert prev < usePosList.usePos(i) : "use positions not sorted";
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Wed Jul 29 11:59:18 2015 +0200
@@ -28,14 +28,13 @@
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
-
 import com.oracle.graal.debug.*;
 
 import jdk.internal.jvmci.meta.*;
 import jdk.internal.jvmci.service.*;
 
 import com.oracle.graal.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
@@ -204,6 +203,8 @@
             }
         } else if (object instanceof StackInterval[]) {
             cfgPrinter.printStackIntervals(message, (StackInterval[]) object);
+        } else if (isBlockList(object)) {
+            cfgPrinter.printCFG(message, getBlockList(object), false);
         }
 
         cfgPrinter.target = null;
@@ -214,6 +215,15 @@
 
     }
 
+    @SuppressWarnings("unchecked")
+    private static List<? extends AbstractBlockBase<?>> getBlockList(Object object) {
+        return (List<? extends AbstractBlockBase<?>>) object;
+    }
+
+    private static boolean isBlockList(Object object) {
+        return object instanceof List<?> && ((List<?>) object).size() > 0 && ((List<?>) object).get(0) instanceof AbstractBlockBase<?>;
+    }
+
     private static DisassemblerProvider disassembler;
 
     private static final DisassemblerProvider NOP_DISASSEMBLER = new DisassemblerProvider() {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java	Wed Jul 29 11:59:18 2015 +0200
@@ -26,10 +26,10 @@
 import java.util.*;
 
 import jdk.internal.jvmci.code.*;
-import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.meta.*;
 
-import com.oracle.graal.lir.dfa.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.util.*;
 
 /**
  * Utility for printing compilation related data structures at various compilation phases. The
@@ -114,7 +114,7 @@
     /**
      * Formats given debug info as a multi line string.
      */
-    protected String debugInfoToString(BytecodePosition codePos, ReferenceMap refMap, ValueSet liveBasePointers, RegisterSaveLayout calleeSaveInfo) {
+    protected String debugInfoToString(BytecodePosition codePos, ReferenceMap refMap, IndexedValueMap liveBasePointers, RegisterSaveLayout calleeSaveInfo) {
         StringBuilder sb = new StringBuilder();
         if (refMap != null) {
             sb.append("reference-map: ");
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraalDebugConfigCustomizer.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraalDebugConfigCustomizer.java	Wed Jul 29 11:59:18 2015 +0200
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.debug.*;
 
-import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.service.*;
 
 import com.oracle.graal.graph.*;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Wed Jul 29 11:59:18 2015 +0200
@@ -35,7 +35,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.*;
 
-import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.meta.*;
 
 import com.oracle.graal.graph.*;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Wed Jul 29 11:59:18 2015 +0200
@@ -35,13 +35,6 @@
 public @interface Snippet {
 
     /**
-     * Specifies whether all FrameStates within this snippet should always be removed. If this is
-     * false, FrameStates are only removed if there are no side-effecting instructions in the
-     * snippet.
-     */
-    boolean removeAllFrameStates() default false;
-
-    /**
      * Denotes a snippet parameter representing 0 or more arguments that will be bound during
      * snippet template {@linkplain SnippetTemplate#instantiate instantiation}. During snippet
      * template creation, its value must be an array whose length specifies the number of arguments
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Wed Jul 29 11:59:18 2015 +0200
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.replacements;
 
+import static com.oracle.graal.debug.Debug.*;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*;
 import static com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates.*;
 import static java.util.FormattableFlags.*;
-import static com.oracle.graal.debug.Debug.*;
 import static jdk.internal.jvmci.meta.LocationIdentity.*;
 
 import java.lang.reflect.*;
@@ -37,15 +37,12 @@
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-
 import jdk.internal.jvmci.meta.*;
 
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
 
 // JaCoCo Exclude
 
@@ -76,32 +77,33 @@
     }
 
     public void virtualize(VirtualizerTool tool) {
-        State state1 = tool.getObjectState(array1);
-        if (state1 != null) {
-            State state2 = tool.getObjectState(array2);
-            if (state2 != null) {
-                if (state1.getVirtualObject() == state2.getVirtualObject()) {
-                    // the same virtual objects will always have the same contents
+        ValueNode alias1 = tool.getAlias(array1);
+        ValueNode alias2 = tool.getAlias(array2);
+        if (alias1 == alias2) {
+            // the same virtual objects will always have the same contents
+            tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
+        } else if (alias1 instanceof VirtualObjectNode && alias2 instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual1 = (VirtualObjectNode) alias1;
+            VirtualObjectNode virtual2 = (VirtualObjectNode) alias2;
+
+            if (virtual1.entryCount() == virtual2.entryCount()) {
+                int entryCount = virtual1.entryCount();
+                boolean allEqual = true;
+                for (int i = 0; i < entryCount; i++) {
+                    ValueNode entry1 = tool.getEntry(virtual1, i);
+                    ValueNode entry2 = tool.getEntry(virtual2, i);
+                    if (entry1 != entry2) {
+                        // the contents might be different
+                        allEqual = false;
+                    }
+                    if (entry1.stamp().alwaysDistinct(entry2.stamp())) {
+                        // the contents are different
+                        tool.replaceWithValue(ConstantNode.forBoolean(false, graph()));
+                        return;
+                    }
+                }
+                if (allEqual) {
                     tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
-                } else if (state1.getVirtualObject().entryCount() == state2.getVirtualObject().entryCount() && state1.getState() == EscapeState.Virtual && state2.getState() == EscapeState.Virtual) {
-                    int entryCount = state1.getVirtualObject().entryCount();
-                    boolean allEqual = true;
-                    for (int i = 0; i < entryCount; i++) {
-                        ValueNode entry1 = state1.getEntry(i);
-                        ValueNode entry2 = state2.getEntry(i);
-                        if (entry1 != entry2) {
-                            // the contents might be different
-                            allEqual = false;
-                        }
-                        if (entry1.stamp().alwaysDistinct(entry2.stamp())) {
-                            // the contents are different
-                            tool.replaceWithValue(ConstantNode.forBoolean(false, graph()));
-                            return;
-                        }
-                    }
-                    if (allEqual) {
-                        tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
-                    }
                 }
             }
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -131,21 +131,11 @@
         return position >= 0 && position + length <= virtualObject.entryCount();
     }
 
-    private static boolean checkEntryTypes(int srcPos, int length, State srcState, ResolvedJavaType destComponentType, VirtualizerTool tool) {
+    private static boolean checkEntryTypes(int srcPos, int length, VirtualObjectNode src, ResolvedJavaType destComponentType, VirtualizerTool tool) {
         if (destComponentType.getKind() == Kind.Object) {
             for (int i = 0; i < length; i++) {
-                ValueNode entry = srcState.getEntry(srcPos + i);
-                State state = tool.getObjectState(entry);
-                ResolvedJavaType type;
-                if (state != null) {
-                    if (state.getState() == EscapeState.Virtual) {
-                        type = state.getVirtualObject().type();
-                    } else {
-                        type = StampTool.typeOrNull(state.getMaterializedValue());
-                    }
-                } else {
-                    type = StampTool.typeOrNull(entry);
-                }
+                ValueNode entry = tool.getEntry(src, srcPos + i);
+                ResolvedJavaType type = StampTool.typeOrNull(entry);
                 if (type == null || !destComponentType.isAssignableFrom(type)) {
                     return false;
                 }
@@ -177,52 +167,49 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        ValueNode sourcePosition = tool.getReplacedValue(getSourcePosition());
-        ValueNode destinationPosition = tool.getReplacedValue(getDestinationPosition());
-        ValueNode replacedLength = tool.getReplacedValue(getLength());
+        ValueNode sourcePosition = tool.getAlias(getSourcePosition());
+        ValueNode destinationPosition = tool.getAlias(getDestinationPosition());
+        ValueNode replacedLength = tool.getAlias(getLength());
 
         if (sourcePosition.isConstant() && destinationPosition.isConstant() && replacedLength.isConstant()) {
             int srcPosInt = sourcePosition.asJavaConstant().asInt();
             int destPosInt = destinationPosition.asJavaConstant().asInt();
             int len = replacedLength.asJavaConstant().asInt();
-            State destState = tool.getObjectState(getDestination());
+            ValueNode destAlias = tool.getAlias(getDestination());
 
-            if (destState != null && destState.getState() == EscapeState.Virtual) {
-                VirtualObjectNode destVirtual = destState.getVirtualObject();
-                if (!(destVirtual instanceof VirtualArrayNode)) {
-                    return;
-                }
+            if (destAlias instanceof VirtualArrayNode) {
+                VirtualArrayNode destVirtual = (VirtualArrayNode) destAlias;
                 if (len < 0 || !checkBounds(destPosInt, len, destVirtual)) {
                     return;
                 }
-                State srcState = tool.getObjectState(getSource());
-                if (srcState != null && srcState.getState() == EscapeState.Virtual) {
-                    VirtualObjectNode srcVirtual = srcState.getVirtualObject();
-                    if (((VirtualArrayNode) destVirtual).componentType().getKind() != Kind.Object) {
+                ValueNode srcAlias = tool.getAlias(getSource());
+
+                if (srcAlias instanceof VirtualObjectNode) {
+                    if (!(srcAlias instanceof VirtualArrayNode)) {
                         return;
                     }
-                    if (!(srcVirtual instanceof VirtualArrayNode)) {
+                    VirtualArrayNode srcVirtual = (VirtualArrayNode) srcAlias;
+                    if (destVirtual.componentType().getKind() != Kind.Object) {
                         return;
                     }
-                    if (((VirtualArrayNode) srcVirtual).componentType().getKind() != Kind.Object) {
+                    if (srcVirtual.componentType().getKind() != Kind.Object) {
                         return;
                     }
                     if (!checkBounds(srcPosInt, len, srcVirtual)) {
                         return;
                     }
-                    if (!checkEntryTypes(srcPosInt, len, srcState, destVirtual.type().getComponentType(), tool)) {
+                    if (!checkEntryTypes(srcPosInt, len, srcVirtual, destVirtual.type().getComponentType(), tool)) {
                         return;
                     }
                     for (int i = 0; i < len; i++) {
-                        tool.setVirtualEntry(destState, destPosInt + i, srcState.getEntry(srcPosInt + i), false);
+                        tool.setVirtualEntry(destVirtual, destPosInt + i, tool.getEntry(srcVirtual, srcPosInt + i), false);
                     }
                     tool.delete();
                     if (Debug.isLogEnabled()) {
                         Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPosInt, getDestination(), destPosInt, len);
                     }
                 } else {
-                    ValueNode source = srcState == null ? tool.getReplacedValue(getSource()) : srcState.getMaterializedValue();
-                    ResolvedJavaType sourceType = StampTool.typeOrNull(source);
+                    ResolvedJavaType sourceType = StampTool.typeOrNull(srcAlias);
                     if (sourceType == null || !sourceType.isArray()) {
                         return;
                     }
@@ -232,9 +219,9 @@
                         return;
                     }
                     for (int i = 0; i < len; i++) {
-                        LoadIndexedNode load = new LoadIndexedNode(source, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getKind());
+                        LoadIndexedNode load = new LoadIndexedNode(srcAlias, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getKind());
                         tool.addNode(load);
-                        tool.setVirtualEntry(destState, destPosInt + i, load, false);
+                        tool.setVirtualEntry(destVirtual, destPosInt + i, load, false);
                     }
                     tool.delete();
                 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -90,26 +90,20 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State originalState = tool.getObjectState(getObject());
-        if (originalState != null && originalState.getState() == EscapeState.Virtual) {
-            VirtualObjectNode originalVirtual = originalState.getVirtualObject();
+        ValueNode originalAlias = tool.getAlias(getObject());
+        if (originalAlias instanceof VirtualObjectNode) {
+            VirtualObjectNode originalVirtual = (VirtualObjectNode) originalAlias;
             if (isCloneableType(originalVirtual.type(), tool.getMetaAccessProvider())) {
                 ValueNode[] newEntryState = new ValueNode[originalVirtual.entryCount()];
                 for (int i = 0; i < newEntryState.length; i++) {
-                    newEntryState[i] = originalState.getEntry(i);
+                    newEntryState[i] = tool.getEntry(originalVirtual, i);
                 }
                 VirtualObjectNode newVirtual = originalVirtual.duplicate();
                 tool.createVirtualObject(newVirtual, newEntryState, Collections.<MonitorIdNode> emptyList(), false);
                 tool.replaceWithVirtual(newVirtual);
             }
         } else {
-            ValueNode obj;
-            if (originalState != null) {
-                obj = originalState.getMaterializedValue();
-            } else {
-                obj = tool.getReplacedValue(getObject());
-            }
-            ResolvedJavaType type = getConcreteType(obj.stamp(), graph().getAssumptions(), tool.getMetaAccessProvider());
+            ResolvedJavaType type = getConcreteType(originalAlias.stamp(), graph().getAssumptions(), tool.getMetaAccessProvider());
             if (type != null && !type.isArray()) {
                 VirtualInstanceNode newVirtual = createVirtualInstanceNode(type, true);
                 ResolvedJavaField[] fields = newVirtual.getFields();
@@ -117,7 +111,7 @@
                 ValueNode[] state = new ValueNode[fields.length];
                 final LoadFieldNode[] loads = new LoadFieldNode[fields.length];
                 for (int i = 0; i < fields.length; i++) {
-                    state[i] = loads[i] = new LoadFieldNode(obj, fields[i]);
+                    state[i] = loads[i] = new LoadFieldNode(originalAlias, fields[i]);
                     tool.addNode(loads[i]);
                 }
                 tool.createVirtualObject(newVirtual, state, Collections.<MonitorIdNode> emptyList(), false);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/VirtualizableInvokeMacroNode.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/VirtualizableInvokeMacroNode.java	Wed Jul 29 11:59:18 2015 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 
 /**
  * A helper class to allow elimination of byte code instrumentation that could interfere with escape
@@ -46,8 +47,8 @@
     @Override
     public void virtualize(VirtualizerTool tool) {
         for (ValueNode arg : arguments) {
-            State state = tool.getObjectState(arg);
-            if (state != null && state.getState() == EscapeState.Virtual) {
+            ValueNode alias = tool.getAlias(arg);
+            if (alias instanceof VirtualObjectNode) {
                 tool.delete();
             }
         }
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Wed Jul 29 11:59:18 2015 +0200
@@ -35,7 +35,6 @@
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.code.CallingConvention.Type;
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.hotspot.*;
 import jdk.internal.jvmci.meta.*;
 import jdk.internal.jvmci.service.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Wed Jul 29 11:59:18 2015 +0200
@@ -29,15 +29,12 @@
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.code.stack.*;
-import jdk.internal.jvmci.debug.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-
 import jdk.internal.jvmci.meta.*;
 import jdk.internal.jvmci.service.*;
 
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.truffle.debug.*;
 import com.oracle.graal.truffle.unsafe.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedAssumption.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedAssumption.java	Wed Jul 29 11:59:18 2015 +0200
@@ -29,8 +29,8 @@
 import java.util.stream.*;
 
 import jdk.internal.jvmci.code.*;
-import jdk.internal.jvmci.debug.*;
 
+import com.oracle.graal.debug.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.impl.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java	Wed Jul 29 11:59:18 2015 +0200
@@ -31,7 +31,7 @@
  * Enables a Truffle compilable to masquerade as a {@link JavaMethod} for use as a context value in
  * {@linkplain Debug#scope(Object) debug scopes}.
  */
-public class TruffleDebugJavaMethod implements JavaMethod, JavaMethodContex {
+public class TruffleDebugJavaMethod implements JavaMethod, JavaMethodContext {
     private final RootCallTarget compilable;
 
     private static final JavaType declaringClass = new JavaType() {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Wed Jul 29 11:59:18 2015 +0200
@@ -176,8 +176,9 @@
      *
      */
     public void replaceAtUsages(ValueNode node, ValueNode replacement) {
+        assert node != null && replacement != null : node + " " + replacement;
         add("replace at usages", (graph, obsoleteNodes) -> {
-            assert node.isAlive() && replacement.isAlive();
+            assert node.isAlive() && replacement.isAlive() : node + " " + replacement;
             if (replacement instanceof FixedWithNextNode && ((FixedWithNextNode) replacement).next() == null) {
                 assert node instanceof FixedNode;
                 graph.addBeforeFixed((FixedNode) node, (FixedWithNextNode) replacement);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Wed Jul 29 11:59:18 2015 +0200
@@ -28,8 +28,6 @@
 
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.virtual.nodes.*;
 
@@ -38,14 +36,11 @@
  * the fields or array elements (called "entries") and the lock count if the object is still
  * virtual. If the object was materialized, it contains the current materialized value.
  */
-public class ObjectState extends Virtualizable.State {
+public class ObjectState {
 
     public static final DebugMetric CREATE_ESCAPED_OBJECT_STATE = Debug.metric("CreateEscapeObjectState");
     public static final DebugMetric GET_ESCAPED_OBJECT_STATE = Debug.metric("GetEscapeObjectState");
 
-    final VirtualObjectNode virtual;
-
-    private EscapeState state;
     private ValueNode[] entries;
     private ValueNode materializedValue;
     private LockState locks;
@@ -53,35 +48,32 @@
 
     private EscapeObjectState cachedState;
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, List<MonitorIdNode> locks, boolean ensureVirtualized) {
-        this(virtual, entries, state, (LockState) null, ensureVirtualized);
+    boolean copyOnWrite;
+
+    public ObjectState(ValueNode[] entries, List<MonitorIdNode> locks, boolean ensureVirtualized) {
+        this(entries, (LockState) null, ensureVirtualized);
         for (int i = locks.size() - 1; i >= 0; i--) {
             this.locks = new LockState(locks.get(i), this.locks);
         }
     }
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, LockState locks, boolean ensureVirtualized) {
-        this.virtual = virtual;
+    public ObjectState(ValueNode[] entries, LockState locks, boolean ensureVirtualized) {
         this.entries = entries;
-        this.state = state;
         this.locks = locks;
         this.ensureVirtualized = ensureVirtualized;
     }
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks, boolean ensureVirtualized) {
-        this.virtual = virtual;
+    public ObjectState(ValueNode materializedValue, LockState locks, boolean ensureVirtualized) {
+        assert materializedValue != null;
         this.materializedValue = materializedValue;
-        this.state = state;
         this.locks = locks;
         this.ensureVirtualized = ensureVirtualized;
     }
 
     private ObjectState(ObjectState other) {
-        virtual = other.virtual;
         entries = other.entries == null ? null : other.entries.clone();
         materializedValue = other.materializedValue;
         locks = other.locks;
-        state = other.state;
         cachedState = other.cachedState;
         ensureVirtualized = other.ensureVirtualized;
     }
@@ -90,7 +82,7 @@
         return new ObjectState(this);
     }
 
-    public EscapeObjectState createEscapeObjectState() {
+    public EscapeObjectState createEscapeObjectState(VirtualObjectNode virtual) {
         GET_ESCAPED_OBJECT_STATE.increment();
         if (cachedState == null) {
             CREATE_ESCAPED_OBJECT_STATE.increment();
@@ -100,68 +92,55 @@
 
     }
 
-    @Override
-    public EscapeState getState() {
-        return state;
+    public boolean isVirtual() {
+        assert materializedValue == null ^ entries == null;
+        return materializedValue == null;
     }
 
-    @Override
-    public VirtualObjectNode getVirtualObject() {
-        return virtual;
-    }
-
-    public boolean isVirtual() {
-        return state == EscapeState.Virtual;
-    }
-
+    /**
+     * Users of this method are not allowed to change the entries of the returned array.
+     */
     public ValueNode[] getEntries() {
-        assert isVirtual() && entries != null;
+        assert isVirtual();
         return entries;
     }
 
-    @Override
     public ValueNode getEntry(int index) {
         assert isVirtual();
         return entries[index];
     }
 
+    public ValueNode getMaterializedValue() {
+        assert !isVirtual();
+        return materializedValue;
+    }
+
     public void setEntry(int index, ValueNode value) {
         assert isVirtual();
-        if (entries[index] != value) {
-            cachedState = null;
-            entries[index] = value;
-        }
+        cachedState = null;
+        entries[index] = value;
     }
 
-    public void escape(ValueNode materialized, EscapeState newState) {
-        assert state == EscapeState.Virtual && newState == EscapeState.Materialized;
-        state = newState;
+    public void escape(ValueNode materialized) {
+        assert isVirtual();
+        assert materialized != null;
         materializedValue = materialized;
         entries = null;
         cachedState = null;
         assert !isVirtual();
     }
 
-    @Override
-    public ValueNode getMaterializedValue() {
-        assert state == EscapeState.Materialized;
-        return materializedValue;
-    }
-
     public void updateMaterializedValue(ValueNode value) {
         assert !isVirtual();
-        if (value != materializedValue) {
-            cachedState = null;
-            materializedValue = value;
-        }
+        assert value != null;
+        cachedState = null;
+        materializedValue = value;
     }
 
-    @Override
     public void addLock(MonitorIdNode monitorId) {
         locks = new LockState(monitorId, locks);
     }
 
-    @Override
     public MonitorIdNode removeLock() {
         try {
             return locks.monitorId;
@@ -188,12 +167,10 @@
         return a == null && b == null;
     }
 
-    @Override
     public void setEnsureVirtualized(boolean ensureVirtualized) {
         this.ensureVirtualized = ensureVirtualized;
     }
 
-    @Override
     public boolean getEnsureVirtualized() {
         return ensureVirtualized;
     }
@@ -206,7 +183,7 @@
         }
         if (entries != null) {
             for (int i = 0; i < entries.length; i++) {
-                str.append(virtual.entryName(i)).append('=').append(entries[i]).append(' ');
+                str.append("entry").append(i).append('=').append(entries[i]).append(' ');
             }
         }
         if (materializedValue != null) {
@@ -223,8 +200,6 @@
         result = prime * result + Arrays.hashCode(entries);
         result = prime * result + (locks != null ? locks.monitorId.getLockDepth() : 0);
         result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode());
-        result = prime * result + ((state == null) ? 0 : state.hashCode());
-        result = prime * result + ((virtual == null) ? 0 : virtual.hashCode());
         return result;
     }
 
@@ -250,13 +225,11 @@
         } else if (!materializedValue.equals(other.materializedValue)) {
             return false;
         }
-        if (state != other.state) {
-            return false;
-        }
-        assert virtual != null && other.virtual != null;
-        if (!virtual.equals(other.virtual)) {
-            return false;
-        }
         return true;
     }
+
+    public ObjectState share() {
+        copyOnWrite = true;
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Wed Jul 29 11:59:18 2015 +0200
@@ -24,16 +24,22 @@
 
 import java.util.*;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
 
 public abstract class PartialEscapeBlockState<T extends PartialEscapeBlockState<T>> extends EffectsBlockState<T> {
 
-    protected final Map<VirtualObjectNode, ObjectState> objectStates = Node.newIdentityMap();
+    private static final ObjectState[] EMPTY_ARRAY = new ObjectState[0];
+
+    private ObjectState[] objectStates;
+
+    private static class RefCount {
+        private int refCount = 1;
+    }
+
+    private RefCount arrayRefCount;
 
     /**
      * Final subclass of PartialEscapeBlockState, for performance and to make everything behave
@@ -50,32 +56,91 @@
     }
 
     protected PartialEscapeBlockState() {
+        objectStates = EMPTY_ARRAY;
+        arrayRefCount = new RefCount();
     }
 
     protected PartialEscapeBlockState(PartialEscapeBlockState<T> other) {
         super(other);
-        for (Map.Entry<VirtualObjectNode, ObjectState> entry : other.objectStates.entrySet()) {
-            objectStates.put(entry.getKey(), entry.getValue().cloneState());
-        }
+        adoptAddObjectStates(other);
+    }
+
+    public ObjectState getObjectState(int object) {
+        ObjectState state = objectStates[object];
+        assert state != null;
+        return state;
+    }
+
+    public ObjectState getObjectStateOptional(int object) {
+        return object >= objectStates.length ? null : objectStates[object];
     }
 
     public ObjectState getObjectState(VirtualObjectNode object) {
-        assert objectStates.containsKey(object);
-        return objectStates.get(object);
+        ObjectState state = objectStates[object.getObjectId()];
+        assert state != null;
+        return state;
     }
 
     public ObjectState getObjectStateOptional(VirtualObjectNode object) {
-        return objectStates.get(object);
+        int id = object.getObjectId();
+        return id >= objectStates.length ? null : objectStates[id];
+    }
+
+    private ObjectState[] getObjectStateArrayForModification() {
+        if (arrayRefCount.refCount > 1) {
+            objectStates = objectStates.clone();
+            arrayRefCount = new RefCount();
+        }
+        return objectStates;
+    }
+
+    private ObjectState getObjectStateForModification(int object) {
+        ObjectState[] array = getObjectStateArrayForModification();
+        ObjectState objectState = array[object];
+        if (objectState.copyOnWrite) {
+            array[object] = objectState = objectState.cloneState();
+        }
+        return objectState;
     }
 
-    public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, GraphEffectList materializeEffects) {
+    public void setEntry(int object, int entryIndex, ValueNode value) {
+        if (objectStates[object].getEntry(entryIndex) != value) {
+            getObjectStateForModification(object).setEntry(entryIndex, value);
+        }
+    }
+
+    public void escape(int object, ValueNode materialized) {
+        getObjectStateForModification(object).escape(materialized);
+    }
+
+    public void addLock(int object, MonitorIdNode monitorId) {
+        getObjectStateForModification(object).addLock(monitorId);
+    }
+
+    public MonitorIdNode removeLock(int object) {
+        return getObjectStateForModification(object).removeLock();
+    }
+
+    public void setEnsureVirtualized(int object, boolean ensureVirtualized) {
+        if (objectStates[object].getEnsureVirtualized() != ensureVirtualized) {
+            getObjectStateForModification(object).setEnsureVirtualized(ensureVirtualized);
+        }
+    }
+
+    public void updateMaterializedValue(int object, ValueNode value) {
+        if (objectStates[object].getMaterializedValue() != value) {
+            getObjectStateForModification(object).updateMaterializedValue(value);
+        }
+    }
+
+    public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, GraphEffectList materializeEffects) {
         PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment();
         List<AllocatedObjectNode> objects = new ArrayList<>(2);
         List<ValueNode> values = new ArrayList<>(8);
         List<List<MonitorIdNode>> locks = new ArrayList<>(2);
         List<ValueNode> otherAllocations = new ArrayList<>(2);
         List<Boolean> ensureVirtual = new ArrayList<>(2);
-        materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations, state);
+        materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations);
 
         materializeEffects.add("materializeBefore", (graph, obsoleteNodes) -> {
             for (ValueNode otherAllocation : otherAllocations) {
@@ -117,13 +182,14 @@
     }
 
     private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<List<MonitorIdNode>> locks, List<ValueNode> values,
-                    List<Boolean> ensureVirtual, List<ValueNode> otherAllocations, EscapeState state) {
+                    List<Boolean> ensureVirtual, List<ValueNode> otherAllocations) {
         ObjectState obj = getObjectState(virtual);
 
         ValueNode[] entries = obj.getEntries();
         ValueNode representation = virtual.getMaterializedRepresentation(fixed, entries, obj.getLocks());
-        obj.escape(representation, state);
-        PartialEscapeClosure.updateStatesForMaterialized(this, obj);
+        escape(virtual.getObjectId(), representation);
+        obj = getObjectState(virtual);
+        PartialEscapeClosure.updateStatesForMaterialized(this, virtual, obj.getMaterializedValue());
         if (representation instanceof AllocatedObjectNode) {
             objects.add((AllocatedObjectNode) representation);
             locks.add(LockState.asList(obj.getLocks()));
@@ -134,9 +200,11 @@
             }
             for (int i = 0; i < entries.length; i++) {
                 if (entries[i] instanceof VirtualObjectNode) {
-                    ObjectState entryObj = getObjectState((VirtualObjectNode) entries[i]);
+                    VirtualObjectNode entryVirtual = (VirtualObjectNode) entries[i];
+                    ObjectState entryObj = getObjectState(entryVirtual);
                     if (entryObj.isVirtual()) {
-                        materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, ensureVirtual, otherAllocations, state);
+                        materializeWithCommit(fixed, entryVirtual, objects, locks, values, ensureVirtual, otherAllocations);
+                        entryObj = getObjectState(entryVirtual);
                     }
                     values.set(pos + i, entryObj.getMaterializedValue());
                 } else {
@@ -155,26 +223,46 @@
         VirtualUtil.trace("materialized %s as %s with values %s", virtual, representation, values);
     }
 
-    public void addObject(VirtualObjectNode virtual, ObjectState state) {
-        objectStates.put(virtual, state);
+    public void addObject(int virtual, ObjectState state) {
+        ensureSize(virtual)[virtual] = state;
     }
 
-    public Iterable<ObjectState> getStates() {
-        return objectStates.values();
+    private ObjectState[] ensureSize(int objectId) {
+        if (objectStates.length <= objectId) {
+            objectStates = Arrays.copyOf(objectStates, Math.max(objectId * 2, 4));
+            arrayRefCount.refCount--;
+            arrayRefCount = new RefCount();
+            return objectStates;
+        } else {
+            return getObjectStateArrayForModification();
+        }
     }
 
-    public Set<VirtualObjectNode> getVirtualObjects() {
-        return objectStates.keySet();
+    public int getStateCount() {
+        return objectStates.length;
     }
 
     @Override
     public String toString() {
-        return super.toString() + ", Object States: " + objectStates;
+        return super.toString() + ", Object States: " + Arrays.toString(objectStates);
     }
 
     @Override
     public boolean equivalentTo(T other) {
-        return compareMaps(objectStates, other.objectStates);
+        int length = Math.max(objectStates.length, other.getStateCount());
+        for (int i = 0; i < length; i++) {
+            ObjectState left = getObjectStateOptional(i);
+            ObjectState right = other.getObjectStateOptional(i);
+            if (left != right) {
+                if (left == null || right == null) {
+                    return false;
+                }
+                if (!left.equals(right)) {
+                    return false;
+                }
+            }
+        }
+        return true;
     }
 
     protected static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) {
@@ -212,4 +300,42 @@
         }
     }
 
+    public void resetObjectStates(int size) {
+        objectStates = new ObjectState[size];
+    }
+
+    public static boolean identicalObjectStates(PartialEscapeBlockState<?>[] states) {
+        for (int i = 1; i < states.length; i++) {
+            if (states[0].objectStates != states[i].objectStates) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean identicalObjectStates(PartialEscapeBlockState<?>[] states, int object) {
+        for (int i = 1; i < states.length; i++) {
+            if (states[0].objectStates[object] != states[i].objectStates[object]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public void adoptAddObjectStates(PartialEscapeBlockState<?> other) {
+        if (objectStates != null) {
+            arrayRefCount.refCount--;
+        }
+        objectStates = other.objectStates;
+        arrayRefCount = other.arrayRefCount;
+
+        if (arrayRefCount.refCount == 1) {
+            for (ObjectState state : objectStates) {
+                if (state != null) {
+                    state.share();
+                }
+            }
+        }
+        arrayRefCount.refCount++;
+    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Jul 29 11:59:18 2015 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.virtual.phases.ea;
 
 import java.util.*;
+import java.util.function.*;
 
 import com.oracle.graal.debug.*;
 import jdk.internal.jvmci.meta.*;
@@ -37,7 +38,6 @@
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.schedule.*;
 
@@ -56,12 +56,14 @@
     private final NodeBitMap hasVirtualInputs;
     private final VirtualizerToolImpl tool;
 
+    public final ArrayList<VirtualObjectNode> virtualObjects = new ArrayList<>();
+
     private final class CollectVirtualObjectsClosure extends NodeClosure<ValueNode> {
-        private final Set<ObjectState> virtual;
+        private final Set<VirtualObjectNode> virtual;
         private final GraphEffectList effects;
         private final BlockT state;
 
-        private CollectVirtualObjectsClosure(Set<ObjectState> virtual, GraphEffectList effects, BlockT state) {
+        private CollectVirtualObjectsClosure(Set<VirtualObjectNode> virtual, GraphEffectList effects, BlockT state) {
             this.virtual = virtual;
             this.effects = effects;
             this.state = state;
@@ -69,20 +71,17 @@
 
         @Override
         public void apply(Node usage, ValueNode value) {
-            ObjectState valueObj = getObjectState(state, value);
-            if (valueObj != null) {
-                virtual.add(valueObj);
-                effects.replaceFirstInput(usage, value, valueObj.virtual);
-            } else if (value instanceof VirtualObjectNode) {
-                ObjectState virtualObj = null;
-                for (ObjectState obj : state.getStates()) {
-                    if (value == obj.virtual) {
-                        virtualObj = obj;
-                        break;
-                    }
+            if (value instanceof VirtualObjectNode) {
+                VirtualObjectNode object = (VirtualObjectNode) value;
+                if (object.getObjectId() != -1 && state.getObjectStateOptional(object) != null) {
+                    virtual.add(object);
                 }
-                if (virtualObj != null) {
-                    virtual.add(virtualObj);
+            } else {
+                ValueNode alias = getAlias(value);
+                if (alias instanceof VirtualObjectNode) {
+                    VirtualObjectNode object = (VirtualObjectNode) alias;
+                    virtual.add(object);
+                    effects.replaceFirstInput(usage, value, object);
                 }
             }
         }
@@ -196,17 +195,11 @@
         }
         if (canonicalizedValue != node && canonicalizedValue != null) {
             if (canonicalizedValue.isAlive()) {
-                ObjectState obj = getObjectState(state, canonicalizedValue);
-                if (obj != null) {
-                    if (obj.getState() == EscapeState.Virtual) {
-                        addAndMarkAlias(obj.virtual, node);
-                        effects.deleteNode(node);
-                    } else {
-                        effects.replaceAtUsages(node, obj.getMaterializedValue());
-                        addScalarAlias(node, obj.getMaterializedValue());
-                    }
+                ValueNode alias = getAliasAndResolve(state, canonicalizedValue);
+                if (alias instanceof VirtualObjectNode) {
+                    addAndMarkAlias((VirtualObjectNode) alias, node);
+                    effects.deleteNode(node);
                 } else {
-                    ValueNode alias = getScalarAlias(canonicalizedValue);
                     effects.replaceAtUsages(node, alias);
                     addScalarAlias(node, alias);
                 }
@@ -240,7 +233,7 @@
                 if (input.isAlive()) {
                     ObjectState obj = getObjectState(state, (ValueNode) input);
                     if (obj != null) {
-                        if (obj.getState() == EscapeState.Virtual) {
+                        if (obj.isVirtual()) {
                             return false;
                         } else {
                             pos.initialize(node, obj.getMaterializedValue());
@@ -262,10 +255,12 @@
         VirtualUtil.trace("processing nodewithstate: %s", node);
         for (Node input : node.inputs()) {
             if (input instanceof ValueNode) {
-                ObjectState obj = getObjectState(state, (ValueNode) input);
-                if (obj != null) {
-                    VirtualUtil.trace("replacing input %s at %s: %s", input, node, obj);
-                    replaceWithMaterialized(input, node, insertBefore, state, obj, effects, METRIC_MATERIALIZATIONS_UNHANDLED);
+                ValueNode alias = getAlias((ValueNode) input);
+                if (alias instanceof VirtualObjectNode) {
+                    int id = ((VirtualObjectNode) alias).getObjectId();
+                    ensureMaterialized(state, id, insertBefore, effects, METRIC_MATERIALIZATIONS_UNHANDLED);
+                    effects.replaceFirstInput(node, input, state.getObjectState(id).getMaterializedValue());
+                    VirtualUtil.trace("replacing input %s at %s", input, node);
                 }
             }
         }
@@ -287,11 +282,11 @@
     private void processNodeWithState(NodeWithState nodeWithState, BlockT state, GraphEffectList effects) {
         for (FrameState fs : nodeWithState.states()) {
             FrameState frameState = getUniqueFramestate(nodeWithState, fs);
-            Set<ObjectState> virtual = new ArraySet<>();
+            Set<VirtualObjectNode> virtual = new ArraySet<>();
             frameState.applyToNonVirtual(new CollectVirtualObjectsClosure(virtual, effects, state));
             collectLockedVirtualObjects(state, virtual);
             collectReferencedVirtualObjects(state, virtual);
-            addVirtualMappings(effects, frameState, virtual);
+            addVirtualMappings(frameState, virtual, state, effects);
         }
     }
 
@@ -305,23 +300,27 @@
         return frameState;
     }
 
-    private static void addVirtualMappings(GraphEffectList effects, FrameState frameState, Set<ObjectState> virtual) {
-        for (ObjectState obj : virtual) {
-            effects.addVirtualMapping(frameState, obj.createEscapeObjectState());
+    private void addVirtualMappings(FrameState frameState, Set<VirtualObjectNode> virtual, BlockT state, GraphEffectList effects) {
+        for (VirtualObjectNode obj : virtual) {
+            effects.addVirtualMapping(frameState, state.getObjectState(obj).createEscapeObjectState(obj));
         }
     }
 
-    private void collectReferencedVirtualObjects(final BlockT state, final Set<ObjectState> virtual) {
-        ArrayDeque<ObjectState> queue = new ArrayDeque<>(virtual);
+    private void collectReferencedVirtualObjects(BlockT state, Set<VirtualObjectNode> virtual) {
+        ArrayDeque<VirtualObjectNode> queue = new ArrayDeque<>(virtual);
         while (!queue.isEmpty()) {
-            ObjectState obj = queue.removeLast();
-            if (obj.isVirtual()) {
-                for (ValueNode entry : obj.getEntries()) {
-                    if (entry instanceof VirtualObjectNode) {
-                        ObjectState fieldObj = state.getObjectState((VirtualObjectNode) entry);
-                        if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) {
-                            virtual.add(fieldObj);
-                            queue.addLast(fieldObj);
+            VirtualObjectNode object = queue.removeLast();
+            int id = object.getObjectId();
+            if (id != -1) {
+                ObjectState objState = state.getObjectStateOptional(id);
+                if (objState != null && objState.isVirtual()) {
+                    for (ValueNode entry : objState.getEntries()) {
+                        if (entry instanceof VirtualObjectNode) {
+                            VirtualObjectNode entryVirtual = (VirtualObjectNode) entry;
+                            if (!virtual.contains(entryVirtual)) {
+                                virtual.add(entryVirtual);
+                                queue.addLast(entryVirtual);
+                            }
                         }
                     }
                 }
@@ -329,10 +328,11 @@
         }
     }
 
-    private void collectLockedVirtualObjects(final BlockT state, Set<ObjectState> virtual) {
-        for (ObjectState obj : state.getStates()) {
-            if (obj.isVirtual() && obj.hasLocks()) {
-                virtual.add(obj);
+    private void collectLockedVirtualObjects(BlockT state, Set<VirtualObjectNode> virtual) {
+        for (int i = 0; i < state.getStateCount(); i++) {
+            ObjectState objState = state.getObjectStateOptional(i);
+            if (objState != null && objState.isVirtual() && objState.hasLocks()) {
+                virtual.add(virtualObjects.get(i));
             }
         }
     }
@@ -340,49 +340,41 @@
     /**
      * @return true if materialization happened, false if not.
      */
-    private boolean ensureMaterialized(BlockT state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) {
-        assert obj != null;
-        if (obj.getState() == EscapeState.Virtual) {
+    private boolean ensureMaterialized(PartialEscapeBlockState<?> state, int object, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) {
+        if (state.getObjectState(object).isVirtual()) {
             metric.increment();
-            state.materializeBefore(materializeBefore, obj.virtual, EscapeState.Materialized, effects);
-            updateStatesForMaterialized(state, obj);
-            assert !obj.isVirtual();
+            VirtualObjectNode virtual = virtualObjects.get(object);
+            state.materializeBefore(materializeBefore, virtual, effects);
+            updateStatesForMaterialized(state, virtual, state.getObjectState(object).getMaterializedValue());
             return true;
         } else {
-            assert obj.getState() == EscapeState.Materialized;
             return false;
         }
     }
 
-    public static void updateStatesForMaterialized(PartialEscapeBlockState<?> state, ObjectState obj) {
+    public static void updateStatesForMaterialized(PartialEscapeBlockState<?> state, VirtualObjectNode virtual, ValueNode materializedValue) {
         // update all existing states with the newly materialized object
-        for (ObjectState objState : state.objectStates.values()) {
-            if (objState.isVirtual()) {
+        for (int i = 0; i < state.getStateCount(); i++) {
+            ObjectState objState = state.getObjectStateOptional(i);
+            if (objState != null && objState.isVirtual()) {
                 ValueNode[] entries = objState.getEntries();
-                for (int i = 0; i < entries.length; i++) {
-                    if (entries[i] == obj.virtual) {
-                        objState.setEntry(i, obj.getMaterializedValue());
+                for (int i2 = 0; i2 < entries.length; i2++) {
+                    if (entries[i2] == virtual) {
+                        state.setEntry(i, i2, materializedValue);
                     }
                 }
             }
         }
     }
 
-    private boolean replaceWithMaterialized(Node value, Node usage, FixedNode materializeBefore, BlockT state, ObjectState obj, GraphEffectList effects, DebugMetric metric) {
-        boolean materialized = ensureMaterialized(state, obj, materializeBefore, effects, metric);
-        effects.replaceFirstInput(usage, value, obj.getMaterializedValue());
-        return materialized;
-    }
-
     @Override
     protected void processInitialLoopState(Loop<Block> loop, BlockT initialState) {
-        super.processInitialLoopState(loop, initialState);
-
         for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) {
             if (phi.valueAt(0) != null) {
-                ObjectState state = getObjectState(initialState, phi.valueAt(0));
-                if (state != null && state.isVirtual()) {
-                    addAndMarkAlias(state.virtual, phi);
+                ValueNode alias = getAliasAndResolve(initialState, phi.valueAt(0));
+                if (alias instanceof VirtualObjectNode) {
+                    VirtualObjectNode virtual = (VirtualObjectNode) alias;
+                    addAndMarkAlias(virtual, phi);
                 }
             }
         }
@@ -391,49 +383,55 @@
     @Override
     protected void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects) {
         if (exitNode.graph().hasValueProxies()) {
-            Map<VirtualObjectNode, ProxyNode> proxies = Node.newMap();
+            Map<Integer, ProxyNode> proxies = new IdentityHashMap<>();
             for (ProxyNode proxy : exitNode.proxies()) {
-                ObjectState obj = getObjectState(exitState, proxy.value());
-                if (obj != null) {
-                    proxies.put(obj.virtual, proxy);
+                ValueNode alias = getAlias(proxy.value());
+                if (alias instanceof VirtualObjectNode) {
+                    VirtualObjectNode virtual = (VirtualObjectNode) alias;
+                    proxies.put(virtual.getObjectId(), proxy);
                 }
             }
-            for (ObjectState obj : exitState.getStates()) {
-                ObjectState initialObj = initialState.getObjectStateOptional(obj.virtual);
-                if (obj.isVirtual()) {
-                    processVirtualAtLoopExit(exitNode, effects, obj, initialObj);
-                } else {
-                    processMaterializedAtLoopExit(exitNode, effects, proxies, obj, initialObj);
+            for (int i = 0; i < exitState.getStateCount(); i++) {
+                ObjectState exitObjState = exitState.getObjectStateOptional(i);
+                if (exitObjState != null) {
+                    ObjectState initialObjState = initialState.getObjectStateOptional(i);
+
+                    if (exitObjState.isVirtual()) {
+                        processVirtualAtLoopExit(exitNode, effects, i, exitObjState, initialObjState, exitState);
+                    } else {
+                        processMaterializedAtLoopExit(exitNode, effects, proxies, i, exitObjState, initialObjState, exitState);
+                    }
                 }
             }
         }
     }
 
-    private static void processMaterializedAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, Map<VirtualObjectNode, ProxyNode> proxies, ObjectState obj, ObjectState initialObj) {
-        if (initialObj == null || initialObj.isVirtual()) {
-            ProxyNode proxy = proxies.get(obj.virtual);
+    private static void processMaterializedAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, Map<Integer, ProxyNode> proxies, int object, ObjectState exitObjState,
+                    ObjectState initialObjState, PartialEscapeBlockState<?> exitState) {
+        if (initialObjState == null || initialObjState.isVirtual()) {
+            ProxyNode proxy = proxies.get(object);
             if (proxy == null) {
-                proxy = new ValueProxyNode(obj.getMaterializedValue(), exitNode);
+                proxy = new ValueProxyNode(exitObjState.getMaterializedValue(), exitNode);
                 effects.addFloatingNode(proxy, "proxy");
             } else {
-                effects.replaceFirstInput(proxy, proxy.value(), obj.getMaterializedValue());
+                effects.replaceFirstInput(proxy, proxy.value(), exitObjState.getMaterializedValue());
                 // nothing to do - will be handled in processNode
             }
-            obj.updateMaterializedValue(proxy);
+            exitState.updateMaterializedValue(object, proxy);
         } else {
-            if (initialObj.getMaterializedValue() == obj.getMaterializedValue()) {
-                Debug.log("materialized value changes within loop: %s vs. %s at %s", initialObj.getMaterializedValue(), obj.getMaterializedValue(), exitNode);
+            if (initialObjState.getMaterializedValue() != exitObjState.getMaterializedValue()) {
+                Debug.log("materialized value changes within loop: %s vs. %s at %s", initialObjState.getMaterializedValue(), exitObjState.getMaterializedValue(), exitNode);
             }
         }
     }
 
-    private static void processVirtualAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, ObjectState obj, ObjectState initialObj) {
-        for (int i = 0; i < obj.getEntries().length; i++) {
-            ValueNode value = obj.getEntry(i);
+    private static void processVirtualAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, int object, ObjectState exitObjState, ObjectState initialObjState, PartialEscapeBlockState<?> exitState) {
+        for (int i = 0; i < exitObjState.getEntries().length; i++) {
+            ValueNode value = exitState.getObjectState(object).getEntry(i);
             if (!(value instanceof VirtualObjectNode || value.isConstant())) {
-                if (exitNode.loopBegin().isPhiAtMerge(value) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) {
+                if (exitNode.loopBegin().isPhiAtMerge(value) || initialObjState == null || !initialObjState.isVirtual() || initialObjState.getEntry(i) != value) {
                     ProxyNode proxy = new ValueProxyNode(value, exitNode);
-                    obj.setEntry(i, proxy);
+                    exitState.setEntry(object, i, proxy);
                     effects.addFloatingNode(proxy, "virtualProxy");
                 }
             }
@@ -525,56 +523,72 @@
          * reached. This method needs to be careful to place the effects of the merging operation
          * into the correct blocks.
          *
-         * @param states the predecessor block states of the merge
+         * @param statesList the predecessor block states of the merge
          */
         @Override
-        protected void merge(List<BlockT> states) {
-            super.merge(states);
+        protected void merge(List<BlockT> statesList) {
+            super.merge(statesList);
+
+            PartialEscapeBlockState<?>[] states = new PartialEscapeBlockState<?>[statesList.size()];
+            for (int i = 0; i < statesList.size(); i++) {
+                states[i] = statesList.get(i);
+            }
 
             // calculate the set of virtual objects that exist in all predecessors
-            Set<VirtualObjectNode> virtualObjTemp = intersectVirtualObjects(states);
+            int[] virtualObjTemp = intersectVirtualObjects(states);
 
-            ObjectState[] objStates = new ObjectState[states.size()];
             boolean materialized;
             do {
                 materialized = false;
-                for (VirtualObjectNode object : virtualObjTemp) {
-                    for (int i = 0; i < objStates.length; i++) {
-                        objStates[i] = states.get(i).getObjectState(object);
-                    }
+
+                if (PartialEscapeBlockState.identicalObjectStates(states)) {
+                    newState.adoptAddObjectStates(states[0]);
+                } else {
 
-                    // determine if all inputs are virtual or the same materialized value
-                    int virtual = 0;
-                    ObjectState startObj = objStates[0];
-                    boolean locksMatch = true;
-                    ValueNode uniqueMaterializedValue = startObj.isVirtual() ? null : startObj.getMaterializedValue();
-                    for (ObjectState obj : objStates) {
-                        if (obj.isVirtual()) {
-                            virtual++;
-                            uniqueMaterializedValue = null;
-                            locksMatch &= obj.locksEqual(startObj);
-                        } else if (obj.getMaterializedValue() != uniqueMaterializedValue) {
-                            uniqueMaterializedValue = null;
+                    for (int object : virtualObjTemp) {
+
+                        if (PartialEscapeBlockState.identicalObjectStates(states, object)) {
+                            newState.addObject(object, states[0].getObjectState(object).share());
+                            continue;
                         }
-                    }
 
-                    if (virtual == objStates.length && locksMatch) {
-                        materialized |= mergeObjectStates(object, objStates, states);
-                    } else {
-                        if (uniqueMaterializedValue != null) {
-                            newState.addObject(object, new ObjectState(object, uniqueMaterializedValue, EscapeState.Materialized, null, false));
+                        // determine if all inputs are virtual or the same materialized value
+                        int virtualCount = 0;
+                        ObjectState startObj = states[0].getObjectState(object);
+                        boolean locksMatch = true;
+                        boolean ensureVirtual = true;
+                        ValueNode uniqueMaterializedValue = startObj.isVirtual() ? null : startObj.getMaterializedValue();
+                        for (int i = 0; i < states.length; i++) {
+                            ObjectState obj = states[i].getObjectState(object);
+                            ensureVirtual &= obj.getEnsureVirtualized();
+                            if (obj.isVirtual()) {
+                                virtualCount++;
+                                uniqueMaterializedValue = null;
+                                locksMatch &= obj.locksEqual(startObj);
+                            } else if (obj.getMaterializedValue() != uniqueMaterializedValue) {
+                                uniqueMaterializedValue = null;
+                            }
+                        }
+
+                        if (virtualCount == states.length && locksMatch) {
+                            materialized |= mergeObjectStates(object, null, states);
                         } else {
-                            PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(Kind.Object));
-                            mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi");
-                            for (int i = 0; i < objStates.length; i++) {
-                                ObjectState obj = objStates[i];
-                                if (obj.isVirtual()) {
-                                    Block predecessor = getPredecessor(i);
-                                    materialized |= ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
+                            if (uniqueMaterializedValue != null) {
+                                newState.addObject(object, new ObjectState(uniqueMaterializedValue, null, ensureVirtual));
+                            } else {
+                                PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(Kind.Object));
+                                mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi");
+                                for (int i = 0; i < states.length; i++) {
+                                    ObjectState obj = states[i].getObjectState(object);
+                                    if (obj.isVirtual()) {
+                                        Block predecessor = getPredecessor(i);
+                                        materialized |= ensureMaterialized(states[i], object, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
+                                        obj = states[i].getObjectState(object);
+                                    }
+                                    setPhiInput(materializedValuePhi, i, obj.getMaterializedValue());
                                 }
-                                setPhiInput(materializedValuePhi, i, obj.getMaterializedValue());
+                                newState.addObject(object, new ObjectState(materializedValuePhi, null, false));
                             }
-                            newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null, false));
                         }
                     }
                 }
@@ -585,19 +599,41 @@
                     }
                 }
                 if (materialized) {
-                    newState.objectStates.clear();
+                    newState.resetObjectStates(virtualObjects.size());
                     mergeEffects.clear();
                     afterMergeEffects.clear();
                 }
             } while (materialized);
         }
 
-        private Set<VirtualObjectNode> intersectVirtualObjects(List<BlockT> states) {
-            Set<VirtualObjectNode> virtualObjTemp = Node.newSet(states.get(0).getVirtualObjects());
-            for (int i = 1; i < states.size(); i++) {
-                virtualObjTemp.retainAll(states.get(i).getVirtualObjects());
+        private int[] intersectVirtualObjects(PartialEscapeBlockState<?>[] states) {
+            int length = states[0].getStateCount();
+            for (int i = 1; i < states.length; i++) {
+                length = Math.min(length, states[i].getStateCount());
             }
-            return virtualObjTemp;
+            boolean[] result = new boolean[length];
+            Arrays.fill(result, true);
+            int count = length;
+            for (int i = 0; i < states.length; i++) {
+                PartialEscapeBlockState<?> state = states[i];
+                for (int i2 = 0; i2 < length; i2++) {
+                    if (result[i2]) {
+                        if (state.getObjectStateOptional(i2) == null) {
+                            result[i2] = false;
+                            count--;
+                        }
+                    }
+                }
+            }
+            int[] resultInts = new int[count];
+            int index = 0;
+            for (int i = 0; i < length; i++) {
+                if (result[i]) {
+                    resultInts[index++] = i;
+                }
+            }
+            assert index == count;
+            return resultInts;
         }
 
         /**
@@ -608,28 +644,30 @@
          * can be incompatible if they contain {@code long} or {@code double} values occupying two
          * {@code int} slots in such a way that that their values cannot be merged using PhiNodes.
          *
-         * @param object the virtual object that should be associated with the merged object state
-         * @param objStates the incoming object states (all of which need to be virtual)
-         * @param blockStates the predecessor block states of the merge
+         * @param states the predecessor block states of the merge
          * @return true if materialization happened during the merge, false otherwise
          */
-        private boolean mergeObjectStates(VirtualObjectNode object, ObjectState[] objStates, List<BlockT> blockStates) {
+        private boolean mergeObjectStates(int resultObject, int[] sourceObjects, PartialEscapeBlockState<?>[] states) {
             boolean compatible = true;
             boolean ensureVirtual = true;
-            ValueNode[] values = objStates[0].getEntries().clone();
+            IntFunction<Integer> getObject = index -> sourceObjects == null ? resultObject : sourceObjects[index];
+
+            VirtualObjectNode virtual = virtualObjects.get(resultObject);
+            int entryCount = virtual.entryCount();
 
             // determine all entries that have a two-slot value
             Kind[] twoSlotKinds = null;
-            outer: for (int i = 0; i < objStates.length; i++) {
-                ValueNode[] entries = objStates[i].getEntries();
+            outer: for (int i = 0; i < states.length; i++) {
+                ObjectState objectState = states[i].getObjectState(getObject.apply(i));
+                ValueNode[] entries = objectState.getEntries();
                 int valueIndex = 0;
-                ensureVirtual &= objStates[i].getEnsureVirtualized();
-                while (valueIndex < values.length) {
+                ensureVirtual &= objectState.getEnsureVirtualized();
+                while (valueIndex < entryCount) {
                     Kind otherKind = entries[valueIndex].getKind();
-                    Kind entryKind = object.entryKind(valueIndex);
+                    Kind entryKind = virtual.entryKind(valueIndex);
                     if (entryKind == Kind.Int && otherKind.needsTwoSlots()) {
                         if (twoSlotKinds == null) {
-                            twoSlotKinds = new Kind[values.length];
+                            twoSlotKinds = new Kind[entryCount];
                         }
                         if (twoSlotKinds[valueIndex] != null && twoSlotKinds[valueIndex] != otherKind) {
                             compatible = false;
@@ -647,18 +685,20 @@
             }
             if (compatible && twoSlotKinds != null) {
                 // if there are two-slot values then make sure the incoming states can be merged
-                outer: for (int valueIndex = 0; valueIndex < values.length; valueIndex++) {
+                outer: for (int valueIndex = 0; valueIndex < entryCount; valueIndex++) {
                     if (twoSlotKinds[valueIndex] != null) {
-                        assert valueIndex < object.entryCount() - 1 && object.entryKind(valueIndex) == Kind.Int && object.entryKind(valueIndex + 1) == Kind.Int;
-                        for (int i = 0; i < objStates.length; i++) {
-                            ValueNode value = objStates[i].getEntry(valueIndex);
+                        assert valueIndex < virtual.entryCount() - 1 && virtual.entryKind(valueIndex) == Kind.Int && virtual.entryKind(valueIndex + 1) == Kind.Int;
+                        for (int i = 0; i < states.length; i++) {
+                            int object = getObject.apply(i);
+                            ObjectState objectState = states[i].getObjectState(object);
+                            ValueNode value = objectState.getEntry(valueIndex);
                             Kind valueKind = value.getKind();
                             if (valueKind != twoSlotKinds[valueIndex]) {
-                                ValueNode nextValue = objStates[i].getEntry(valueIndex + 1);
+                                ValueNode nextValue = objectState.getEntry(valueIndex + 1);
                                 if (value.isConstant() && value.asConstant().equals(JavaConstant.INT_0) && nextValue.isConstant() && nextValue.asConstant().equals(JavaConstant.INT_0)) {
                                     // rewrite to a zero constant of the larger kind
-                                    objStates[i].setEntry(valueIndex, ConstantNode.defaultForKind(twoSlotKinds[valueIndex], graph()));
-                                    objStates[i].setEntry(valueIndex + 1, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()));
+                                    states[i].setEntry(object, valueIndex, ConstantNode.defaultForKind(twoSlotKinds[valueIndex], graph()));
+                                    states[i].setEntry(object, valueIndex + 1, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()));
                                 } else {
                                     compatible = false;
                                     break outer;
@@ -671,12 +711,13 @@
 
             if (compatible) {
                 // virtual objects are compatible: create phis for all entries that need them
-                PhiNode[] phis = getValuePhis(object, object.entryCount());
+                ValueNode[] values = states[0].getObjectState(getObject.apply(0)).getEntries().clone();
+                PhiNode[] phis = getValuePhis(virtual, virtual.entryCount());
                 int valueIndex = 0;
                 while (valueIndex < values.length) {
-                    for (int i = 1; i < objStates.length; i++) {
+                    for (int i = 1; i < states.length; i++) {
                         if (phis[valueIndex] == null) {
-                            ValueNode field = objStates[i].getEntry(valueIndex);
+                            ValueNode field = states[i].getObjectState(getObject.apply(i)).getEntry(valueIndex);
                             if (values[valueIndex] != field) {
                                 phis[valueIndex] = createValuePhi(values[valueIndex].stamp().unrestricted());
                             }
@@ -699,26 +740,31 @@
                     PhiNode phi = phis[i];
                     if (phi != null) {
                         mergeEffects.addFloatingNode(phi, "virtualMergePhi");
-                        if (object.entryKind(i) == Kind.Object) {
-                            materialized |= mergeObjectEntry(objStates, blockStates, phi, i);
+                        if (virtual.entryKind(i) == Kind.Object) {
+                            materialized |= mergeObjectEntry(getObject, states, phi, i);
                         } else {
-                            mergePrimitiveEntry(objStates, phi, i);
+                            for (int i2 = 0; i2 < states.length; i2++) {
+                                ObjectState state = states[i2].getObjectState(getObject.apply(i2));
+                                if (!state.isVirtual()) {
+                                    break;
+                                }
+                                setPhiInput(phi, i2, state.getEntry(i));
+                            }
                         }
                         values[i] = phi;
                     }
                 }
-                newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, objStates[0].getLocks(), ensureVirtual));
+                newState.addObject(resultObject, new ObjectState(values, states[0].getObjectState(getObject.apply(0)).getLocks(), ensureVirtual));
                 return materialized;
             } else {
                 // not compatible: materialize in all predecessors
-                PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(Kind.Object));
-                for (int i = 0; i < blockStates.size(); i++) {
-                    ObjectState obj = objStates[i];
+                PhiNode materializedValuePhi = getPhi(resultObject, StampFactory.forKind(Kind.Object));
+                for (int i = 0; i < states.length; i++) {
                     Block predecessor = getPredecessor(i);
-                    ensureMaterialized(blockStates.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
-                    setPhiInput(materializedValuePhi, i, obj.getMaterializedValue());
+                    ensureMaterialized(states[i], getObject.apply(i), predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
+                    setPhiInput(materializedValuePhi, i, states[i].getObjectState(getObject.apply(i)).getMaterializedValue());
                 }
-                newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null, false));
+                newState.addObject(resultObject, new ObjectState(materializedValuePhi, null, ensureVirtual));
                 return true;
             }
         }
@@ -729,19 +775,22 @@
          *
          * @return true if materialization happened during the merge, false otherwise
          */
-        private boolean mergeObjectEntry(ObjectState[] objStates, List<BlockT> blockStates, PhiNode phi, int entryIndex) {
+        private boolean mergeObjectEntry(IntFunction<Integer> objectIdFunc, PartialEscapeBlockState<?>[] states, PhiNode phi, int entryIndex) {
             boolean materialized = false;
-            for (int i = 0; i < objStates.length; i++) {
-                if (!objStates[i].isVirtual()) {
+            for (int i = 0; i < states.length; i++) {
+                int object = objectIdFunc.apply(i);
+                ObjectState objectState = states[i].getObjectState(object);
+                if (!objectState.isVirtual()) {
                     break;
                 }
-                ValueNode entry = objStates[i].getEntry(entryIndex);
+                ValueNode entry = objectState.getEntry(entryIndex);
                 if (entry instanceof VirtualObjectNode) {
-                    ObjectState obj = blockStates.get(i).getObjectState((VirtualObjectNode) entry);
+                    VirtualObjectNode entryVirtual = (VirtualObjectNode) entry;
                     Block predecessor = getPredecessor(i);
-                    materialized |= ensureMaterialized(blockStates.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
-                    if (objStates[i].isVirtual()) {
-                        objStates[i].setEntry(entryIndex, entry = obj.getMaterializedValue());
+                    materialized |= ensureMaterialized(states[i], entryVirtual.getObjectId(), predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
+                    objectState = states[i].getObjectState(object);
+                    if (objectState.isVirtual()) {
+                        states[i].setEntry(object, entryIndex, entry = states[i].getObjectState(entryVirtual.getObjectId()).getMaterializedValue());
                     }
                 }
                 setPhiInput(phi, i, entry);
@@ -750,20 +799,6 @@
         }
 
         /**
-         * Fill the inputs of the PhiNode corresponding to one primitive entry in the virtual
-         * object.
-         */
-        private void mergePrimitiveEntry(ObjectState[] objStates, PhiNode phi, int entryIndex) {
-            for (int i = 0; i < objStates.length; i++) {
-                ObjectState state = objStates[i];
-                if (!state.isVirtual()) {
-                    break;
-                }
-                setPhiInput(phi, i, state.getEntry(entryIndex));
-            }
-        }
-
-        /**
          * Examine a PhiNode and try to replace it with merging of virtual objects if all its inputs
          * refer to virtual object states. In order for the merging to happen, all incoming object
          * states need to be compatible and without object identity (meaning that their object
@@ -775,40 +810,46 @@
          *            and therefore also exist in the merged state
          * @return true if materialization happened during the merge, false otherwise
          */
-        private boolean processPhi(ValuePhiNode phi, List<BlockT> states, Set<VirtualObjectNode> mergedVirtualObjects) {
+        private boolean processPhi(ValuePhiNode phi, PartialEscapeBlockState<?>[] states, int[] mergedVirtualObjects) {
             aliases.set(phi, null);
 
             // determine how many inputs are virtual and if they're all the same virtual object
             int virtualInputs = 0;
-            ObjectState[] objStates = new ObjectState[states.size()];
             boolean uniqueVirtualObject = true;
-            for (int i = 0; i < objStates.length; i++) {
-                ObjectState obj = objStates[i] = getObjectState(states.get(i), getPhiValueAt(phi, i));
-                if (obj != null) {
-                    if (obj.isVirtual()) {
-                        if (objStates[0] == null || objStates[0].virtual != obj.virtual) {
+            VirtualObjectNode[] virtualObjs = new VirtualObjectNode[states.length];
+            for (int i = 0; i < states.length; i++) {
+                ValueNode alias = getAlias(getPhiValueAt(phi, i));
+                if (alias instanceof VirtualObjectNode) {
+                    VirtualObjectNode virtual = (VirtualObjectNode) alias;
+                    virtualObjs[i] = virtual;
+                    if (states[i].getObjectState(virtual).isVirtual()) {
+                        if (virtualObjs[0] != alias) {
                             uniqueVirtualObject = false;
                         }
                         virtualInputs++;
                     }
                 }
             }
-            if (virtualInputs == objStates.length) {
+            if (virtualInputs == states.length) {
                 if (uniqueVirtualObject) {
                     // all inputs refer to the same object: just make the phi node an alias
-                    addAndMarkAlias(objStates[0].virtual, phi);
+                    addAndMarkAlias(virtualObjs[0], phi);
                     mergeEffects.deleteNode(phi);
                     return false;
                 } else {
                     // all inputs are virtual: check if they're compatible and without identity
                     boolean compatible = true;
                     boolean hasIdentity = false;
-                    ObjectState firstObj = objStates[0];
-                    for (int i = 0; i < objStates.length; i++) {
-                        ObjectState obj = objStates[i];
-                        hasIdentity |= obj.virtual.hasIdentity();
-                        boolean identitySurvives = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual);
-                        if (identitySurvives || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) {
+                    VirtualObjectNode firstVirtual = virtualObjs[0];
+                    for (int i = 0; i < states.length; i++) {
+                        VirtualObjectNode virtual = virtualObjs[i];
+                        hasIdentity |= virtual.hasIdentity();
+                        boolean identitySurvives = virtual.hasIdentity() && Arrays.asList(mergedVirtualObjects).contains(virtual.getObjectId());
+                        if (identitySurvives || !firstVirtual.type().equals(virtual.type()) || firstVirtual.entryCount() != virtual.entryCount()) {
+                            compatible = false;
+                            break;
+                        }
+                        if (!states[0].getObjectState(firstVirtual).locksEqual(states[i].getObjectState(virtual))) {
                             compatible = false;
                             break;
                         }
@@ -816,22 +857,34 @@
                     if (compatible && hasIdentity) {
                         // we still need to check whether this value is referenced by any other phi
                         outer: for (PhiNode otherPhi : getPhis().filter(otherPhi -> otherPhi != phi)) {
-                            for (int i = 0; i < objStates.length; i++) {
-                                ObjectState otherPhiValueState = getObjectState(states.get(i), getPhiValueAt(otherPhi, i));
-                                if (Arrays.asList(objStates).contains(otherPhiValueState)) {
-                                    compatible = false;
-                                    break outer;
+                            for (int i = 0; i < states.length; i++) {
+                                ValueNode alias = getAliasAndResolve(states[i], getPhiValueAt(otherPhi, i));
+                                if (alias instanceof VirtualObjectNode) {
+                                    VirtualObjectNode phiValueVirtual = (VirtualObjectNode) alias;
+                                    if (Arrays.asList(virtualObjs).contains(phiValueVirtual)) {
+                                        compatible = false;
+                                        break outer;
+                                    }
                                 }
                             }
                         }
                     }
 
                     if (compatible) {
-                        VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), getPhiValueAt(phi, 0)).virtual);
+                        VirtualObjectNode virtual = getValueObjectVirtual(phi, virtualObjs[0]);
                         mergeEffects.addFloatingNode(virtual, "valueObjectNode");
                         mergeEffects.deleteNode(phi);
+                        if (virtual.getObjectId() == -1) {
+                            int id = virtualObjects.size();
+                            virtualObjects.add(virtual);
+                            virtual.setObjectId(id);
+                        }
 
-                        boolean materialized = mergeObjectStates(virtual, objStates, states);
+                        int[] virtualObjectIds = new int[states.length];
+                        for (int i = 0; i < states.length; i++) {
+                            virtualObjectIds[i] = virtualObjs[i].getObjectId();
+                        }
+                        boolean materialized = mergeObjectStates(virtual.getObjectId(), virtualObjectIds, states);
                         addAndMarkAlias(virtual, virtual);
                         addAndMarkAlias(virtual, phi);
                         return materialized;
@@ -841,12 +894,12 @@
 
             // otherwise: materialize all phi inputs
             boolean materialized = false;
-            for (int i = 0; i < objStates.length; i++) {
-                ObjectState obj = objStates[i];
-                if (obj != null) {
+            for (int i = 0; i < states.length; i++) {
+                VirtualObjectNode virtual = virtualObjs[i];
+                if (virtual != null) {
                     Block predecessor = getPredecessor(i);
-                    materialized |= ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_PHI);
-                    setPhiInput(phi, i, obj.getMaterializedValue());
+                    materialized |= ensureMaterialized(states[i], virtual.getObjectId(), predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_PHI);
+                    setPhiInput(phi, i, getAliasAndResolve(states[i], virtual));
                 }
             }
             return materialized;
@@ -868,6 +921,29 @@
         }
     }
 
+    public ValueNode getAlias(ValueNode value) {
+        if (value != null && !(value instanceof VirtualObjectNode)) {
+            if (value.isAlive() && !aliases.isNew(value)) {
+                ValueNode result = aliases.get(value);
+                if (result != null) {
+                    return result;
+                }
+            }
+        }
+        return value;
+    }
+
+    public ValueNode getAliasAndResolve(PartialEscapeBlockState<?> state, ValueNode value) {
+        ValueNode result = getAlias(value);
+        if (result instanceof VirtualObjectNode) {
+            int id = ((VirtualObjectNode) result).getObjectId();
+            if (id != -1 && !state.getObjectState(id).isVirtual()) {
+                result = state.getObjectState(id).getMaterializedValue();
+            }
+        }
+        return result;
+    }
+
     void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node) {
         if (node.isAlive()) {
             aliases.set(node, virtual);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Wed Jul 29 11:59:18 2015 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
@@ -83,6 +84,9 @@
 
     @Override
     protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule, ControlFlowGraph cfg) {
+        for (VirtualObjectNode virtual : cfg.graph.getNodes(VirtualObjectNode.TYPE)) {
+            virtual.resetObjectId();
+        }
         assert schedule != null;
         if (readElimination) {
             return new PEReadEliminationClosure(schedule, context.getMetaAccess(), context.getConstantReflection());
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Wed Jul 29 11:59:18 2015 +0200
@@ -27,8 +27,6 @@
 import java.util.*;
 
 import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.debug.*;
-
 import com.oracle.graal.debug.*;
 
 import jdk.internal.jvmci.meta.*;
@@ -109,6 +107,7 @@
         }
         if (!success) {
             TTY.println();
+            Debug.dump(graph, "assertNonReachable");
         }
         return success;
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Tue Jul 28 17:35:49 2015 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Wed Jul 29 11:59:18 2015 +0200
@@ -33,8 +33,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
-import com.oracle.graal.nodes.spi.Virtualizable.State;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
 
@@ -78,33 +76,35 @@
     }
 
     @Override
-    public State getObjectState(ValueNode value) {
-        return closure.getObjectState(state, value);
+    public ValueNode getAlias(ValueNode value) {
+        return closure.getAliasAndResolve(state, value);
+    }
+
+    public ValueNode getEntry(VirtualObjectNode virtualObject, int index) {
+        return state.getObjectState(virtualObject).getEntry(index);
     }
 
     @Override
-    public void setVirtualEntry(State objectState, int index, ValueNode value, boolean unsafe) {
-        ObjectState obj = (ObjectState) objectState;
-        assert obj != null && obj.isVirtual() : "not virtual: " + obj;
+    public void setVirtualEntry(VirtualObjectNode virtual, int index, ValueNode value, boolean unsafe) {
+        ObjectState obj = state.getObjectState(virtual);
+        assert obj.isVirtual() : "not virtual: " + obj;
         ValueNode newValue;
         if (value == null) {
             newValue = null;
         } else {
-            ObjectState valueState = closure.getObjectState(state, value);
-            if (valueState == null) {
-                newValue = getReplacedValue(value);
-                assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).getKind() == newValue.getKind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue));
-            } else {
-                if (valueState.getState() != EscapeState.Virtual) {
-                    newValue = valueState.getMaterializedValue();
-                    assert newValue.getKind() == Kind.Object;
-                } else {
-                    newValue = valueState.getVirtualObject();
-                }
-                assert obj.getEntry(index) == null || isObjectEntry(obj.getEntry(index));
-            }
+            newValue = closure.getAliasAndResolve(state, value);
+            assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).getKind() == newValue.getKind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue));
         }
-        obj.setEntry(index, newValue);
+        state.setEntry(virtual.getObjectId(), index, newValue);
+    }
+
+    public void setEnsureVirtualized(VirtualObjectNode virtualObject, boolean ensureVirtualized) {
+        int id = virtualObject.getObjectId();
+        state.setEnsureVirtualized(id, ensureVirtualized);
+    }
+
+    public boolean getEnsureVirtualized(VirtualObjectNode virtualObject) {
+        return state.getObjectState(virtualObject).getEnsureVirtualized();
     }
 
     private static boolean isObjectEntry(ValueNode value) {
@@ -112,11 +112,6 @@
     }
 
     @Override
-    public ValueNode getReplacedValue(ValueNode original) {
-        return closure.getScalarAlias(original);
-    }
-
-    @Override
     public void replaceWithVirtual(VirtualObjectNode virtual) {
         closure.addAndMarkAlias(virtual, current);
         effects.deleteNode(current);
@@ -157,16 +152,16 @@
             effects.addFloatingNode(virtualObject, "newVirtualObject");
         }
         for (int i = 0; i < entryState.length; i++) {
-            if (!(entryState[i] instanceof VirtualObjectNode)) {
-                ObjectState v = closure.getObjectState(state, entryState[i]);
-                if (v != null) {
-                    entryState[i] = v.isVirtual() ? v.getVirtualObject() : v.getMaterializedValue();
-                } else {
-                    entryState[i] = closure.getScalarAlias(entryState[i]);
-                }
-            }
+            ValueNode entry = entryState[i];
+            entryState[i] = entry instanceof VirtualObjectNode ? entry : closure.getAliasAndResolve(state, entry);
         }
-        state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks, ensureVirtualized));
+        int id = virtualObject.getObjectId();
+        if (id == -1) {
+            id = closure.virtualObjects.size();
+            closure.virtualObjects.add(virtualObject);
+            virtualObject.setObjectId(id);
+        }
+        state.addObject(id, new ObjectState(entryState, locks, ensureVirtualized));
         closure.addAndMarkAlias(virtualObject, virtualObject);
         PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment();
     }
@@ -178,18 +173,23 @@
 
     @Override
     public void replaceWith(ValueNode node) {
-        State resultState = getObjectState(node);
-        if (resultState == null) {
-            replaceWithValue(node);
+        if (node instanceof VirtualObjectNode) {
+            replaceWithVirtual((VirtualObjectNode) node);
         } else {
-            if (resultState.getState() == EscapeState.Virtual) {
-                replaceWithVirtual(resultState.getVirtualObject());
-            } else {
-                replaceWithValue(resultState.getMaterializedValue());
-            }
+            replaceWithValue(node);
         }
     }
 
+    public void addLock(VirtualObjectNode virtualObject, MonitorIdNode monitorId) {
+        int id = virtualObject.getObjectId();
+        state.addLock(id, monitorId);
+    }
+
+    public MonitorIdNode removeLock(VirtualObjectNode virtualObject) {
+        int id = virtualObject.getObjectId();
+        return state.removeLock(id);
+    }
+
     public MetaAccessProvider getMetaAccess() {
         return metaAccess;
     }
--- a/mx.graal/mx_graal.py	Tue Jul 28 17:35:49 2015 -0700
+++ b/mx.graal/mx_graal.py	Wed Jul 29 11:59:18 2015 +0200
@@ -281,6 +281,7 @@
 graal_unit_test_runs = [
     UnitTestRun('UnitTests', []),
     UnitTestRun('UnitTestsNonSSA', ['-G:-SSA_LIR']),
+    UnitTestRun('UnitTestsTraceRA', ['-G:+TraceRA']),
 ]
 
 _registers = 'o0,o1,o2,o3,f8,f9,d32,d34' if platform.processor() == 'sparc' else 'rbx,r11,r10,r14,xmm3,xmm11,xmm14'
@@ -294,6 +295,7 @@
     BootstrapTest('BootstrapWithExceptionEdges', 'fastdebug', ['-esa', '-G:+StressInvokeWithExceptionNode']),
     BootstrapTest('BootstrapWithRegisterPressure', 'product', ['-esa', '-G:RegisterPressure=' + _registers]),
     BootstrapTest('BootstrapNonSSAWithRegisterPressure', 'product', ['-esa', '-G:-SSA_LIR', '-G:RegisterPressure=' + _registers]),
+    BootstrapTest('BootstrapTraceRAWithRegisterPressure', 'product', ['-esa', '-G:+TraceRA', '-G:RegisterPressure=' + _registers]),
     BootstrapTest('BootstrapWithImmutableCode', 'product', ['-esa', '-G:+ImmutableCode', '-G:+VerifyPhases']),
 ]
 
--- a/mx.graal/suite.py	Tue Jul 28 17:35:49 2015 -0700
+++ b/mx.graal/suite.py	Wed Jul 29 11:59:18 2015 +0200
@@ -6,7 +6,7 @@
     "suites": [
             {
                "name" : "jvmci",
-               "version" : "8217ef77a80a64b8b773ba1a91363dbeb3d782e6",
+               "version" : "528eeeca785ef0ed43138966bc0a301707fbf5d7",
                "urls" : [
                     {"url" : "https://lafo.ssw.uni-linz.ac.at/hg/graal-jvmci-8", "kind" : "hg"},
                     {"url" : "http://lafo.ssw.uni-linz.ac.at/nexus/content/repositories/snapshots", "kind" : "binary"},
@@ -283,7 +283,6 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.graal.debug",
         "com.oracle.graal.nodeinfo",
         "com.oracle.graal.compiler.common",
         "com.oracle.graal.api.collections",
@@ -381,7 +380,6 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.graal.compiler.common",
-        "com.oracle.graal.debug",
         "com.oracle.graal.asm",
       ],
       "annotationProcessors" : ["jvmci:JVMCI_OPTIONS_PROCESSOR"],
@@ -738,7 +736,7 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "jvmci:JVMCI_API",
+        "com.oracle.graal.debug",
       ],
       "annotationProcessors" : ["jvmci:JVMCI_OPTIONS_PROCESSOR"],
       "checkstyle" : "com.oracle.graal.graph",