changeset 22275:329f734a9803

Merge with basic-graal
author Doug Simon <doug.simon@oracle.com>
date Tue, 21 Jul 2015 16:17:54 +0200
parents b5ac72b4f62a (current diff) b6d504612b3f (diff)
children 8f16ac5f8271
files .hgignore graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeMappableLIRBuilder.java graal/com.oracle.graal.truffle.test/sl/TestDeoptInInlinedFunction.sl mx.graal/mx_graal.py mx.graal/suite.py
diffstat 180 files changed, 4045 insertions(+), 1361 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Jul 21 15:16:00 2015 +0200
+++ b/.hgignore	Tue Jul 21 16:17:54 2015 +0200
@@ -88,7 +88,7 @@
 jacoco.exec
 workingsets.xml
 .buildbot/
-graal.options
+jvmci.options
 agent/build/*
 agent/make/filelist
 agent/make/sa17.tar.gz
--- a/.hgtags	Tue Jul 21 15:16:00 2015 +0200
+++ b/.hgtags	Tue Jul 21 16:17:54 2015 +0200
@@ -617,3 +617,4 @@
 f4822d12204179e6a3e7aaf98991b6171670cbf2 jdk8u45-b11
 dc29108bcbcbfcd49eaa9135368306dc85db73a6 jdk8u45-b12
 efbf340fc7f56e49735111c23cef030413146409 jdk8u45-b13
+3c622007e098d8905d8e0947362a3894a629a5f1 graal-0.8
--- a/CHANGELOG.md	Tue Jul 21 15:16:00 2015 +0200
+++ b/CHANGELOG.md	Tue Jul 21 16:17:54 2015 +0200
@@ -1,17 +1,22 @@
 # GraalVM Changelog
 
-This changelog summarizes major changes between Graal versions relevant to languages implementors building upon the Truffle framework and developers building technology on top of Graal. The main focus is on APIs exported by Graal and Truffle.
-
+This changelog summarizes major changes between Graal versions relevant to developers building technology on top of Graal. The main focus is on APIs exported by Graal.
 
 ## `tip`
+...
+
+## Version 0.8
+15-Jul-2015, [Repository Revision](http://hg.openjdk.java.net/graal/graal/shortlog/graal-0.8)
 ### Graal
 * Add support for constructing low-level IR in SSA form (default behavior).
 * Add support for SSA linear scan register allocation (default behavior).
 * Remove dummy parameter `includeAbstract` from `ResolvedJavaType#resolveMethod()`; The behavior is now the `includeAbstract==true` case. The `includeAbstract==false` variant is available via `resolveConcreteMethod()`.
-...
+* HotSpot modifications have been renamed to JVMCI in preparation for [JEP 243](http://openjdk.java.net/jeps/243). As a result HotSpot options containing "Graal" have been changed to "JVMCI" (e.g., -XX:+BootstrapJVMCI).
+* All the APIs used to interface with the VM (`api.meta`, `api.code` etc.) have been moved to `jdk.internal.jvmci` packages (e.g., `jdk.internal.jvmci.meta`).
+* Fast JVMCI services do not need to implement an interface anymore, implementations simply need to be annotated with `jdk.internal.jvmci.service.ServiceProvider`.
 
 ### Truffle
-...
+* Moved Truffle to it own [repository](http://lafo.ssw.uni-linz.ac.at/hg/truffle/)
 
 ## Version 0.7
 29-Apr-2015, [Repository Revision](http://hg.openjdk.java.net/graal/graal/shortlog/graal-0.7)
--- a/graal/com.oracle.graal.api.directives/src/com/oracle/graal/api/directives/GraalDirectives.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.api.directives/src/com/oracle/graal/api/directives/GraalDirectives.java	Tue Jul 21 16:17:54 2015 +0200
@@ -283,4 +283,17 @@
         }
         return value;
     }
+
+    /**
+     * Ensures that the given object will be virtual (escape analyzed) at all points that are
+     * dominated by the current position.
+     */
+    public static void ensureVirtualized(@SuppressWarnings("unused") Object object) {
+    }
+
+    /**
+     * Ensures that the given object will be virtual at the current position.
+     */
+    public static void ensureVirtualizedHere(@SuppressWarnings("unused") Object object) {
+    }
 }
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Tue Jul 21 16:17:54 2015 +0200
@@ -24,9 +24,9 @@
 
 import static com.oracle.graal.asm.sparc.SPARCAssembler.CC.*;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag.*;
-import static com.oracle.graal.asm.sparc.SPARCAssembler.Op.*;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Op3s.*;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Opfs.*;
+import static com.oracle.graal.asm.sparc.SPARCAssembler.Ops.*;
 import static java.lang.String.*;
 import static jdk.internal.jvmci.sparc.SPARC.*;
 import jdk.internal.jvmci.code.*;
@@ -117,18 +117,6 @@
         }
     }
 
-    public enum Op {
-        Op00(0b00),
-        Op01(0b01),
-        Op10(0b10),
-        Op11(0b11);
-        int op;
-
-        Op(int op) {
-            this.op = op;
-        }
-    }
-
     public enum Op2s {
         // @formatter:off
 
@@ -162,113 +150,113 @@
     public enum Op3s {
         // @formatter:off
 
-        Add(0x00, "add", Op10),
-        And(0x01, "and", Op10),
-        Or(0x02, "or", Op10),
-        Xor(0x03, "xor", Op10),
-        Sub(0x04, "sub", Op10),
-        Andn(0x05, "andn", Op10),
-        Orn(0x06, "orn", Op10),
-        Xnor(0x07, "xnor", Op10),
-        Addc(0x08, "addc", Op10),
-        Mulx(0x09, "mulx", Op10),
-        Umul(0x0A, "umul", Op10),
-        Smul(0x0B, "smul", Op10),
-        Subc(0x0C, "subc", Op10),
-        Udivx(0x0D, "udivx", Op10),
-        Udiv(0x0E, "udiv", Op10),
-        Sdiv(0x0F, "sdiv", Op10),
+        Add(0x00, "add", ArithOp),
+        And(0x01, "and", ArithOp),
+        Or(0x02, "or", ArithOp),
+        Xor(0x03, "xor", ArithOp),
+        Sub(0x04, "sub", ArithOp),
+        Andn(0x05, "andn", ArithOp),
+        Orn(0x06, "orn", ArithOp),
+        Xnor(0x07, "xnor", ArithOp),
+        Addc(0x08, "addc", ArithOp),
+        Mulx(0x09, "mulx", ArithOp),
+        Umul(0x0A, "umul", ArithOp),
+        Smul(0x0B, "smul", ArithOp),
+        Subc(0x0C, "subc", ArithOp),
+        Udivx(0x0D, "udivx", ArithOp),
+        Udiv(0x0E, "udiv", ArithOp),
+        Sdiv(0x0F, "sdiv", ArithOp),
 
-        Addcc(0x10, "addcc", Op10),
-        Andcc(0x11, "andcc", Op10),
-        Orcc(0x12, "orcc", Op10),
-        Xorcc(0x13, "xorcc", Op10),
-        Subcc(0x14, "subcc", Op10),
-        Andncc(0x15, "andncc", Op10),
-        Orncc(0x16, "orncc", Op10),
-        Xnorcc(0x17, "xnorcc", Op10),
-        Addccc(0x18, "addccc", Op10),
+        Addcc(0x10, "addcc", ArithOp),
+        Andcc(0x11, "andcc", ArithOp),
+        Orcc(0x12, "orcc", ArithOp),
+        Xorcc(0x13, "xorcc", ArithOp),
+        Subcc(0x14, "subcc", ArithOp),
+        Andncc(0x15, "andncc", ArithOp),
+        Orncc(0x16, "orncc", ArithOp),
+        Xnorcc(0x17, "xnorcc", ArithOp),
+        Addccc(0x18, "addccc", ArithOp),
 
-        Umulcc(0x1A, "umulcc", Op10),
-        Smulcc(0x1B, "smulcc", Op10),
-        Subccc(0x1C, "subccc", Op10),
-        Udivcc(0x1E, "udivcc", Op10),
-        Sdivcc(0x1F, "sdivcc", Op10),
+        Umulcc(0x1A, "umulcc", ArithOp),
+        Smulcc(0x1B, "smulcc", ArithOp),
+        Subccc(0x1C, "subccc", ArithOp),
+        Udivcc(0x1E, "udivcc", ArithOp),
+        Sdivcc(0x1F, "sdivcc", ArithOp),
 
-        Taddcc(0x20, "taddcc", Op10),
-        Tsubcc(0x21, "tsubcc", Op10),
-        Taddcctv(0x22, "taddcctv", Op10),
-        Tsubcctv(0x23, "tsubcctv", Op10),
-        Mulscc(0x24, "mulscc", Op10),
-        Sll(0x25, "sll", Op10),
-        Sllx(0x25, "sllx", Op10),
-        Srl(0x26, "srl", Op10),
-        Srlx(0x26, "srlx", Op10),
-        Sra(0x27, "srax", Op10),
-        Srax(0x27, "srax", Op10),
-        Membar(0x28, "membar", Op10),
+        Taddcc(0x20, "taddcc", ArithOp),
+        Tsubcc(0x21, "tsubcc", ArithOp),
+        Taddcctv(0x22, "taddcctv", ArithOp),
+        Tsubcctv(0x23, "tsubcctv", ArithOp),
+        Mulscc(0x24, "mulscc", ArithOp),
+        Sll(0x25, "sll", ArithOp),
+        Sllx(0x25, "sllx", ArithOp),
+        Srl(0x26, "srl", ArithOp),
+        Srlx(0x26, "srlx", ArithOp),
+        Sra(0x27, "srax", ArithOp),
+        Srax(0x27, "srax", ArithOp),
+        Membar(0x28, "membar", ArithOp),
 
-        Flushw(0x2B, "flushw", Op10),
-        Movcc(0x2C, "movcc", Op10),
-        Sdivx(0x2D, "sdivx", Op10),
-        Popc(0x2E, "popc", Op10),
-        Movr(0x2F, "movr", Op10),
+        Flushw(0x2B, "flushw", ArithOp),
+        Movcc(0x2C, "movcc", ArithOp),
+        Sdivx(0x2D, "sdivx", ArithOp),
+        Popc(0x2E, "popc", ArithOp),
+        Movr(0x2F, "movr", ArithOp),
 
-        Fpop1(0b11_0100, "fpop1", Op10),
-        Fpop2(0b11_0101, "fpop2", Op10),
-        Impdep1(0b11_0110, "impdep1", Op10),
-        Impdep2(0b11_0111, "impdep2", Op10),
-        Jmpl(0x38, "jmpl", Op10),
-        Rett(0x39, "rett", Op10),
-        Trap(0x3a, "trap", Op10),
-        Flush(0x3b, "flush", Op10),
-        Save(0x3c, "save", Op10),
-        Restore(0x3d, "restore", Op10),
-        Retry(0x3e, "retry", Op10),
+        Fpop1(0b11_0100, "fpop1", ArithOp),
+        Fpop2(0b11_0101, "fpop2", ArithOp),
+        Impdep1(0b11_0110, "impdep1", ArithOp),
+        Impdep2(0b11_0111, "impdep2", ArithOp),
+        Jmpl(0x38, "jmpl", ArithOp),
+        Rett(0x39, "rett", ArithOp),
+        Trap(0x3a, "trap", ArithOp),
+        Flush(0x3b, "flush", ArithOp),
+        Save(0x3c, "save", ArithOp),
+        Restore(0x3d, "restore", ArithOp),
+        Retry(0x3e, "retry", ArithOp),
 
 
-        Casa(0b111100, "casa", Op11),
-        Casxa(0b111110, "casxa", Op11),
-        Prefetch(0b101101, "prefetch", Op11),
-        Prefetcha(0b111101, "prefetcha", Op11),
+        Casa(0b111100, "casa", LdstOp),
+        Casxa(0b111110, "casxa", LdstOp),
+        Prefetch(0b101101, "prefetch", LdstOp),
+        Prefetcha(0b111101, "prefetcha", LdstOp),
 
-        Lduw  (0b00_0000, "lduw", Op11),
-        Ldub  (0b00_0001, "ldub", Op11),
-        Lduh  (0b00_0010, "lduh", Op11),
-        Stw   (0b00_0100, "stw", Op11),
-        Stb   (0b00_0101, "stb", Op11),
-        Sth   (0b00_0110, "sth", Op11),
-        Ldsw  (0b00_1000, "ldsw", Op11),
-        Ldsb  (0b00_1001, "ldsb", Op11),
-        Ldsh  (0b00_1010, "ldsh", Op11),
-        Ldx   (0b00_1011, "ldx", Op11),
-        Stx   (0b00_1110, "stx", Op11),
+        Lduw  (0b00_0000, "lduw", LdstOp),
+        Ldub  (0b00_0001, "ldub", LdstOp),
+        Lduh  (0b00_0010, "lduh", LdstOp),
+        Stw   (0b00_0100, "stw", LdstOp),
+        Stb   (0b00_0101, "stb", LdstOp),
+        Sth   (0b00_0110, "sth", LdstOp),
+        Ldsw  (0b00_1000, "ldsw", LdstOp),
+        Ldsb  (0b00_1001, "ldsb", LdstOp),
+        Ldsh  (0b00_1010, "ldsh", LdstOp),
+        Ldx   (0b00_1011, "ldx", LdstOp),
+        Stx   (0b00_1110, "stx", LdstOp),
 
-        Ldf   (0b10_0000, "ldf", Op11),
-        Ldfsr (0b10_0001, "ldfsr", Op11),
-        Ldaf  (0b10_0010, "ldaf", Op11),
-        Lddf  (0b10_0011, "lddf", Op11),
-        Stf   (0b10_0100, "stf", Op11),
-        Stfsr (0b10_0101, "stfsr", Op11),
-        Staf  (0x10_0110, "staf", Op11),
-        Stdf  (0b10_0111, "stdf", Op11),
+        Ldf   (0b10_0000, "ldf", LdstOp),
+        Ldfsr (0b10_0001, "ldfsr", LdstOp),
+        Ldaf  (0b10_0010, "ldaf", LdstOp),
+        Lddf  (0b10_0011, "lddf", LdstOp),
+        Stf   (0b10_0100, "stf", LdstOp),
+        Stfsr (0b10_0101, "stfsr", LdstOp),
+        Staf  (0x10_0110, "staf", LdstOp),
+        Stdf  (0b10_0111, "stdf", LdstOp),
 
-        Rd    (0b10_1000, "rd", Op10),
-        Wr    (0b11_0000, "wr", Op10),
-        Fcmp  (0b11_0101, "fcmp", Op10),
+        Rd    (0b10_1000, "rd", ArithOp),
+        Wr    (0b11_0000, "wr", ArithOp),
+        Fcmp  (0b11_0101, "fcmp", ArithOp),
 
-        Ldxa  (0b01_1011, "ldxa", Op11),
-        Lduwa (0b01_0000, "lduwa", Op11),
+        Ldxa  (0b01_1011, "ldxa", LdstOp),
+        Lduwa (0b01_0000, "lduwa", LdstOp),
 
-        Tcc(0b11_1010, "tcc", Op10);
+        Tcc(0b11_1010, "tcc", ArithOp);
 
         // @formatter:on
 
         private final int value;
         private final String operator;
-        private final Op op;
+        private final Ops op;
 
-        private Op3s(int value, String name, Op op) {
+        private Op3s(int value, String name, Ops op) {
             this.value = value;
             this.operator = name;
             this.op = op;
@@ -914,20 +902,20 @@
 
     private void op3(Op3s op3, Opfs opf, Register rs1, Register rs2, Register rd) {
         int b = opf.value << 5 | (rs2 == null ? 0 : rs2.encoding);
-        fmt(op3.op.op, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b);
+        fmt(op3.op.value, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b);
     }
 
     protected void op3(Op3s op3, Register rs1, Register rs2, Register rd) {
         int b = rs2 == null ? 0 : rs2.encoding;
         int xBit = getXBit(op3);
-        fmt(op3.op.op, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b | xBit);
+        fmt(op3.op.value, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b | xBit);
     }
 
     protected void op3(Op3s op3, Register rs1, int simm13, Register rd) {
         assert isSimm13(simm13);
         int i = 1 << 13;
         int simm13WithX = simm13 | getXBit(op3);
-        fmt(op3.op.op, rd.encoding, op3.value, rs1.encoding, i | simm13WithX & ((1 << 13) - 1));
+        fmt(op3.op.value, rd.encoding, op3.value, rs1.encoding, i | simm13WithX & ((1 << 13) - 1));
     }
 
     // @formatter:off
@@ -1501,10 +1489,10 @@
         if (addr.getIndex().equals(Register.None)) {
             int dis = addr.getDisplacement();
             assert isSimm13(dis);
-            fmt(Prefetch.op.op, fcn.value, Prefetch.value, rs1.encoding, 1 << 13 | dis & ((1 << 13) - 1));
+            fmt(Prefetch.op.value, fcn.value, Prefetch.value, rs1.encoding, 1 << 13 | dis & ((1 << 13) - 1));
         } else {
             Register rs2 = addr.getIndex();
-            fmt(Prefetch.op.op, fcn.value, Prefetch.value, rs1.encoding, rs2.encoding);
+            fmt(Prefetch.op.value, fcn.value, Prefetch.value, rs1.encoding, rs2.encoding);
         }
     }
 
@@ -1670,7 +1658,7 @@
             if (asi != null) {
                 int b = rs2.encoding;
                 b |= asi.value << 5;
-                fmt(op3.op.op, rd.encoding, op3.value, rs1.encoding, b);
+                fmt(op3.op.value, rd.encoding, op3.value, rs1.encoding, b);
             } else {
                 op3(op3, rs1, rs2, rd);
             }
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Tue Jul 21 16:17:54 2015 +0200
@@ -39,7 +39,7 @@
      * patched.
      */
     private static final SPARCAddress Placeholder = new SPARCAddress(g0, 0);
-    private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(g1), new ScratchRegister(g3)};
+    private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(g3), new ScratchRegister(o7)};
     // Points to the next free scratch register
     private int nextFreeScratchRegister = 0;
     /**
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/NumUtil.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/NumUtil.java	Tue Jul 21 16:17:54 2015 +0200
@@ -93,6 +93,10 @@
         return s == (s & 0xFFFF);
     }
 
+    public static boolean isUShort(long s) {
+        return s == (s & 0xFFFF);
+    }
+
     public static boolean is32bit(long x) {
         return -0x80000000L <= x && x < 0x80000000L;
     }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64AddressNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64AddressNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -66,7 +66,19 @@
         AllocatableValue baseValue = base == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(base));
         AllocatableValue indexValue = index == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(index));
 
-        LIRKind kind = tool.getLIRKind(stamp());
+        AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue);
+        AllocatableValue indexReference;
+        if (scale.equals(Scale.Times1)) {
+            indexReference = LIRKind.derivedBaseFromValue(indexValue);
+        } else {
+            if (indexValue.getLIRKind().isValue()) {
+                indexReference = null;
+            } else {
+                indexReference = Value.ILLEGAL;
+            }
+        }
+
+        LIRKind kind = LIRKind.combineDerived(tool.getLIRKind(stamp()), baseReference, indexReference);
         gen.setResult(this, new AMD64AddressValue(kind, baseValue, indexValue, scale, displacement));
     }
 
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue Jul 21 16:17:54 2015 +0200
@@ -625,7 +625,7 @@
     @Override
     public Variable emitNegate(Value inputVal) {
         AllocatableValue input = asAllocatable(inputVal);
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         switch (input.getKind()) {
             case Int:
                 append(new AMD64Unary.MOp(NEG, DWORD, result, input));
@@ -648,7 +648,7 @@
     @Override
     public Variable emitNot(Value inputVal) {
         AllocatableValue input = asAllocatable(inputVal);
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         switch (input.getKind()) {
             case Int:
                 append(new AMD64Unary.MOp(NOT, DWORD, result, input));
@@ -662,29 +662,29 @@
         return result;
     }
 
-    private Variable emitBinary(AMD64BinaryArithmetic op, OperandSize size, boolean commutative, Value a, Value b, boolean setFlags) {
+    private Variable emitBinary(LIRKind resultKind, AMD64BinaryArithmetic op, OperandSize size, boolean commutative, Value a, Value b, boolean setFlags) {
         if (isConstant(b)) {
-            return emitBinaryConst(op, size, commutative, asAllocatable(a), asConstant(b), setFlags);
+            return emitBinaryConst(resultKind, op, size, commutative, asAllocatable(a), asConstant(b), setFlags);
         } else if (commutative && isConstant(a)) {
-            return emitBinaryConst(op, size, commutative, asAllocatable(b), asConstant(a), setFlags);
+            return emitBinaryConst(resultKind, op, size, commutative, asAllocatable(b), asConstant(a), setFlags);
         } else {
-            return emitBinaryVar(op.getRMOpcode(size), size, commutative, asAllocatable(a), asAllocatable(b));
+            return emitBinaryVar(resultKind, op.getRMOpcode(size), size, commutative, asAllocatable(a), asAllocatable(b));
         }
     }
 
-    private Variable emitBinary(AMD64RMOp op, OperandSize size, boolean commutative, Value a, Value b) {
+    private Variable emitBinary(LIRKind resultKind, AMD64RMOp op, OperandSize size, boolean commutative, Value a, Value b) {
         if (isConstant(b)) {
-            return emitBinaryConst(op, size, asAllocatable(a), asConstant(b));
+            return emitBinaryConst(resultKind, op, size, asAllocatable(a), asConstant(b));
         } else if (commutative && isConstant(a)) {
-            return emitBinaryConst(op, size, asAllocatable(b), asConstant(a));
+            return emitBinaryConst(resultKind, op, size, asAllocatable(b), asConstant(a));
         } else {
-            return emitBinaryVar(op, size, commutative, asAllocatable(a), asAllocatable(b));
+            return emitBinaryVar(resultKind, op, size, commutative, asAllocatable(a), asAllocatable(b));
         }
     }
 
-    private Variable emitBinaryConst(AMD64BinaryArithmetic op, OperandSize size, boolean commutative, AllocatableValue a, JavaConstant b, boolean setFlags) {
+    private Variable emitBinaryConst(LIRKind resultKind, AMD64BinaryArithmetic op, OperandSize size, boolean commutative, AllocatableValue a, JavaConstant b, boolean setFlags) {
         if (NumUtil.isInt(b.asLong())) {
-            Variable result = newVariable(LIRKind.derive(a, b));
+            Variable result = newVariable(resultKind);
             int constant = (int) b.asLong();
 
             if (!setFlags) {
@@ -698,7 +698,7 @@
             append(new AMD64Binary.ConstOp(op, size, result, a, constant));
             return result;
         } else {
-            return emitBinaryVar(op.getRMOpcode(size), size, commutative, a, asAllocatable(b));
+            return emitBinaryVar(resultKind, op.getRMOpcode(size), size, commutative, a, asAllocatable(b));
         }
     }
 
@@ -721,14 +721,14 @@
         return null;
     }
 
-    private Variable emitBinaryConst(AMD64RMOp op, OperandSize size, AllocatableValue a, JavaConstant b) {
-        Variable result = newVariable(LIRKind.derive(a, b));
+    private Variable emitBinaryConst(LIRKind resultKind, AMD64RMOp op, OperandSize size, AllocatableValue a, JavaConstant b) {
+        Variable result = newVariable(resultKind);
         append(new AMD64Binary.DataOp(op, size, result, a, b));
         return result;
     }
 
-    private Variable emitBinaryVar(AMD64RMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) {
-        Variable result = newVariable(LIRKind.derive(a, b));
+    private Variable emitBinaryVar(LIRKind resultKind, AMD64RMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) {
+        Variable result = newVariable(resultKind);
         if (commutative) {
             append(new AMD64Binary.CommutativeOp(op, size, result, a, b));
         } else {
@@ -738,32 +738,32 @@
     }
 
     @Override
-    public Variable emitAdd(Value a, Value b, boolean setFlags) {
+    public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(ADD, DWORD, true, a, b, setFlags);
+                return emitBinary(resultKind, ADD, DWORD, true, a, b, setFlags);
             case Long:
-                return emitBinary(ADD, QWORD, true, a, b, setFlags);
+                return emitBinary(resultKind, ADD, QWORD, true, a, b, setFlags);
             case Float:
-                return emitBinary(SSEOp.ADD, SS, true, a, b);
+                return emitBinary(resultKind, SSEOp.ADD, SS, true, a, b);
             case Double:
-                return emitBinary(SSEOp.ADD, SD, true, a, b);
+                return emitBinary(resultKind, SSEOp.ADD, SD, true, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
     }
 
     @Override
-    public Variable emitSub(Value a, Value b, boolean setFlags) {
+    public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(SUB, DWORD, false, a, b, setFlags);
+                return emitBinary(resultKind, SUB, DWORD, false, a, b, setFlags);
             case Long:
-                return emitBinary(SUB, QWORD, false, a, b, setFlags);
+                return emitBinary(resultKind, SUB, QWORD, false, a, b, setFlags);
             case Float:
-                return emitBinary(SSEOp.SUB, SS, false, a, b);
+                return emitBinary(resultKind, SSEOp.SUB, SS, false, a, b);
             case Double:
-                return emitBinary(SSEOp.SUB, SD, false, a, b);
+                return emitBinary(resultKind, SSEOp.SUB, SD, false, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
@@ -779,11 +779,11 @@
                 op = AMD64RMIOp.IMUL;
             }
 
-            Variable ret = newVariable(LIRKind.derive(a, b));
+            Variable ret = newVariable(LIRKind.combine(a, b));
             append(new AMD64Binary.RMIOp(op, size, ret, a, imm));
             return ret;
         } else {
-            return emitBinaryVar(AMD64RMOp.IMUL, size, true, a, asAllocatable(b));
+            return emitBinaryVar(LIRKind.combine(a, b), AMD64RMOp.IMUL, size, true, a, asAllocatable(b));
         }
     }
 
@@ -793,7 +793,7 @@
         } else if (isConstant(a)) {
             return emitIMULConst(size, asAllocatable(b), asConstant(a));
         } else {
-            return emitBinaryVar(AMD64RMOp.IMUL, size, true, asAllocatable(a), asAllocatable(b));
+            return emitBinaryVar(LIRKind.combine(a, b), AMD64RMOp.IMUL, size, true, asAllocatable(a), asAllocatable(b));
         }
     }
 
@@ -805,9 +805,9 @@
             case Long:
                 return emitIMUL(QWORD, a, b);
             case Float:
-                return emitBinary(SSEOp.MUL, SS, true, a, b);
+                return emitBinary(LIRKind.combine(a, b), SSEOp.MUL, SS, true, a, b);
             case Double:
-                return emitBinary(SSEOp.MUL, SD, true, a, b);
+                return emitBinary(LIRKind.combine(a, b), SSEOp.MUL, SD, true, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
@@ -820,7 +820,7 @@
     }
 
     private Value emitMulHigh(AMD64MOp opcode, OperandSize size, Value a, Value b) {
-        AMD64MulDivOp mulHigh = append(new AMD64MulDivOp(opcode, size, LIRKind.derive(a, b), moveToReg(AMD64.rax, a), asAllocatable(b)));
+        AMD64MulDivOp mulHigh = append(new AMD64MulDivOp(opcode, size, LIRKind.combine(a, b), moveToReg(AMD64.rax, a), asAllocatable(b)));
         return emitMove(mulHigh.getHighResult());
     }
 
@@ -849,7 +849,7 @@
     }
 
     public Value emitBinaryMemory(AMD64RMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
-        Variable result = newVariable(LIRKind.derive(a));
+        Variable result = newVariable(LIRKind.combine(a));
         append(new AMD64Binary.MemoryOp(op, size, result, a, location, state));
         return result;
     }
@@ -886,14 +886,14 @@
     }
 
     private AMD64MulDivOp emitIDIV(OperandSize size, Value a, Value b, LIRFrameState state) {
-        LIRKind kind = LIRKind.derive(a, b);
+        LIRKind kind = LIRKind.combine(a, b);
 
         AMD64SignExtendOp sx = append(new AMD64SignExtendOp(size, kind, moveToReg(AMD64.rax, a)));
         return append(new AMD64MulDivOp(AMD64MOp.IDIV, size, kind, sx.getHighResult(), sx.getLowResult(), asAllocatable(b), state));
     }
 
     private AMD64MulDivOp emitDIV(OperandSize size, Value a, Value b, LIRFrameState state) {
-        LIRKind kind = LIRKind.derive(a, b);
+        LIRKind kind = LIRKind.combine(a, b);
 
         RegisterValue rax = moveToReg(AMD64.rax, a);
         RegisterValue rdx = AMD64.rdx.asValue(kind);
@@ -926,9 +926,9 @@
                 AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state);
                 return emitMove(lop.getQuotient());
             case Float:
-                return emitBinary(SSEOp.DIV, SS, false, a, b);
+                return emitBinary(LIRKind.combine(a, b), SSEOp.DIV, SS, false, a, b);
             case Double:
-                return emitBinary(SSEOp.DIV, SD, false, a, b);
+                return emitBinary(LIRKind.combine(a, b), SSEOp.DIV, SD, false, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
@@ -944,12 +944,12 @@
                 AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state);
                 return emitMove(lop.getRemainder());
             case Float: {
-                Variable result = newVariable(LIRKind.derive(a, b));
+                Variable result = newVariable(LIRKind.combine(a, b));
                 append(new FPDivRemOp(FREM, result, load(a), load(b)));
                 return result;
             }
             case Double: {
-                Variable result = newVariable(LIRKind.derive(a, b));
+                Variable result = newVariable(LIRKind.combine(a, b));
                 append(new FPDivRemOp(DREM, result, load(a), load(b)));
                 return result;
             }
@@ -992,15 +992,16 @@
 
     @Override
     public Variable emitAnd(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(AND, DWORD, true, a, b, false);
+                return emitBinary(resultKind, AND, DWORD, true, a, b, false);
             case Long:
-                return emitBinary(AND, QWORD, true, a, b, false);
+                return emitBinary(resultKind, AND, QWORD, true, a, b, false);
             case Float:
-                return emitBinary(SSEOp.AND, PS, true, a, b);
+                return emitBinary(resultKind, SSEOp.AND, PS, true, a, b);
             case Double:
-                return emitBinary(SSEOp.AND, PD, true, a, b);
+                return emitBinary(resultKind, SSEOp.AND, PD, true, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
@@ -1008,15 +1009,16 @@
 
     @Override
     public Variable emitOr(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(OR, DWORD, true, a, b, false);
+                return emitBinary(resultKind, OR, DWORD, true, a, b, false);
             case Long:
-                return emitBinary(OR, QWORD, true, a, b, false);
+                return emitBinary(resultKind, OR, QWORD, true, a, b, false);
             case Float:
-                return emitBinary(SSEOp.OR, PS, true, a, b);
+                return emitBinary(resultKind, SSEOp.OR, PS, true, a, b);
             case Double:
-                return emitBinary(SSEOp.OR, PD, true, a, b);
+                return emitBinary(resultKind, SSEOp.OR, PD, true, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
@@ -1024,22 +1026,23 @@
 
     @Override
     public Variable emitXor(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(XOR, DWORD, true, a, b, false);
+                return emitBinary(resultKind, XOR, DWORD, true, a, b, false);
             case Long:
-                return emitBinary(XOR, QWORD, true, a, b, false);
+                return emitBinary(resultKind, XOR, QWORD, true, a, b, false);
             case Float:
-                return emitBinary(SSEOp.XOR, PS, true, a, b);
+                return emitBinary(resultKind, SSEOp.XOR, PS, true, a, b);
             case Double:
-                return emitBinary(SSEOp.XOR, PD, true, a, b);
+                return emitBinary(resultKind, SSEOp.XOR, PD, true, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
     }
 
     private Variable emitShift(AMD64Shift op, OperandSize size, Value a, Value b) {
-        Variable result = newVariable(LIRKind.derive(a, b).changeType(a.getPlatformKind()));
+        Variable result = newVariable(LIRKind.combine(a, b).changeType(a.getPlatformKind()));
         AllocatableValue input = asAllocatable(a);
         if (isConstant(b)) {
             JavaConstant c = asConstant(b);
@@ -1174,25 +1177,25 @@
     public Value emitFloatConvert(FloatConvert op, Value input) {
         switch (op) {
             case D2F:
-                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Float), SSEOp.CVTSD2SS, SD, input);
+                return emitConvertOp(LIRKind.combine(input).changeType(Kind.Float), SSEOp.CVTSD2SS, SD, input);
             case D2I:
-                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Int), SSEOp.CVTTSD2SI, DWORD, input);
+                return emitConvertOp(LIRKind.combine(input).changeType(Kind.Int), SSEOp.CVTTSD2SI, DWORD, input);
             case D2L:
-                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Long), SSEOp.CVTTSD2SI, QWORD, input);
+                return emitConvertOp(LIRKind.combine(input).changeType(Kind.Long), SSEOp.CVTTSD2SI, QWORD, input);
             case F2D:
-                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Double), SSEOp.CVTSS2SD, SS, input);
+                return emitConvertOp(LIRKind.combine(input).changeType(Kind.Double), SSEOp.CVTSS2SD, SS, input);
             case F2I:
-                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Int), SSEOp.CVTTSS2SI, DWORD, input);
+                return emitConvertOp(LIRKind.combine(input).changeType(Kind.Int), SSEOp.CVTTSS2SI, DWORD, input);
             case F2L:
-                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Long), SSEOp.CVTTSS2SI, QWORD, input);
+                return emitConvertOp(LIRKind.combine(input).changeType(Kind.Long), SSEOp.CVTTSS2SI, QWORD, input);
             case I2D:
-                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Double), SSEOp.CVTSI2SD, DWORD, input);
+                return emitConvertOp(LIRKind.combine(input).changeType(Kind.Double), SSEOp.CVTSI2SD, DWORD, input);
             case I2F:
-                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Float), SSEOp.CVTSI2SS, DWORD, input);
+                return emitConvertOp(LIRKind.combine(input).changeType(Kind.Float), SSEOp.CVTSI2SS, DWORD, input);
             case L2D:
-                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Double), SSEOp.CVTSI2SD, QWORD, input);
+                return emitConvertOp(LIRKind.combine(input).changeType(Kind.Double), SSEOp.CVTSI2SD, QWORD, input);
             case L2F:
-                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Float), SSEOp.CVTSI2SS, QWORD, input);
+                return emitConvertOp(LIRKind.combine(input).changeType(Kind.Float), SSEOp.CVTSI2SS, QWORD, input);
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
@@ -1202,7 +1205,7 @@
     public Value emitNarrow(Value inputVal, int bits) {
         if (inputVal.getKind() == Kind.Long && bits <= 32) {
             // TODO make it possible to reinterpret Long as Int in LIR without move
-            return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Int), AMD64RMOp.MOV, DWORD, inputVal);
+            return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Int), AMD64RMOp.MOV, DWORD, inputVal);
         } else {
             return inputVal;
         }
@@ -1217,11 +1220,11 @@
             // sign extend to 64 bits
             switch (fromBits) {
                 case 8:
-                    return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Long), MOVSXB, QWORD, inputVal);
+                    return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Long), MOVSXB, QWORD, inputVal);
                 case 16:
-                    return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Long), MOVSX, QWORD, inputVal);
+                    return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Long), MOVSX, QWORD, inputVal);
                 case 32:
-                    return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Long), MOVSXD, QWORD, inputVal);
+                    return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Long), MOVSXD, QWORD, inputVal);
                 default:
                     throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
             }
@@ -1229,9 +1232,9 @@
             // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
             switch (fromBits) {
                 case 8:
-                    return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Int), MOVSXB, DWORD, inputVal);
+                    return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Int), MOVSXB, DWORD, inputVal);
                 case 16:
-                    return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Int), MOVSX, DWORD, inputVal);
+                    return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Int), MOVSX, DWORD, inputVal);
                 case 32:
                     return inputVal;
                 default:
@@ -1247,14 +1250,14 @@
             return inputVal;
         } else if (fromBits > 32) {
             assert inputVal.getKind() == Kind.Long;
-            Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long));
+            Variable result = newVariable(LIRKind.combine(inputVal).changeType(Kind.Long));
             long mask = CodeUtil.mask(fromBits);
             append(new AMD64Binary.DataOp(AND.getRMOpcode(QWORD), QWORD, result, asAllocatable(inputVal), JavaConstant.forLong(mask)));
             return result;
         } else {
             assert inputVal.getKind().getStackKind() == Kind.Int;
 
-            LIRKind resultKind = LIRKind.derive(inputVal);
+            LIRKind resultKind = LIRKind.combine(inputVal);
             if (toBits > 32) {
                 resultKind = resultKind.changeType(Kind.Long);
             } else {
@@ -1311,7 +1314,7 @@
 
     @Override
     public Variable emitBitCount(Value value) {
-        Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
+        Variable result = newVariable(LIRKind.combine(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
             append(new AMD64Unary.RMOp(POPCNT, DWORD, result, asAllocatable(value)));
         } else {
@@ -1322,14 +1325,14 @@
 
     @Override
     public Variable emitBitScanForward(Value value) {
-        Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
+        Variable result = newVariable(LIRKind.combine(value).changeType(Kind.Int));
         append(new AMD64Unary.RMOp(BSF, QWORD, result, asAllocatable(value)));
         return result;
     }
 
     @Override
     public Variable emitBitScanReverse(Value value) {
-        Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
+        Variable result = newVariable(LIRKind.combine(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
             append(new AMD64Unary.RMOp(BSR, DWORD, result, asAllocatable(value)));
         } else {
@@ -1339,7 +1342,7 @@
     }
 
     public Value emitCountLeadingZeros(Value value) {
-        Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
+        Variable result = newVariable(LIRKind.combine(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
             append(new AMD64Unary.RMOp(LZCNT, DWORD, result, asAllocatable(value)));
         } else {
@@ -1349,7 +1352,7 @@
     }
 
     public Value emitCountTrailingZeros(Value value) {
-        Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
+        Variable result = newVariable(LIRKind.combine(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
             append(new AMD64Unary.RMOp(TZCNT, DWORD, result, asAllocatable(value)));
         } else {
@@ -1360,7 +1363,7 @@
 
     @Override
     public Value emitMathAbs(Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         switch (input.getKind()) {
             case Float:
                 append(new AMD64Binary.DataOp(SSEOp.AND, PS, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)), 16));
@@ -1376,7 +1379,7 @@
 
     @Override
     public Value emitMathSqrt(Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         switch (input.getKind()) {
             case Float:
                 append(new AMD64Unary.RMOp(SSEOp.SQRT, SS, result, asAllocatable(input)));
@@ -1392,35 +1395,35 @@
 
     @Override
     public Value emitMathLog(Value input, boolean base10) {
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         append(new AMD64MathIntrinsicOp(base10 ? LOG10 : LOG, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathCos(Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         append(new AMD64MathIntrinsicOp(COS, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathSin(Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         append(new AMD64MathIntrinsicOp(SIN, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathTan(Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         append(new AMD64MathIntrinsicOp(TAN, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Variable emitByteSwap(Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         append(new AMD64ByteSwapOp(result, input));
         return result;
     }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64SuitesProvider.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64SuitesProvider.java	Tue Jul 21 16:17:54 2015 +0200
@@ -38,7 +38,8 @@
     public LIRSuites createLIRSuites() {
         LIRSuites lirSuites = super.createLIRSuites();
         if (StackMoveOptimizationPhase.Options.LIROptStackMoveOptimizer.getValue() && GraalOptions.SSA_LIR.getValue()) {
-            lirSuites.getPostAllocationOptimizationStage().prependPhase(new StackMoveOptimizationPhase());
+            /* Note: this phase must be inserted <b>after</b> RedundantMoveElimination */
+            lirSuites.getPostAllocationOptimizationStage().appendPhase(new StackMoveOptimizationPhase());
         }
         return lirSuites;
     }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java	Tue Jul 21 16:17:54 2015 +0200
@@ -265,7 +265,7 @@
         int result = 1;
         result = prime * result + super.hashCode();
         result = prime * result + (exactType ? 1231 : 1237);
-        result = prime * result + ((type == null) ? 0 : type.hashCode());
+        result = prime * result + ((type == null || type.isJavaLangObject()) ? 0 : type.hashCode());
         return result;
     }
 
@@ -278,7 +278,19 @@
             return false;
         }
         AbstractObjectStamp other = (AbstractObjectStamp) obj;
-        if (exactType != other.exactType || !Objects.equals(type, other.type)) {
+        if (exactType != other.exactType) {
+            return false;
+        }
+        // null == java.lang.Object
+        if (type == null) {
+            if (other.type != null && !other.type.isJavaLangObject()) {
+                return false;
+            }
+        } else if (other.type == null) {
+            if (type != null && !type.isJavaLangObject()) {
+                return false;
+            }
+        } else if (!type.equals(other.type)) {
             return false;
         }
         return super.equals(other);
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCImmediateAddressNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCImmediateAddressNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -57,6 +57,11 @@
         AllocatableValue baseValue = tool.asAllocatable(gen.operand(base));
 
         LIRKind kind = tool.getLIRKind(stamp());
+        AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue);
+        if (baseReference != null) {
+            kind = kind.makeDerivedReference(baseReference);
+        }
+
         gen.setResult(this, new SPARCImmediateAddressValue(kind, baseValue, displacement));
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCIndexedAddressNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCIndexedAddressNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -55,7 +55,10 @@
         AllocatableValue baseValue = tool.asAllocatable(gen.operand(base));
         AllocatableValue indexValue = tool.asAllocatable(gen.operand(index));
 
-        LIRKind kind = tool.getLIRKind(stamp());
+        AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue);
+        AllocatableValue indexReference = LIRKind.derivedBaseFromValue(indexValue);
+
+        LIRKind kind = LIRKind.combineDerived(tool.getLIRKind(stamp()), baseReference, indexReference);
         gen.setResult(this, new SPARCIndexedAddressValue(kind, baseValue, indexValue));
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Tue Jul 21 16:17:54 2015 +0200
@@ -419,7 +419,7 @@
 
     @Override
     public Variable emitBitCount(Value operand) {
-        Variable result = newVariable(LIRKind.derive(operand).changeType(Kind.Int));
+        Variable result = newVariable(LIRKind.combine(operand).changeType(Kind.Int));
         if (operand.getKind().getStackKind() == Kind.Int) {
             append(new SPARCBitManipulationOp(IPOPCNT, result, asAllocatable(operand), this));
         } else {
@@ -430,14 +430,14 @@
 
     @Override
     public Variable emitBitScanForward(Value operand) {
-        Variable result = newVariable(LIRKind.derive(operand).changeType(Kind.Int));
+        Variable result = newVariable(LIRKind.combine(operand).changeType(Kind.Int));
         append(new SPARCBitManipulationOp(BSF, result, asAllocatable(operand), this));
         return result;
     }
 
     @Override
     public Variable emitBitScanReverse(Value operand) {
-        Variable result = newVariable(LIRKind.derive(operand).changeType(Kind.Int));
+        Variable result = newVariable(LIRKind.combine(operand).changeType(Kind.Int));
         if (operand.getKind().getStackKind() == Kind.Int) {
             append(new SPARCBitManipulationOp(IBSR, result, asAllocatable(operand), this));
         } else {
@@ -448,21 +448,21 @@
 
     @Override
     public Value emitMathAbs(Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         append(new SPARCMathIntrinsicOp(ABS, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathSqrt(Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         append(new SPARCMathIntrinsicOp(SQRT, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Variable emitByteSwap(Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         append(new SPARCByteSwapOp(this, result, input));
         return result;
     }
@@ -503,26 +503,26 @@
     }
 
     private Variable emitUnary(SPARCArithmetic op, Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
+        Variable result = newVariable(LIRKind.combine(input));
         append(new Unary2Op(op, result, load(input)));
         return result;
     }
 
-    private Variable emitBinary(SPARCArithmetic op, boolean commutative, Value a, Value b) {
-        return emitBinary(op, commutative, a, b, null);
+    private Variable emitBinary(LIRKind resultKind, SPARCArithmetic op, boolean commutative, Value a, Value b) {
+        return emitBinary(resultKind, op, commutative, a, b, null);
     }
 
-    private Variable emitBinary(SPARCArithmetic op, boolean commutative, Value a, Value b, LIRFrameState state) {
+    private Variable emitBinary(LIRKind resultKind, SPARCArithmetic op, boolean commutative, Value a, Value b, LIRFrameState state) {
         if (isConstant(b) && canInlineConstant(asConstant(b))) {
-            return emitBinaryConst(op, load(a), asConstant(b), state);
+            return emitBinaryConst(resultKind, op, load(a), asConstant(b), state);
         } else if (commutative && isConstant(a) && canInlineConstant(asConstant(a))) {
-            return emitBinaryConst(op, load(b), asConstant(a), state);
+            return emitBinaryConst(resultKind, op, load(b), asConstant(a), state);
         } else {
-            return emitBinaryVar(op, load(a), load(b), state);
+            return emitBinaryVar(resultKind, op, load(a), load(b), state);
         }
     }
 
-    private Variable emitBinaryConst(SPARCArithmetic op, AllocatableValue a, JavaConstant b, LIRFrameState state) {
+    private Variable emitBinaryConst(LIRKind resultKind, SPARCArithmetic op, AllocatableValue a, JavaConstant b, LIRFrameState state) {
         switch (op) {
             case IADD:
             case LADD:
@@ -537,48 +537,48 @@
             case IMUL:
             case LMUL:
                 if (canInlineConstant(b)) {
-                    Variable result = newVariable(LIRKind.derive(a, b));
+                    Variable result = newVariable(resultKind);
                     append(new BinaryRegConst(op, result, a, b, state));
                     return result;
                 }
                 break;
         }
-        return emitBinaryVar(op, a, asAllocatable(b), state);
+        return emitBinaryVar(resultKind, op, a, asAllocatable(b), state);
     }
 
-    private Variable emitBinaryVar(SPARCArithmetic op, AllocatableValue a, AllocatableValue b, LIRFrameState state) {
-        Variable result = newVariable(LIRKind.derive(a, b));
+    private Variable emitBinaryVar(LIRKind resultKind, SPARCArithmetic op, AllocatableValue a, AllocatableValue b, LIRFrameState state) {
+        Variable result = newVariable(resultKind);
         append(new BinaryRegReg(op, result, a, b, state));
         return result;
     }
 
     @Override
-    public Variable emitAdd(Value a, Value b, boolean setFlags) {
+    public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(setFlags ? IADDCC : IADD, true, a, b);
+                return emitBinary(resultKind, setFlags ? IADDCC : IADD, true, a, b);
             case Long:
-                return emitBinary(setFlags ? LADDCC : LADD, true, a, b);
+                return emitBinary(resultKind, setFlags ? LADDCC : LADD, true, a, b);
             case Float:
-                return emitBinary(FADD, true, a, b);
+                return emitBinary(resultKind, FADD, true, a, b);
             case Double:
-                return emitBinary(DADD, true, a, b);
+                return emitBinary(resultKind, DADD, true, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
     }
 
     @Override
-    public Variable emitSub(Value a, Value b, boolean setFlags) {
+    public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(setFlags ? ISUBCC : ISUB, false, a, b);
+                return emitBinary(resultKind, setFlags ? ISUBCC : ISUB, false, a, b);
             case Long:
-                return emitBinary(setFlags ? LSUBCC : LSUB, false, a, b);
+                return emitBinary(resultKind, setFlags ? LSUBCC : LSUB, false, a, b);
             case Float:
-                return emitBinary(FSUB, false, a, b);
+                return emitBinary(resultKind, FSUB, false, a, b);
             case Double:
-                return emitBinary(DSUB, false, a, b);
+                return emitBinary(resultKind, DSUB, false, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere("missing: " + a.getKind());
         }
@@ -586,21 +586,22 @@
 
     @Override
     public Variable emitMul(Value a, Value b, boolean setFlags) {
+        LIRKind resultKind = LIRKind.combine(a, b);
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(setFlags ? IMULCC : IMUL, true, a, b);
+                return emitBinary(resultKind, setFlags ? IMULCC : IMUL, true, a, b);
             case Long:
                 if (setFlags) {
-                    Variable result = newVariable(LIRKind.derive(a, b));
+                    Variable result = newVariable(LIRKind.combine(a, b));
                     append(new SPARCLMulccOp(result, load(a), load(b), this));
                     return result;
                 } else {
-                    return emitBinary(LMUL, true, a, b);
+                    return emitBinary(resultKind, LMUL, true, a, b);
                 }
             case Float:
-                return emitBinary(FMUL, true, a, b);
+                return emitBinary(resultKind, FMUL, true, a, b);
             case Double:
-                return emitBinary(DMUL, true, a, b);
+                return emitBinary(resultKind, DMUL, true, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere("missing: " + a.getKind());
         }
@@ -631,23 +632,24 @@
     }
 
     private Value emitMulHigh(SPARCArithmetic opcode, Value a, Value b) {
-        Variable result = newVariable(LIRKind.derive(a, b));
-        MulHighOp mulHigh = new MulHighOp(opcode, load(a), load(b), result, newVariable(LIRKind.derive(a, b)));
+        Variable result = newVariable(LIRKind.combine(a, b));
+        MulHighOp mulHigh = new MulHighOp(opcode, load(a), load(b), result, newVariable(LIRKind.combine(a, b)));
         append(mulHigh);
         return result;
     }
 
     @Override
     public Value emitDiv(Value a, Value b, LIRFrameState state) {
+        LIRKind resultKind = LIRKind.combine(a, b);
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(IDIV, false, a, b, state);
+                return emitBinary(resultKind, IDIV, false, a, b, state);
             case Long:
-                return emitBinary(LDIV, false, a, b, state);
+                return emitBinary(resultKind, LDIV, false, a, b, state);
             case Float:
-                return emitBinary(FDIV, false, a, b, state);
+                return emitBinary(resultKind, FDIV, false, a, b, state);
             case Double:
-                return emitBinary(DDIV, false, a, b, state);
+                return emitBinary(resultKind, DDIV, false, a, b, state);
             default:
                 throw JVMCIError.shouldNotReachHere("missing: " + a.getKind());
         }
@@ -655,7 +657,7 @@
 
     @Override
     public Value emitRem(Value a, Value b, LIRFrameState state) {
-        Variable result = newVariable(LIRKind.derive(a, b));
+        Variable result = newVariable(LIRKind.combine(a, b));
         Variable q1; // Intermediate values
         Variable q2;
         Variable q3;
@@ -697,7 +699,7 @@
 
     @Override
     public Value emitURem(Value a, Value b, LIRFrameState state) {
-        Variable result = newVariable(LIRKind.derive(a, b));
+        Variable result = newVariable(LIRKind.combine(a, b));
         switch (a.getKind().getStackKind()) {
             case Int:
                 append(new RemOp(IUREM, result, load(a), load(b), state, this));
@@ -729,16 +731,17 @@
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
-        return emitBinary(op, false, actualA, actualB, state);
+        return emitBinary(LIRKind.combine(actualA, actualB), op, false, actualA, actualB, state);
     }
 
     @Override
     public Variable emitAnd(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(IAND, true, a, b);
+                return emitBinary(resultKind, IAND, true, a, b);
             case Long:
-                return emitBinary(LAND, true, a, b);
+                return emitBinary(resultKind, LAND, true, a, b);
 
             default:
                 throw JVMCIError.shouldNotReachHere("missing: " + a.getKind());
@@ -747,11 +750,12 @@
 
     @Override
     public Variable emitOr(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(IOR, true, a, b);
+                return emitBinary(resultKind, IOR, true, a, b);
             case Long:
-                return emitBinary(LOR, true, a, b);
+                return emitBinary(resultKind, LOR, true, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere("missing: " + a.getKind());
         }
@@ -759,18 +763,19 @@
 
     @Override
     public Variable emitXor(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(IXOR, true, a, b);
+                return emitBinary(resultKind, IXOR, true, a, b);
             case Long:
-                return emitBinary(LXOR, true, a, b);
+                return emitBinary(resultKind, LXOR, true, a, b);
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
     }
 
     private Variable emitShift(SPARCArithmetic op, Value a, Value b) {
-        Variable result = newVariable(LIRKind.derive(a, b).changeType(a.getPlatformKind()));
+        Variable result = newVariable(LIRKind.combine(a, b).changeType(a.getPlatformKind()));
         if (isConstant(b) && canInlineConstant((JavaConstant) b)) {
             append(new BinaryRegConst(op, result, load(a), asConstant(b), null));
         } else {
@@ -832,11 +837,11 @@
         AllocatableValue input = asAllocatable(inputVal);
         switch (op) {
             case D2F:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), D2F, input);
+                return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Float), D2F, input);
             case F2D:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), F2D, input);
+                return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Double), F2D, input);
             case I2F: {
-                AllocatableValue intEncodedFloatReg = newVariable(LIRKind.derive(input).changeType(Kind.Float));
+                AllocatableValue intEncodedFloatReg = newVariable(LIRKind.combine(input).changeType(Kind.Float));
                 moveBetweenFpGp(intEncodedFloatReg, input);
                 AllocatableValue convertedFloatReg = newVariable(intEncodedFloatReg.getLIRKind());
                 append(new Unary2Op(I2F, convertedFloatReg, intEncodedFloatReg));
@@ -845,48 +850,48 @@
             case I2D: {
                 // Unfortunately we must do int -> float -> double because fitod has float
                 // and double encoding in one instruction
-                AllocatableValue convertedFloatReg = newVariable(LIRKind.derive(input).changeType(Kind.Float));
+                AllocatableValue convertedFloatReg = newVariable(LIRKind.combine(input).changeType(Kind.Float));
                 moveBetweenFpGp(convertedFloatReg, input);
-                AllocatableValue convertedDoubleReg = newVariable(LIRKind.derive(input).changeType(Kind.Double));
+                AllocatableValue convertedDoubleReg = newVariable(LIRKind.combine(input).changeType(Kind.Double));
                 append(new Unary2Op(I2D, convertedDoubleReg, convertedFloatReg));
                 return convertedDoubleReg;
             }
             case L2D: {
-                AllocatableValue longEncodedDoubleReg = newVariable(LIRKind.derive(input).changeType(Kind.Double));
+                AllocatableValue longEncodedDoubleReg = newVariable(LIRKind.combine(input).changeType(Kind.Double));
                 moveBetweenFpGp(longEncodedDoubleReg, input);
                 AllocatableValue convertedDoubleReg = newVariable(longEncodedDoubleReg.getLIRKind());
                 append(new Unary2Op(L2D, convertedDoubleReg, longEncodedDoubleReg));
                 return convertedDoubleReg;
             }
             case D2I: {
-                AllocatableValue convertedFloatReg = emitConvert2Op(LIRKind.derive(input).changeType(Kind.Float), D2I, input);
-                AllocatableValue convertedIntReg = newVariable(LIRKind.derive(convertedFloatReg).changeType(Kind.Int));
+                AllocatableValue convertedFloatReg = emitConvert2Op(LIRKind.combine(input).changeType(Kind.Float), D2I, input);
+                AllocatableValue convertedIntReg = newVariable(LIRKind.combine(convertedFloatReg).changeType(Kind.Int));
                 moveBetweenFpGp(convertedIntReg, convertedFloatReg);
                 return convertedIntReg;
             }
             case F2L: {
-                AllocatableValue convertedDoubleReg = emitConvert2Op(LIRKind.derive(input).changeType(Kind.Double), F2L, input);
-                AllocatableValue convertedLongReg = newVariable(LIRKind.derive(convertedDoubleReg).changeType(Kind.Long));
+                AllocatableValue convertedDoubleReg = emitConvert2Op(LIRKind.combine(input).changeType(Kind.Double), F2L, input);
+                AllocatableValue convertedLongReg = newVariable(LIRKind.combine(convertedDoubleReg).changeType(Kind.Long));
                 moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
                 return convertedLongReg;
             }
             case F2I: {
-                AllocatableValue convertedFloatReg = emitConvert2Op(LIRKind.derive(input).changeType(Kind.Float), F2I, input);
-                AllocatableValue convertedIntReg = newVariable(LIRKind.derive(convertedFloatReg).changeType(Kind.Int));
+                AllocatableValue convertedFloatReg = emitConvert2Op(LIRKind.combine(input).changeType(Kind.Float), F2I, input);
+                AllocatableValue convertedIntReg = newVariable(LIRKind.combine(convertedFloatReg).changeType(Kind.Int));
                 moveBetweenFpGp(convertedIntReg, convertedFloatReg);
                 return convertedIntReg;
             }
             case D2L: {
-                AllocatableValue convertedDoubleReg = emitConvert2Op(LIRKind.derive(input).changeType(Kind.Double), D2L, input);
-                AllocatableValue convertedLongReg = newVariable(LIRKind.derive(convertedDoubleReg).changeType(Kind.Long));
+                AllocatableValue convertedDoubleReg = emitConvert2Op(LIRKind.combine(input).changeType(Kind.Double), D2L, input);
+                AllocatableValue convertedLongReg = newVariable(LIRKind.combine(convertedDoubleReg).changeType(Kind.Long));
                 moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
                 return convertedLongReg;
             }
             case L2F: {
                 // long -> double -> float see above
-                AllocatableValue convertedDoubleReg = newVariable(LIRKind.derive(input).changeType(Kind.Double));
+                AllocatableValue convertedDoubleReg = newVariable(LIRKind.combine(input).changeType(Kind.Double));
                 moveBetweenFpGp(convertedDoubleReg, input);
-                AllocatableValue convertedFloatReg = newVariable(LIRKind.derive(input).changeType(Kind.Float));
+                AllocatableValue convertedFloatReg = newVariable(LIRKind.combine(input).changeType(Kind.Float));
                 append(new Unary2Op(L2F, convertedFloatReg, convertedDoubleReg));
                 return convertedFloatReg;
             }
@@ -919,7 +924,7 @@
     @Override
     public Value emitNarrow(Value inputVal, int bits) {
         if (inputVal.getKind() == Kind.Long && bits <= 32) {
-            return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), L2I, asAllocatable(inputVal));
+            return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Int), L2I, asAllocatable(inputVal));
         } else {
             return inputVal;
         }
@@ -934,11 +939,11 @@
             // sign extend to 64 bits
             switch (fromBits) {
                 case 8:
-                    return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), B2L, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Long), B2L, asAllocatable(inputVal));
                 case 16:
-                    return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), S2L, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Long), S2L, asAllocatable(inputVal));
                 case 32:
-                    return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), I2L, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Long), I2L, asAllocatable(inputVal));
                 default:
                     throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
             }
@@ -946,9 +951,9 @@
             // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
             switch (fromBits) {
                 case 8:
-                    return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), B2I, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Int), B2I, asAllocatable(inputVal));
                 case 16:
-                    return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), S2I, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Int), S2I, asAllocatable(inputVal));
                 case 32:
                     return inputVal;
                 default:
@@ -964,13 +969,13 @@
             return inputVal;
         } else if (fromBits > 32) {
             assert inputVal.getKind() == Kind.Long;
-            Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long));
+            Variable result = newVariable(LIRKind.combine(inputVal).changeType(Kind.Long));
             long mask = CodeUtil.mask(fromBits);
             append(new BinaryRegConst(SPARCArithmetic.LAND, result, asAllocatable(inputVal), JavaConstant.forLong(mask), null));
             return result;
         } else {
             assert inputVal.getKind() == Kind.Int || inputVal.getKind() == Kind.Short || inputVal.getKind() == Kind.Byte || inputVal.getKind() == Kind.Char : inputVal.getKind();
-            Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int));
+            Variable result = newVariable(LIRKind.combine(inputVal).changeType(Kind.Int));
             long mask = CodeUtil.mask(fromBits);
             JavaConstant constant = JavaConstant.forInt((int) mask);
             if (fromBits == 32) {
@@ -978,12 +983,12 @@
             } else if (canInlineConstant(constant)) {
                 append(new BinaryRegConst(SPARCArithmetic.IAND, result, asAllocatable(inputVal), constant, null));
             } else {
-                Variable maskVar = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int));
+                Variable maskVar = newVariable(LIRKind.combine(inputVal).changeType(Kind.Int));
                 emitMove(maskVar, constant);
                 append(new BinaryRegReg(IAND, result, maskVar, asAllocatable(inputVal)));
             }
             if (toBits > 32) {
-                Variable longResult = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long));
+                Variable longResult = newVariable(LIRKind.combine(inputVal).changeType(Kind.Long));
                 emitMove(longResult, result);
                 return longResult;
             } else {
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Tue Jul 21 16:17:54 2015 +0200
@@ -111,12 +111,54 @@
         };
     }
 
+    private ComplexMatchResult emitZeroExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        Kind toKind = null;
+        Kind fromKind = null;
+        if (fromBits == toBits) {
+            return null;
+        } else if (toBits > 32) {
+            toKind = Kind.Long;
+        } else if (toBits > 16) {
+            toKind = Kind.Int;
+        } else {
+            toKind = Kind.Short;
+        }
+        switch (fromBits) {
+            case 8:
+                fromKind = Kind.Byte;
+                break;
+            case 16:
+                fromKind = Kind.Short;
+                break;
+            case 32:
+                fromKind = Kind.Int;
+                break;
+            default:
+                throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+        }
+
+        Kind localFromKind = fromKind;
+        Kind localToKind = toKind;
+        return builder -> {
+            // Loads are always zero extending load
+            Value v = getLIRGeneratorTool().emitLoad(LIRKind.value(localFromKind), operand(access.getAddress()), getState(access));
+            return getLIRGeneratorTool().emitReinterpret(LIRKind.value(localToKind), v);
+        };
+    }
+
     @MatchRule("(SignExtend Read=access)")
     @MatchRule("(SignExtend FloatingRead=access)")
     public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
         return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
     }
 
+    @MatchRule("(ZeroExtend Read=access)")
+    @MatchRule("(ZeroExtend FloatingRead=access)")
+    public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
+        return emitZeroExtendMemory(access, root.getInputBits(), root.getResultBits());
+    }
+
     @Override
     public SPARCLIRGenerator getLIRGeneratorTool() {
         return (SPARCLIRGenerator) super.getLIRGeneratorTool();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CountedLoopTest.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CountedLoopTest.java	Tue Jul 21 16:17:54 2015 +0200
@@ -189,6 +189,22 @@
         test("decrementEqSnippet", 256, 0, 3);
     }
 
+    public static Result twoVariablesSnippet() {
+        Result ret = new Result();
+        int j = 0;
+        for (int i = 0; i < 1024; i++) {
+            j += 5;
+            ret.extremum = get(InductionVariable::extremumNode, j);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, j);
+        return ret;
+    }
+
+    @Test
+    public void testTwoVariables() {
+        test("twoVariablesSnippet");
+    }
+
     @NodeInfo
     private static class IVPropertyNode extends FloatingNode implements LIRLowerable {
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ImplicitNullCheckTest.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ImplicitNullCheckTest.java	Tue Jul 21 16:17:54 2015 +0200
@@ -53,6 +53,7 @@
         return 0;
     }
 
+    @Ignore("temporarily disable until LoadHub lowering is clarified")
     @Test
     public void test1() {
         test("test1Snippet");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAAssertionsTest.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,235 @@
+/*
+ * 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.compiler.test.ea;
+
+import jdk.internal.jvmci.code.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.compiler.test.*;
+
+public class PEAAssertionsTest extends GraalCompilerTest {
+
+    public static Object field;
+
+    public static void snippet1(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualized(object);
+    }
+
+    @Test
+    public void test1() {
+        test("snippet1", 1);
+    }
+
+    public static void snippet2(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualized(object);
+        field = object; // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void test2() {
+        test("snippet2", 1);
+    }
+
+    public static void snippet3(int i) {
+        Integer object = new Integer(i);
+        field = object;
+        GraalDirectives.ensureVirtualized(object); // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void test3() {
+        test("snippet3", 1);
+    }
+
+    public static void snippetHere1(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualizedHere(object);
+    }
+
+    @Test
+    public void testHere1() {
+        test("snippetHere1", 1);
+    }
+
+    public static void snippetHere2(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualizedHere(object);
+        field = object;
+    }
+
+    @Test
+    public void testHere2() {
+        test("snippetHere2", 1);
+    }
+
+    public static void snippetHere3(int i) {
+        Integer object = new Integer(i);
+        field = object;
+        GraalDirectives.ensureVirtualizedHere(object); // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testHere3() {
+        test("snippetHere3", 1);
+    }
+
+    public static void snippetBoxing1(int i) {
+        Integer object = i;
+        GraalDirectives.ensureVirtualizedHere(object); // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testBoxing1() {
+        test("snippetBoxing1", 1);
+    }
+
+    public static void snippetBoxing2(int i) {
+        Integer object = i;
+        GraalDirectives.ensureVirtualized(object); // assert here
+        field = object;
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testBoxing2() {
+        test("snippetBoxing2", 1);
+    }
+
+    public static void snippetControlFlow1(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            GraalDirectives.ensureVirtualized(object);
+        }
+        field = object;
+    }
+
+    @Test
+    public void testControlFlow1() {
+        test("snippetControlFlow1", true, 1);
+    }
+
+    public static void snippetControlFlow2(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            GraalDirectives.ensureVirtualized(object);
+        } else {
+            GraalDirectives.ensureVirtualized(object);
+        }
+        field = object; // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testControlFlow2() {
+        test("snippetControlFlow2", true, 1);
+    }
+
+    public static void snippetControlFlow3(boolean b, int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualized(object);
+        if (b) {
+            field = 1;
+        } else {
+            field = 2;
+        }
+        field = object; // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testControlFlow3() {
+        test("snippetControlFlow3", true, 1);
+    }
+
+    public static void snippetControlFlow4(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            field = object;
+        } else {
+            field = 2;
+        }
+        GraalDirectives.ensureVirtualized(object); // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testControlFlow4() {
+        test("snippetControlFlow4", true, 1);
+    }
+
+    public static void snippetControlFlow5(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            field = object;
+        } else {
+            field = 2;
+        }
+        GraalDirectives.ensureVirtualizedHere(object); // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testControlFlow5() {
+        test("snippetControlFlow5", true, 1);
+    }
+
+    public static final class TestClass {
+        Object a;
+        Object b;
+    }
+
+    public static void snippetIndirect1(boolean b, int i) {
+        Integer object = new Integer(i);
+        TestClass t = new TestClass();
+        t.a = object;
+        GraalDirectives.ensureVirtualized(object);
+
+        if (b) {
+            field = t; // assert here
+        } else {
+            field = 2;
+        }
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testIndirect1() {
+        test("snippetIndirect1", true, 1);
+    }
+
+    public static void snippetIndirect2(boolean b, int i) {
+        Integer object = new Integer(i);
+        TestClass t = new TestClass();
+        t.a = object;
+        GraalDirectives.ensureVirtualized(t);
+
+        if (b) {
+            field = object;
+        } else {
+            field = 2;
+        }
+    }
+
+    @Test
+    public void testIndirect2() {
+        test("snippetIndirect2", true, 1);
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Tue Jul 21 16:17:54 2015 +0200
@@ -23,29 +23,30 @@
 package com.oracle.graal.compiler.gen;
 
 import java.util.*;
-import java.util.Map.Entry;
+import java.util.Map.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.virtual.nodes.*;
 
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
 import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.meta.*;
 
-import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.nodes.virtual.*;
-import com.oracle.graal.virtual.nodes.*;
-
 /**
  * Builds {@link LIRFrameState}s from {@link FrameState}s.
  */
 public class DebugInfoBuilder {
 
-    protected final NodeMap<Value> nodeOperands;
+    protected final NodeValueMap nodeValueMap;
 
-    public DebugInfoBuilder(NodeMap<Value> nodeOperands) {
-        this.nodeOperands = nodeOperands;
+    public DebugInfoBuilder(NodeValueMap nodeValueMap) {
+        this.nodeValueMap = nodeValueMap;
     }
 
     protected final Map<VirtualObjectNode, VirtualObject> virtualObjects = Node.newMap();
@@ -216,7 +217,7 @@
 
                 } else if (value != null) {
                     STATE_VARIABLES.increment();
-                    Value operand = nodeOperands.get(value);
+                    Value operand = nodeValueMap.operand(value);
                     assert operand != null && (operand instanceof Variable || operand instanceof JavaConstant) : operand + " for " + value;
                     return operand;
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Jul 21 16:17:54 2015 +0200
@@ -100,15 +100,15 @@
     public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         this.gen = gen;
         this.nodeOperands = graph.createNodeMap();
-        this.debugInfoBuilder = createDebugInfoBuilder(graph, nodeOperands);
+        this.debugInfoBuilder = createDebugInfoBuilder(graph, this);
         if (MatchExpressions.getValue()) {
             matchRules = MatchRuleRegistry.lookup(getClass());
         }
     }
 
-    @SuppressWarnings({"unused", "hiding"})
-    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeMap<Value> nodeOperands) {
-        return new DebugInfoBuilder(nodeOperands);
+    @SuppressWarnings({"unused"})
+    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) {
+        return new DebugInfoBuilder(nodeValueMap);
     }
 
     /**
@@ -138,7 +138,8 @@
     }
 
     public ValueNode valueForOperand(Value value) {
-        for (Entry<Node, Value> entry : getNodeOperands().entries()) {
+        assert nodeOperands != null;
+        for (Entry<Node, Value> entry : nodeOperands.entries()) {
             if (entry.getValue().equals(value)) {
                 return (ValueNode) entry.getKey();
             }
@@ -215,7 +216,7 @@
     }
 
     private static boolean verifyPHIKind(LIRKind derivedKind, LIRKind phiKind) {
-        assert derivedKind.getPlatformKind() != Kind.Object || !derivedKind.isDerivedReference();
+        assert derivedKind.getPlatformKind() != Kind.Object || !derivedKind.isUnknownReference();
         PlatformKind phiPlatformKind = phiKind.getPlatformKind();
         assert derivedKind.equals(phiKind) || derivedKind.getPlatformKind().equals(phiPlatformKind instanceof Kind ? ((Kind) phiPlatformKind).getStackKind() : phiPlatformKind);
         return true;
@@ -633,11 +634,6 @@
         }
     }
 
-    public final NodeMap<Value> getNodeOperands() {
-        assert nodeOperands != null;
-        return nodeOperands;
-    }
-
     public DebugInfoBuilder getDebugInfoBuilder() {
         assert debugInfoBuilder != null;
         return debugInfoBuilder;
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Tue Jul 21 16:17:54 2015 +0200
@@ -204,6 +204,10 @@
         this.useProfiling = b;
     }
 
+    public GraphBuilderConfiguration withEagerResolving(boolean newEagerResolving) {
+        return new GraphBuilderConfiguration(newEagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins);
+    }
+
     public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
         return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins);
     }
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java	Tue Jul 21 16:17:54 2015 +0200
@@ -39,8 +39,17 @@
      */
     public static class InlineInfo {
 
-        /** Marker return value to use when the call site must not be inlined. */
-        public static final InlineInfo DO_NOT_INLINE = new InlineInfo(null, false);
+        /**
+         * Denotes a call site that must not be inlined and should be implemented by a node that
+         * does not speculate on the call not raising an exception.
+         */
+        public static final InlineInfo DO_NOT_INLINE_WITH_EXCEPTION = new InlineInfo(null, false);
+
+        /**
+         * Denotes a call site must not be inlined and can be implemented by a node that speculates
+         * the call will not throw an exception.
+         */
+        public static final InlineInfo DO_NOT_INLINE_NO_EXCEPTION = new InlineInfo(null, false);
 
         private final ResolvedJavaMethod methodToInline;
         private final boolean isIntrinsic;
@@ -75,8 +84,8 @@
      * method than the one specified here as the parameter, which allows method substitutions.
      * <p>
      * Non-null return value with a null {@link InlineInfo#getMethodToInline method}, e.g.,
-     * {@link InlineInfo#DO_NOT_INLINE}: The method is not inlined, and other plugins with a lower
-     * priority cannot overwrite this decision.
+     * {@link InlineInfo#DO_NOT_INLINE_WITH_EXCEPTION}: The method is not inlined, and other plugins
+     * with a lower priority cannot overwrite this decision.
      * <p>
      * Null return value: This plugin made no decision, other plugins with a lower priority are
      * asked.
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Tue Jul 21 16:17:54 2015 +0200
@@ -311,8 +311,7 @@
                     assert sig[0] == GraphBuilderContext.class;
                     assert sig[1] == ResolvedJavaMethod.class;
                     assert sig[2] == InvocationPlugin.Receiver.class;
-                    Class<?>[] sigTail = Arrays.copyOfRange(sig, 3, sig.length);
-                    assert Arrays.asList(sigTail).stream().allMatch(c -> c == ValueNode.class);
+                    assert Arrays.asList(sig).subList(3, sig.length).stream().allMatch(c -> c == ValueNode.class);
                     while (sigs.size() < sig.length - 2) {
                         sigs.add(null);
                     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Tue Jul 21 16:17:54 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -69,7 +69,7 @@
 
     @Override
     public FrameMap newFrameMap(RegisterConfig registerConfig) {
-        return new AMD64FrameMap(getCodeCache(), registerConfig);
+        return new AMD64FrameMap(getCodeCache(), registerConfig, this);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Jul 21 16:17:54 2015 +0200
@@ -38,6 +38,7 @@
 import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.amd64.*;
@@ -76,7 +77,7 @@
             try (InitTimer rt = timer("create Lowerer provider")) {
                 lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, target);
             }
-            HotSpotStampProvider stampProvider = new HotSpotStampProvider();
+            HotSpotStampProvider stampProvider = new HotSpotStampProvider(target.wordKind);
             Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, stampProvider);
 
             try (InitTimer rt = timer("create SnippetReflection provider")) {
@@ -86,7 +87,7 @@
                 replacements = createReplacements(runtime, p, snippetReflection);
             }
             try (InitTimer rt = timer("create WordTypes")) {
-                wordTypes = new HotSpotWordTypes(metaAccess, target.wordKind);
+                wordTypes = new HotSpotWordTypes(metaAccess, target.wordKind, stampProvider.createHubStamp(false), MethodPointerStamp.method());
             }
             try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
                 plugins = createGraphBuilderPlugins(runtime, target, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider);
@@ -167,15 +168,15 @@
         } else {
             /*
              * System V Application Binary Interface, AMD64 Architecture Processor Supplement
-             * 
+             *
              * Draft Version 0.96
-             * 
+             *
              * http://www.uclibc.org/docs/psABI-x86_64.pdf
-             * 
+             *
              * 3.2.1
-             * 
+             *
              * ...
-             * 
+             *
              * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12
              * through %r15 "belong" to the calling function and the called function is required to
              * preserve their values. In other words, a called function must preserve these
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDirectStaticCallOp.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012, 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.amd64;
+
+import jdk.internal.jvmci.hotspot.*;
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+
+/**
+ * A direct call that complies with the conventions for such calls in HotSpot. It doesn't use an
+ * inline cache so it's just a patchable call site.
+ */
+@Opcode("CALL_DIRECT")
+final class AMD64HotSpotDirectStaticCallOp extends DirectCallOp {
+    public static final LIRInstructionClass<AMD64HotSpotDirectStaticCallOp> TYPE = LIRInstructionClass.create(AMD64HotSpotDirectStaticCallOp.class);
+
+    private final InvokeKind invokeKind;
+    private final HotSpotVMConfig config;
+
+    AMD64HotSpotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, HotSpotVMConfig config) {
+        super(TYPE, target, result, parameters, temps, state);
+        assert invokeKind.isDirect();
+        this.invokeKind = invokeKind;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL);
+        super.emitCode(crb, masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Jul 21 16:17:54 2015 +0200
@@ -588,7 +588,7 @@
             CompressEncoding encoding = config.getOopEncoding();
             Value uncompressed;
             if (encoding.shift <= 3) {
-                LIRKind wordKind = LIRKind.derivedReference(target().wordKind);
+                LIRKind wordKind = LIRKind.unknownReference(target().wordKind);
                 uncompressed = new AMD64AddressValue(wordKind, getProviders().getRegisters().getHeapBaseRegister().asValue(wordKind), asAllocatable(address), Scale.fromInt(1 << encoding.shift), 0);
             } else {
                 uncompressed = emitUncompress(address, encoding, false);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Tue Jul 21 16:17:54 2015 +0200
@@ -25,23 +25,24 @@
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static jdk.internal.jvmci.amd64.AMD64.*;
 import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import com.oracle.graal.compiler.amd64.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.AMD64Move.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.*;
+import com.oracle.graal.nodes.spi.*;
+
 import jdk.internal.jvmci.amd64.*;
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.hotspot.*;
 import jdk.internal.jvmci.meta.*;
 
-import com.oracle.graal.compiler.amd64.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
-import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.*;
-
 /**
  * LIR generator specialized for AMD64 HotSpot.
  */
@@ -62,9 +63,9 @@
     }
 
     @Override
-    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeMap<Value> nodeOperands) {
+    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) {
         HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(Kind.Long));
-        return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
+        return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack);
     }
 
     @Override
@@ -110,7 +111,7 @@
             assert invokeKind.isDirect();
             HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
             assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method.";
-            append(new AMD64HotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, runtime.getConfig()));
+            append(new AMD64HotSpotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, runtime.getConfig()));
         }
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java	Tue Jul 21 15:16:00 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2012, 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.amd64;
-
-import jdk.internal.jvmci.hotspot.*;
-import jdk.internal.jvmci.meta.*;
-
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp;
-import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
-
-/**
- * A direct call that complies with the conventions for such calls in HotSpot. It doesn't use an
- * inline cache so it's just a patchable call site.
- */
-@Opcode("CALL_DIRECT")
-final class AMD64HotspotDirectStaticCallOp extends DirectCallOp {
-    public static final LIRInstructionClass<AMD64HotspotDirectStaticCallOp> TYPE = LIRInstructionClass.create(AMD64HotspotDirectStaticCallOp.class);
-
-    private final InvokeKind invokeKind;
-    private final HotSpotVMConfig config;
-
-    AMD64HotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, HotSpotVMConfig config) {
-        super(TYPE, target, result, parameters, temps, state);
-        assert invokeKind.isDirect();
-        this.invokeKind = invokeKind;
-        this.config = config;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL);
-        super.emitCode(crb, masm);
-    }
-}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Tue Jul 21 16:17:54 2015 +0200
@@ -23,6 +23,8 @@
 package com.oracle.graal.hotspot.sparc;
 
 import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
+import jdk.internal.jvmci.meta.*;
+import jdk.internal.jvmci.sparc.*;
 
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.lir.*;
@@ -34,12 +36,13 @@
 final class SPARCDeoptimizeOp extends SPARCLIRInstruction implements BlockEndOp {
     public static final LIRInstructionClass<SPARCDeoptimizeOp> TYPE = LIRInstructionClass.create(SPARCDeoptimizeOp.class);
     public static final SizeEstimate SIZE = SizeEstimate.create(1);
-
+    @Temp AllocatableValue pcRegister;
     @State private LIRFrameState info;
 
-    SPARCDeoptimizeOp(LIRFrameState info) {
+    SPARCDeoptimizeOp(LIRFrameState info, PlatformKind wordKind) {
         super(TYPE, SIZE);
         this.info = info;
+        pcRegister = SPARC.o7.asValue(LIRKind.value(wordKind));
     }
 
     @Override
@@ -52,6 +55,6 @@
         // [Deopt Handler Code]
         // 0xffffffff749bb60c: call 0xffffffff748da540 ; {runtime_call}
         // 0xffffffff749bb610: nop
-        SPARCCall.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, false, info);
+        SPARCCall.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, info);
     }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Jul 21 16:17:54 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -96,7 +96,7 @@
 
     @Override
     public FrameMap newFrameMap(RegisterConfig registerConfig) {
-        return new SPARCFrameMap(getCodeCache(), registerConfig);
+        return new SPARCFrameMap(getCodeCache(), registerConfig, this);
     }
 
     @Override
@@ -140,6 +140,7 @@
                     } else {
                         try (ScratchRegister sc = masm.getScratchRegister()) {
                             Register scratch = sc.getRegister();
+                            assert afterFrameInit || isGlobalRegister(scratch) : "Only global (g1-g7) registers are allowed if the frame was not initialized here. Got register " + scratch;
                             new Setx(address.getDisplacement(), scratch).emit(masm);
                             masm.stx(g0, new SPARCAddress(sp, scratch));
                         }
@@ -175,6 +176,7 @@
             } else {
                 try (ScratchRegister sc = masm.getScratchRegister()) {
                     Register scratch = sc.getRegister();
+                    assert isGlobalRegister(scratch) : "Only global registers are allowed before save. Got register " + scratch;
                     new Setx(stackpoinerChange, scratch).emit(masm);
                     masm.save(sp, scratch, sp);
                 }
@@ -283,7 +285,7 @@
         // TODO: (sa) Fold the two traversals into one
         stuffDelayedControlTransfers(lir);
         int constantSize = calculateConstantSize(lir);
-        boolean canUseImmediateConstantLoad = constantSize < (1 << 13) - 1;
+        boolean canUseImmediateConstantLoad = constantSize < (1 << 13);
         masm.setImmediateConstantLoad(canUseImmediateConstantLoad);
         FrameMap frameMap = crb.frameMap;
         RegisterConfig regConfig = frameMap.getRegisterConfig();
@@ -332,9 +334,9 @@
         HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls();
         if (!frameContext.isStub) {
             crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
-            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
+            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, null);
             crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
-            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null);
+            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, null);
         } else {
             // No need to emit the stubs for entries back into the method since
             // it has no calls that can cause such "return" entries
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Jul 21 16:17:54 2015 +0200
@@ -35,6 +35,7 @@
 import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -56,11 +57,11 @@
         Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig());
         HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters);
         LoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, target);
-        HotSpotStampProvider stampProvider = new HotSpotStampProvider();
+        HotSpotStampProvider stampProvider = new HotSpotStampProvider(codeCache.getTarget().wordKind);
         Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, stampProvider);
         HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime);
         HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, runtime.getConfig(), target);
-        HotSpotWordTypes wordTypes = new HotSpotWordTypes(metaAccess, target.wordKind);
+        HotSpotWordTypes wordTypes = new HotSpotWordTypes(metaAccess, target.wordKind, stampProvider.createHubStamp(false), MethodPointerStamp.method());
         Plugins plugins = createGraphBuilderPlugins(runtime, metaAccess, constantReflection, foreignCalls, stampProvider, snippetReflection, replacements, wordTypes);
         replacements.setGraphBuilderPlugins(plugins);
         HotSpotSuitesProvider suites = createSuites(runtime, plugins, codeCache);
@@ -99,6 +100,9 @@
         Set<Register> callerSavedRegisters = new HashSet<>();
         Collections.addAll(callerSavedRegisters, regConfig.getCalleeSaveLayout().registers);
         Collections.addAll(callerSavedRegisters, SPARC.fpuRegisters);
+        callerSavedRegisters.add(SPARC.g1);
+        callerSavedRegisters.add(SPARC.g4);
+        callerSavedRegisters.add(SPARC.g5);
         Value[] nativeABICallerSaveRegisters = new Value[callerSavedRegisters.size()];
         int i = 0;
         for (Register reg : callerSavedRegisters) {
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java	Tue Jul 21 16:17:54 2015 +0200
@@ -22,10 +22,11 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+import static jdk.internal.jvmci.code.ValueUtil.*;
+import static jdk.internal.jvmci.sparc.SPARC.*;
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.meta.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-import static jdk.internal.jvmci.sparc.SPARC.*;
 
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.lir.*;
@@ -41,20 +42,23 @@
     private final Register thread;
     private final Register stackPointer;
     @Def({REG, STACK}) protected Value threadTemp;
+    @Temp({REG}) protected AllocatableValue spScratch;
 
-    public SPARCHotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, Register thread, Register stackPointer, Value threadTemp) {
+    public SPARCHotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, Register thread, Register stackPointer, Value threadTemp, AllocatableValue spScratch) {
         super(TYPE, SIZE);
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.thread = thread;
         this.stackPointer = stackPointer;
         this.threadTemp = threadTemp;
+        this.spScratch = spScratch;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
         // Save last Java frame.
-        masm.add(stackPointer, STACK_BIAS, g4);
-        masm.stx(g4, new SPARCAddress(thread, threadLastJavaSpOffset));
+        Register scratchRegister = asRegister(spScratch);
+        masm.add(stackPointer, STACK_BIAS, scratchRegister);
+        masm.stx(scratchRegister, new SPARCAddress(thread, threadLastJavaSpOffset));
 
         // Save the thread register when calling out to the runtime.
         SPARCMove.move(crb, masm, threadTemp, thread.asValue(LIRKind.value(Kind.Long)), delayedControlTransfer);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java	Tue Jul 21 16:17:54 2015 +0200
@@ -22,11 +22,12 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+import static jdk.internal.jvmci.code.ValueUtil.*;
+import static jdk.internal.jvmci.meta.LIRKind.*;
+import static jdk.internal.jvmci.sparc.SPARC.*;
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.meta.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-import static jdk.internal.jvmci.code.ValueUtil.*;
-import static jdk.internal.jvmci.sparc.SPARC.*;
 
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.hotspot.*;
@@ -48,8 +49,10 @@
     @Alive(REG) AllocatableValue framePc;
     @Alive(REG) AllocatableValue senderSp;
     @Temp(REG) AllocatableValue scratch;
+    @Temp(REG) AllocatableValue callerReturnPc;
 
-    SPARCHotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue scratch) {
+    SPARCHotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue scratch,
+                    PlatformKind wordKind) {
         super(TYPE);
         this.thread = thread;
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
@@ -57,6 +60,7 @@
         this.framePc = framePc;
         this.senderSp = senderSp;
         this.scratch = scratch;
+        callerReturnPc = o7.asValue(value(wordKind));
     }
 
     @Override
@@ -70,7 +74,7 @@
         masm.mov(senderSpRegister, o5);
 
         // Load final frame PC.
-        masm.mov(framePcRegister, o7);
+        masm.mov(framePcRegister, asRegister(callerReturnPc));
 
         // Allocate a full sized frame.
         masm.save(sp, -totalFrameSize, sp);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Tue Jul 21 16:17:54 2015 +0200
@@ -33,7 +33,7 @@
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
 import jdk.internal.jvmci.hotspot.*;
-import jdk.internal.jvmci.hotspot.HotSpotVMConfig.*;
+import jdk.internal.jvmci.hotspot.HotSpotVMConfig.CompressEncoding;
 import jdk.internal.jvmci.meta.*;
 import jdk.internal.jvmci.sparc.*;
 
@@ -142,7 +142,8 @@
             Register thread = registers.getThreadRegister();
             Value threadTemp = newVariable(LIRKind.value(Kind.Long));
             Register stackPointer = registers.getStackPointerRegister();
-            append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread, stackPointer, threadTemp));
+            Variable spScratch = newVariable(LIRKind.value(target().wordKind));
+            append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread, stackPointer, threadTemp, spScratch));
             result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
             append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), thread, threadTemp));
         } else {
@@ -192,7 +193,7 @@
     @Override
     public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
         moveDeoptValuesToThread(actionAndReason, speculation);
-        append(new SPARCDeoptimizeOp(state));
+        append(new SPARCDeoptimizeOp(state, target().wordKind));
     }
 
     @Override
@@ -399,7 +400,8 @@
         Variable framePcVariable = load(framePc);
         Variable senderSpVariable = load(senderSp);
         Variable scratchVariable = newVariable(LIRKind.value(getHostWordKind()));
-        append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable));
+        append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable,
+                        target().wordKind));
     }
 
     public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
@@ -419,10 +421,11 @@
         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP);
 
         Register threadRegister = getProviders().getRegisters().getThreadRegister();
-        Value threadTemp = newVariable(LIRKind.value(Kind.Long));
+        Value threadTemp = newVariable(LIRKind.value(target().wordKind));
         Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
-        append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp));
-        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(Kind.Long)), trapRequest);
+        Variable spScratch = newVariable(LIRKind.value(target().wordKind));
+        append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp, spScratch));
+        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(target().wordKind)), trapRequest);
         append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister, threadTemp));
 
         Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((SPARCHotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo();
@@ -438,10 +441,11 @@
         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(FETCH_UNROLL_INFO);
 
         Register threadRegister = getProviders().getRegisters().getThreadRegister();
-        Value threadTemp = newVariable(LIRKind.value(Kind.Long));
+        Value threadTemp = newVariable(LIRKind.value(target().wordKind));
         Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
-        append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp));
-        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(Kind.Long)));
+        Variable spScratch = newVariable(LIRKind.value(target().wordKind));
+        append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp, spScratch));
+        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(target().wordKind)));
         append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister, threadTemp));
 
         Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((SPARCHotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo();
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Tue Jul 21 16:17:54 2015 +0200
@@ -24,22 +24,23 @@
 
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static jdk.internal.jvmci.sparc.SPARC.*;
+
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.sparc.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.sparc.SPARCMove.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.*;
+import com.oracle.graal.nodes.spi.*;
+
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.hotspot.*;
 import jdk.internal.jvmci.meta.*;
 
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.sparc.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.lir.sparc.SPARCMove.CompareAndSwapOp;
-import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.*;
-
 public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
     private HotSpotGraalRuntimeProvider runtime;
@@ -53,9 +54,9 @@
     }
 
     @Override
-    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeMap<Value> nodeOperands) {
+    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) {
         HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(Kind.Long));
-        return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
+        return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack);
     }
 
     private SPARCHotSpotLIRGenerator getGen() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ConstantPoolSubstitutionsTests.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,116 @@
+/*
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.*;
+
+import jdk.internal.jvmci.debug.*;
+import jdk.internal.jvmci.debug.Debug.*;
+import sun.misc.*;
+import sun.reflect.*;
+
+public class ConstantPoolSubstitutionsTests extends GraalCompilerTest {
+
+    protected StructuredGraph test(final String snippet) {
+        try (Scope s = Debug.scope("ConstantPoolSubstitutionsTests", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            compile(graph.method(), graph);
+            assertNotInGraph(graph, Invoke.class);
+            Debug.dump(graph, snippet);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) {
+        for (Node node : graph.getNodes()) {
+            if (clazz.isInstance(node)) {
+                fail(node.toString());
+            }
+        }
+        return graph;
+    }
+
+    @Test
+    public void testGetSize() {
+        ConstantPool cp = SharedSecrets.getJavaLangAccess().getConstantPool(Object.class);
+        test("getSize", cp);
+    }
+
+    @Test
+    public void testGetIntAt() {
+        test("getIntAt");
+    }
+
+    @Test
+    public void testGetLongAt() {
+        test("getLongAt");
+    }
+
+    @Test
+    public void testGetFloatAt() {
+        test("getFloatAt");
+    }
+
+    @Test
+    public void testGetDoubleAt() {
+        test("getDoubleAt");
+    }
+
+    // @Test
+    public void testGetUTF8At() {
+        test("getUTF8At");
+    }
+
+    public int getSize(ConstantPool cp) {
+        return cp.getSize();
+    }
+
+    public int getIntAt(ConstantPool cp) {
+        return cp.getIntAt(0);
+    }
+
+    public long getLongAt(ConstantPool cp) {
+        return cp.getLongAt(0);
+    }
+
+    public float getFloatAt(ConstantPool cp) {
+        return cp.getFloatAt(0);
+    }
+
+    public double getDoubleAt(ConstantPool cp) {
+        return cp.getDoubleAt(0);
+    }
+
+    public String getUTF8At(ConstantPool cp) {
+        return cp.getUTF8At(0);
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Tue Jul 21 16:17:54 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -52,7 +52,7 @@
 /**
  * HotSpot specific backend.
  */
-public abstract class HotSpotBackend extends Backend {
+public abstract class HotSpotBackend extends Backend implements FrameMap.ReferenceMapBuilderFactory {
 
     public static class Options {
         // @formatter:off
@@ -242,4 +242,9 @@
             HotSpotInstructionProfiling.countInstructions(lir, crb.asm);
         }
     }
+
+    @Override
+    public ReferenceMapBuilder newReferenceMapBuilder(int totalFrameSize) {
+        return new HotSpotReferenceMapBuilder(getTarget(), totalFrameSize);
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Tue Jul 21 16:17:54 2015 +0200
@@ -22,14 +22,15 @@
  */
 package com.oracle.graal.hotspot;
 
+import static jdk.internal.jvmci.code.BytecodeFrame.*;
+
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
 import jdk.internal.jvmci.meta.*;
-import static jdk.internal.jvmci.code.BytecodeFrame.*;
-
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
 
 /**
  * Extends {@link DebugInfoBuilder} to allocate the extra debug information required for locks.
@@ -38,8 +39,8 @@
 
     private final HotSpotLockStack lockStack;
 
-    public HotSpotDebugInfoBuilder(NodeMap<Value> nodeOperands, HotSpotLockStack lockStack) {
-        super(nodeOperands);
+    public HotSpotDebugInfoBuilder(NodeValueMap nodeValueMap, HotSpotLockStack lockStack) {
+        super(nodeValueMap);
         this.lockStack = lockStack;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMapBuilder.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2009, 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;
+
+import static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.framemap.*;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.common.*;
+import jdk.internal.jvmci.hotspot.*;
+import jdk.internal.jvmci.meta.*;
+
+public final class HotSpotReferenceMapBuilder extends ReferenceMapBuilder {
+
+    private int maxRegisterSize;
+
+    private final ArrayList<Value> objectValues;
+    private int objectCount;
+
+    private final TargetDescription target;
+    private final int totalFrameSize;
+
+    public HotSpotReferenceMapBuilder(TargetDescription target, int totalFrameSize) {
+        this.objectValues = new ArrayList<>();
+        this.objectCount = 0;
+
+        this.target = target;
+        this.totalFrameSize = totalFrameSize;
+    }
+
+    @Override
+    public void addLiveValue(Value v) {
+        if (isConstant(v)) {
+            return;
+        }
+        LIRKind lirKind = v.getLIRKind();
+        if (!lirKind.isValue()) {
+            objectValues.add(v);
+            if (lirKind.isUnknownReference()) {
+                objectCount++;
+            } else {
+                objectCount += lirKind.getReferenceCount();
+            }
+        }
+        if (isRegister(v)) {
+            int size = target.getSizeInBytes(lirKind.getPlatformKind());
+            if (size > maxRegisterSize) {
+                maxRegisterSize = size;
+            }
+        }
+    }
+
+    @Override
+    public ReferenceMap finish(LIRFrameState state) {
+        Location[] objects = new Location[objectCount];
+        Location[] derivedBase = new Location[objectCount];
+        int[] sizeInBytes = new int[objectCount];
+
+        int idx = 0;
+        for (Value obj : objectValues) {
+            LIRKind kind = obj.getLIRKind();
+            int bytes = bytesPerElement(kind);
+            if (kind.isUnknownReference()) {
+                throw JVMCIError.unimplemented("derived references not yet implemented");
+            } else {
+                Location base = null;
+                if (kind.isDerivedReference()) {
+                    Variable baseVariable = (Variable) kind.getDerivedReferenceBase();
+                    Value baseValue = state.getLiveBasePointers().get(baseVariable.index);
+                    assert baseValue.getPlatformKind().getVectorLength() == 1 && baseValue.getLIRKind().isReference(0) && !baseValue.getLIRKind().isDerivedReference();
+                    base = toLocation(baseValue, 0);
+                }
+
+                for (int i = 0; i < kind.getPlatformKind().getVectorLength(); i++) {
+                    if (kind.isReference(i)) {
+                        objects[idx] = toLocation(obj, i * bytes);
+                        derivedBase[idx] = base;
+                        sizeInBytes[idx] = bytes;
+                        idx++;
+                    }
+                }
+            }
+        }
+
+        return new HotSpotReferenceMap(objects, derivedBase, sizeInBytes, maxRegisterSize);
+    }
+
+    private int bytesPerElement(LIRKind kind) {
+        PlatformKind platformKind = kind.getPlatformKind();
+        return target.getSizeInBytes(platformKind) / platformKind.getVectorLength();
+    }
+
+    private Location toLocation(Value v, int offset) {
+        if (isRegister(v)) {
+            return Location.subregister(asRegister(v), offset);
+        } else {
+            StackSlot s = asStackSlot(v);
+            return Location.stack(s.getOffset(totalFrameSize) + offset);
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Jul 21 16:17:54 2015 +0200
@@ -159,6 +159,8 @@
             arraycopySnippets.lower((ArrayCopyNode) n, tool);
         } else if (n instanceof ArrayCopySlowPathNode) {
             arraycopySnippets.lower((ArrayCopySlowPathNode) n, tool);
+        } else if (n instanceof ArrayCopyUnrollNode) {
+            arraycopySnippets.lower((ArrayCopyUnrollNode) n, tool);
         } else if (n instanceof G1PreWriteBarrier) {
             writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
         } else if (n instanceof G1PostWriteBarrier) {
@@ -272,7 +274,7 @@
                 ResolvedJavaType receiverType = invoke.getReceiverType();
                 if (hsMethod.isInVirtualMethodTable(receiverType)) {
                     Kind wordKind = runtime.getTarget().wordKind;
-                    ValueNode hub = createReadHub(graph, receiver, receiverNullCheck);
+                    ValueNode hub = createReadHub(graph, receiver, receiverNullCheck, tool);
 
                     ReadNode metaspaceMethod = createReadVirtualMethod(graph, hub, hsMethod, receiverType);
                     // We use LocationNode.ANY_LOCATION for the reads that access the
@@ -330,13 +332,13 @@
     }
 
     @Override
-    protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor) {
+    protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor, LoweringTool tool) {
         /*
          * Anchor the read of the element klass to the cfg, because it is only valid when arrayClass
          * is an object class, which might not be the case in other parts of the compiled method.
          */
         AddressNode address = createOffsetAddress(graph, arrayHub, runtime.getConfig().arrayClassElementOffset);
-        return graph.unique(new FloatingReadNode(address, OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION, null, KlassPointerStamp.klassNonNull(), AbstractBeginNode.prevBegin(anchor)));
+        return graph.unique(new FloatingReadNode(address, OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION, null, tool.getStampProvider().createHubStamp(true), AbstractBeginNode.prevBegin(anchor)));
     }
 
     @Override
@@ -483,11 +485,14 @@
     }
 
     @Override
-    protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, GuardingNode guard) {
+    protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, GuardingNode guard, LoweringTool tool) {
+        if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
+            return graph.unique(new LoadHubNode(tool.getStampProvider(), object, guard != null ? guard.asNode() : null));
+        }
         HotSpotVMConfig config = runtime.getConfig();
         assert !object.isConstant() || object.isNullConstant();
 
-        KlassPointerStamp hubStamp = KlassPointerStamp.klassNonNull();
+        KlassPointerStamp hubStamp = (KlassPointerStamp) tool.getStampProvider().createHubStamp(true);
         if (config.useCompressedClassPointers) {
             hubStamp = hubStamp.compressed(config.getKlassEncoding());
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Tue Jul 21 16:17:54 2015 +0200
@@ -47,7 +47,7 @@
     public HotSpotProviders(MetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls,
                     LoweringProvider lowerer, Replacements replacements, SuitesProvider suites, HotSpotRegistersProvider registers, SnippetReflectionProvider snippetReflection,
                     HotSpotWordTypes wordTypes, Plugins graphBuilderPlugins) {
-        super(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, new HotSpotStampProvider());
+        super(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, new HotSpotStampProvider(codeCache.getTarget().wordKind));
         this.suites = suites;
         this.registers = registers;
         this.snippetReflection = snippetReflection;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotStampProvider.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotStampProvider.java	Tue Jul 21 16:17:54 2015 +0200
@@ -22,17 +22,43 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import jdk.internal.jvmci.meta.*;
+
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.nodes.spi.*;
 
 public class HotSpotStampProvider implements StampProvider {
 
+    private final KlassPointerStamp klassStamp;
+
+    private final KlassPointerStamp klassNonNullStamp;
+
+    @SuppressWarnings("unused") private final Kind wordKind;
+
+    public HotSpotStampProvider(Kind wordKind) {
+        this.wordKind = wordKind;
+        klassStamp = new KlassPointerStamp(false, false, wordKind);
+        klassNonNullStamp = new KlassPointerStamp(true, false, wordKind);
+    }
+
+    public KlassPointerStamp klass() {
+        return klassStamp;
+    }
+
+    public KlassPointerStamp klassNonNull() {
+        return klassNonNullStamp;
+    }
+
     public Stamp createHubStamp(ObjectStamp object) {
-        return KlassPointerStamp.klassNonNull();
+        return klassNonNull();
     }
 
     public Stamp createMethodStamp() {
         return MethodPointerStamp.methodNonNull();
     }
+
+    public Stamp createHubStamp(boolean nonNull) {
+        return nonNull ? klassNonNullStamp : klassStamp;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Tue Jul 21 16:17:54 2015 +0200
@@ -43,17 +43,21 @@
 import com.oracle.graal.nodes.memory.address.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.*;
 
 /**
  * Extends {@link WordOperationPlugin} to handle {@linkplain HotSpotOperation HotSpot word
  * operations}.
  */
 class HotSpotWordOperationPlugin extends WordOperationPlugin {
-    public HotSpotWordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) {
+
+    public HotSpotWordOperationPlugin(SnippetReflectionProvider snippetReflection, HotSpotWordTypes wordTypes) {
         super(snippetReflection, wordTypes);
     }
 
+    HotSpotWordTypes wordTypes() {
+        return (HotSpotWordTypes) wordTypes;
+    }
+
     @Override
     protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) {
         ResolvedJavaType arrayType = StampTool.typeOrNull(array);
@@ -115,17 +119,17 @@
 
             case TO_KLASS_POINTER:
                 assert args.length == 1;
-                b.addPush(returnKind, new PointerCastNode(KlassPointerStamp.klass(), args[0]));
+                b.addPush(returnKind, new PointerCastNode(wordTypes().getKlassPointerStamp(), args[0]));
                 break;
 
             case TO_METHOD_POINTER:
                 assert args.length == 1;
-                b.addPush(returnKind, new PointerCastNode(MethodPointerStamp.method(), args[0]));
+                b.addPush(returnKind, new PointerCastNode(wordTypes().getMethodPointerStamp(), args[0]));
                 break;
 
             case READ_KLASS_POINTER:
                 assert args.length == 2 || args.length == 3;
-                Stamp readStamp = KlassPointerStamp.klass();
+                Stamp readStamp = wordTypes().getKlassPointerStamp();
                 AddressNode address = makeAddress(b, args[0], args[1]);
                 LocationIdentity location;
                 if (args.length == 2) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -69,6 +69,10 @@
         return input.graph().unique(new CompressionNode(CompressionOp.Compress, input, encoding));
     }
 
+    public static CompressionNode compressNoUnique(ValueNode input, CompressEncoding encoding) {
+        return new CompressionNode(CompressionOp.Compress, input, encoding);
+    }
+
     public static CompressionNode uncompress(ValueNode input, CompressEncoding encoding) {
         return input.graph().unique(new CompressionNode(CompressionOp.Uncompress, input, encoding));
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -53,7 +53,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        AllocatableValue obj = gen.getLIRGeneratorTool().newVariable(LIRKind.derivedReference(gen.getLIRGeneratorTool().target().wordKind));
+        AllocatableValue obj = gen.getLIRGeneratorTool().newVariable(LIRKind.unknownReference(gen.getLIRGeneratorTool().target().wordKind));
         gen.getLIRGeneratorTool().emitMove(obj, gen.operand(object));
         gen.setResult(this, obj);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/KlassPointerStamp.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/KlassPointerStamp.java	Tue Jul 21 16:17:54 2015 +0200
@@ -33,34 +33,23 @@
 
 public final class KlassPointerStamp extends MetaspacePointerStamp {
 
-    private static final KlassPointerStamp KLASS = new KlassPointerStamp(false, false);
-
-    private static final KlassPointerStamp KLASS_NON_NULL = new KlassPointerStamp(true, false);
-
-    private static final KlassPointerStamp KLASS_ALWAYS_NULL = new KlassPointerStamp(false, true);
-
     private final CompressEncoding encoding;
 
-    public static KlassPointerStamp klass() {
-        return KLASS;
+    private final Kind kind;
+
+    public KlassPointerStamp(boolean nonNull, boolean alwaysNull, Kind kind) {
+        this(nonNull, alwaysNull, null, kind);
     }
 
-    public static KlassPointerStamp klassNonNull() {
-        return KLASS_NON_NULL;
-    }
-
-    private KlassPointerStamp(boolean nonNull, boolean alwaysNull) {
-        this(nonNull, alwaysNull, null);
-    }
-
-    private KlassPointerStamp(boolean nonNull, boolean alwaysNull, CompressEncoding encoding) {
+    private KlassPointerStamp(boolean nonNull, boolean alwaysNull, CompressEncoding encoding, Kind kind) {
         super(nonNull, alwaysNull);
         this.encoding = encoding;
+        this.kind = kind;
     }
 
     @Override
     protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) {
-        return new KlassPointerStamp(newNonNull, newAlwaysNull, encoding);
+        return new KlassPointerStamp(newNonNull, newAlwaysNull, encoding, kind);
     }
 
     @Override
@@ -79,23 +68,20 @@
     public Stamp constant(Constant c, MetaAccessProvider meta) {
         if (isCompressed()) {
             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
-                return new KlassPointerStamp(false, true, encoding);
+                return new KlassPointerStamp(false, true, encoding, kind);
             }
         } else {
             if (JavaConstant.NULL_POINTER.equals(c)) {
-                return KLASS_ALWAYS_NULL;
+                return new KlassPointerStamp(false, true, encoding, kind);
             }
         }
 
         assert c instanceof HotSpotMetaspaceConstant;
+        assert ((HotSpotMetaspaceConstant) c).isCompressed() == isCompressed();
         if (nonNull()) {
             return this;
         }
-        if (isCompressed()) {
-            return new KlassPointerStamp(true, false, encoding);
-        } else {
-            return KLASS_NON_NULL;
-        }
+        return new KlassPointerStamp(true, false, encoding, kind);
     }
 
     @Override
@@ -126,12 +112,12 @@
 
     public KlassPointerStamp compressed(CompressEncoding newEncoding) {
         assert !isCompressed();
-        return new KlassPointerStamp(nonNull(), alwaysNull(), newEncoding);
+        return new KlassPointerStamp(nonNull(), alwaysNull(), newEncoding, Kind.Int);
     }
 
     public KlassPointerStamp uncompressed() {
         assert isCompressed();
-        return new KlassPointerStamp(nonNull(), alwaysNull());
+        return new KlassPointerStamp(nonNull(), alwaysNull(), Kind.Long);
     }
 
     @Override
@@ -176,4 +162,9 @@
         }
         return ret.toString();
     }
+
+    @Override
+    public Kind getStackKind() {
+        return isCompressed() ? Kind.Int : Kind.Long;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Tue Jul 21 16:17:54 2015 +0200
@@ -70,7 +70,7 @@
                 Stamp stamp = StampFactory.exactNonNull(metaAccess.lookupJavaType(Class.class));
 
                 if (type instanceof HotSpotResolvedObjectType) {
-                    ConstantNode klass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) type).klass(), metaAccess, graph);
+                    ConstantNode klass = ConstantNode.forConstant(context.getStampProvider().createHubStamp(true), ((HotSpotResolvedObjectType) type).klass(), metaAccess, graph);
                     AddressNode address = graph.unique(new OffsetAddressNode(klass, ConstantNode.forLong(classMirrorOffset, graph)));
                     ValueNode read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_LOCATION, null, stamp));
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -48,14 +47,16 @@
 public final class ClassGetHubNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, ConvertNode {
     public static final NodeClass<ClassGetHubNode> TYPE = NodeClass.create(ClassGetHubNode.class);
     @Input protected ValueNode clazz;
+    StampProvider stampProvider;
 
-    public ClassGetHubNode(ValueNode clazz) {
-        this(clazz, null);
+    public ClassGetHubNode(@InjectedNodeParameter StampProvider stampProvider, ValueNode clazz) {
+        this(stampProvider, clazz, null);
     }
 
-    public ClassGetHubNode(ValueNode clazz, ValueNode guard) {
-        super(TYPE, KlassPointerStamp.klass(), (GuardingNode) guard);
+    public ClassGetHubNode(@InjectedNodeParameter StampProvider stampProvider, ValueNode clazz, ValueNode guard) {
+        super(TYPE, stampProvider.createHubStamp(false), (GuardingNode) guard);
         this.clazz = clazz;
+        this.stampProvider = stampProvider;
     }
 
     @Override
@@ -78,7 +79,7 @@
             }
             if (clazz instanceof GetClassNode) {
                 GetClassNode getClass = (GetClassNode) clazz;
-                return new LoadHubNode(KlassPointerStamp.klassNonNull(), getClass.getObject(), null);
+                return new LoadHubNode(stampProvider, getClass.getObject(), null);
             }
             if (clazz instanceof HubGetClassNode) {
                 // replace _klass._java_mirror._klass -> _klass
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CompilerToVMImplSubstitutions.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CompilerToVMImplSubstitutions.java	Tue Jul 21 16:17:54 2015 +0200
@@ -25,6 +25,7 @@
 import jdk.internal.jvmci.hotspot.*;
 
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -35,6 +36,6 @@
 
     @MethodSubstitution(isStatic = false)
     public static Class<?> getJavaMirror(@SuppressWarnings("unused") CompilerToVMImpl impl, long metaspaceklass) {
-        return HotSpotClassSubstitutions.readJavaMirror(Word.unsigned(metaspaceklass));
+        return HotSpotClassSubstitutions.readJavaMirror(KlassPointer.fromWord(Word.unsigned(metaspaceklass)));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ConstantPoolSubstitutions.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,77 @@
+/*
+ * 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.replacements;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.word.*;
+
+import sun.reflect.*;
+
+/**
+ * Substitutions for {@link sun.reflect.ConstantPool} methods.
+ */
+@ClassSubstitution(sun.reflect.ConstantPool.class)
+public class ConstantPoolSubstitutions {
+
+    /**
+     * Get the metaspace {@code ConstantPool} pointer for the given holder class.
+     *
+     * @param constantPoolOop the holder class as {@link Object}
+     * @return a metaspace {@code ConstantPool} pointer
+     */
+    private static Word metaspaceConstantPool(Object constantPoolOop) {
+        // ConstantPool.constantPoolOop is in fact the holder class.
+        Class<?> constantPoolHolder = (Class<?>) constantPoolOop;
+        KlassPointer klass = ClassGetHubNode.readClass(constantPoolHolder);
+        return klass.readWord(instanceKlassConstantsOffset(), INSTANCE_KLASS_CONSTANTS);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    private static int getSize0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop) {
+        return metaspaceConstantPool(constantPoolOop).readInt(constantPoolLengthOffset());
+    }
+
+    @MethodSubstitution(isStatic = false)
+    private static int getIntAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) {
+        return metaspaceConstantPool(constantPoolOop).readInt(constantPoolSize() + index * wordSize());
+    }
+
+    @MethodSubstitution(isStatic = false)
+    private static long getLongAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) {
+        return metaspaceConstantPool(constantPoolOop).readLong(constantPoolSize() + index * wordSize());
+    }
+
+    @MethodSubstitution(isStatic = false)
+    private static float getFloatAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) {
+        return metaspaceConstantPool(constantPoolOop).readFloat(constantPoolSize() + index * wordSize());
+    }
+
+    @MethodSubstitution(isStatic = false)
+    private static double getDoubleAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) {
+        return metaspaceConstantPool(constantPoolOop).readDouble(constantPoolSize() + index * wordSize());
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java	Tue Jul 21 16:17:54 2015 +0200
@@ -28,7 +28,6 @@
 
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.word.*;
 
 // JaCoCo Exclude
 
@@ -81,8 +80,8 @@
                 if (klassIsArray(klass)) {
                     return Object.class;
                 } else {
-                    Word superKlass = klass.readWord(klassSuperKlassOffset(), KLASS_SUPER_KLASS_LOCATION);
-                    if (superKlass.equal(0)) {
+                    KlassPointer superKlass = klass.readKlassPointer(klassSuperKlassOffset(), KLASS_SUPER_KLASS_LOCATION);
+                    if (superKlass.isNull()) {
                         return null;
                     } else {
                         return readJavaMirror(superKlass);
@@ -95,7 +94,7 @@
         return null;
     }
 
-    public static Class<?> readJavaMirror(Word klass) {
+    public static Class<?> readJavaMirror(KlassPointer klass) {
         return PiNode.asNonNullClass(klass.readObject(classMirrorOffset(), CLASS_MIRROR_LOCATION));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Jul 21 16:17:54 2015 +0200
@@ -22,22 +22,29 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import jdk.internal.jvmci.code.*;
-import jdk.internal.jvmci.common.*;
-import jdk.internal.jvmci.hotspot.*;
-import jdk.internal.jvmci.meta.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
 import static jdk.internal.jvmci.common.UnsafeAccess.*;
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.common.*;
+import jdk.internal.jvmci.hotspot.*;
+import jdk.internal.jvmci.meta.Assumptions.AssumptionResult;
+import jdk.internal.jvmci.meta.*;
 
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
+import com.oracle.graal.nodes.memory.address.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
@@ -49,6 +56,60 @@
  */
 public class HotSpotReplacementsUtil {
 
+    abstract static class HotSpotOptimizingLocationIdentity extends NamedLocationIdentity implements CanonicalizableLocation {
+
+        HotSpotOptimizingLocationIdentity(String name) {
+            super(name, true);
+        }
+
+        @Override
+        public abstract ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool);
+
+        protected ValueNode findReadHub(ValueNode object) {
+            ValueNode base = object;
+            if (base instanceof CompressionNode) {
+                base = ((CompressionNode) base).getValue();
+            }
+            if (base instanceof Access) {
+                Access access = (Access) base;
+                if (access.getLocationIdentity().equals(HUB_LOCATION)) {
+                    AddressNode address = access.getAddress();
+                    if (address instanceof OffsetAddressNode) {
+                        OffsetAddressNode offset = (OffsetAddressNode) address;
+                        return offset.getBase();
+                    }
+                }
+            } else if (base instanceof LoadHubNode) {
+                LoadHubNode loadhub = (LoadHubNode) base;
+                return loadhub.getValue();
+            }
+            return null;
+        }
+
+        /**
+         * Fold reads that convert from Class -> Hub -> Class or vice versa.
+         *
+         * @param read
+         * @param object
+         * @param otherLocation
+         * @return an earlier read or the original {@code read}
+         */
+        protected static ValueNode foldIndirection(ValueNode read, ValueNode object, LocationIdentity otherLocation) {
+            if (object instanceof Access) {
+                Access access = (Access) object;
+                if (access.getLocationIdentity().equals(otherLocation)) {
+                    AddressNode address = access.getAddress();
+                    if (address instanceof OffsetAddressNode) {
+                        OffsetAddressNode offset = (OffsetAddressNode) address;
+                        assert offset.getBase().stamp().isCompatible(read.stamp());
+                        return offset.getBase();
+                    }
+                }
+            }
+            return read;
+        }
+    }
+
     @Fold
     public static HotSpotVMConfig config() {
         return runtime().getConfig();
@@ -296,7 +357,23 @@
         return config().jvmAccWrittenFlags;
     }
 
-    public static final LocationIdentity KLASS_LAYOUT_HELPER_LOCATION = NamedLocationIdentity.immutable("Klass::_layout_helper");
+    public static final LocationIdentity KLASS_LAYOUT_HELPER_LOCATION = new HotSpotOptimizingLocationIdentity("Klass::_layout_helper") {
+        @Override
+        public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
+            ValueNode javaObject = findReadHub(object);
+            if (javaObject != null) {
+                if (javaObject.stamp() instanceof ObjectStamp) {
+                    ObjectStamp stamp = (ObjectStamp) javaObject.stamp();
+                    HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) stamp.javaType(tool.getMetaAccess());
+                    if (type.isArray() && !type.getComponentType().isPrimitive()) {
+                        int layout = ((HotSpotResolvedObjectTypeImpl) type).layoutHelper();
+                        return ConstantNode.forInt(layout);
+                    }
+                }
+            }
+            return read;
+        }
+    };
 
     @Fold
     public static int klassLayoutHelperOffset() {
@@ -356,7 +433,20 @@
 
     public static final LocationIdentity HUB_WRITE_LOCATION = NamedLocationIdentity.mutable("Hub:write");
 
-    public static final LocationIdentity HUB_LOCATION = NamedLocationIdentity.immutable("Hub");
+    public static final LocationIdentity HUB_LOCATION = new HotSpotOptimizingLocationIdentity("Hub") {
+        @Override
+        public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
+            ResolvedJavaType constantType = LoadHubNode.findSynonymType(read.graph(), tool.getMetaAccess(), object);
+            if (constantType != null) {
+                if (config().useCompressedClassPointers) {
+                    return ConstantNode.forConstant(read.stamp(), ((HotSpotMetaspaceConstant) constantType.getObjectHub()).compress(config().getKlassEncoding()), tool.getMetaAccess());
+                } else {
+                    return ConstantNode.forConstant(read.stamp(), constantType.getObjectHub(), tool.getMetaAccess());
+                }
+            }
+            return read;
+        }
+    };
 
     @Fold
     private static int hubOffset() {
@@ -578,6 +668,11 @@
         return loadWordFromObjectIntrinsic(object, offset, getWordKind(), identity);
     }
 
+    public static KlassPointer loadKlassFromObject(Object object, int offset, LocationIdentity identity) {
+        ReplacementsUtil.staticAssert(offset != hubOffset(), "Use loadHubIntrinsic instead of loadWordFromObject");
+        return loadKlassFromObjectIntrinsic(object, offset, getWordKind(), identity);
+    }
+
     /**
      * Reads the value of a given register.
      *
@@ -597,6 +692,9 @@
     @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true)
     private static native Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter Kind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity);
 
+    @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true)
+    private static native KlassPointer loadKlassFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter Kind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity);
+
     @NodeIntrinsic(value = LoadHubNode.class)
     public static native KlassPointer loadHubIntrinsic(Object object, GuardingNode anchor);
 
@@ -620,6 +718,13 @@
         return config().instanceKlassStateFullyInitialized;
     }
 
+    public static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
+
+    @Fold
+    public static int instanceKlassConstantsOffset() {
+        return config().instanceKlassConstantsOffset;
+    }
+
     /**
      *
      * @param hub the hub of an InstanceKlass
@@ -640,14 +745,24 @@
         return config().klassModifierFlagsOffset;
     }
 
-    public static final LocationIdentity CLASS_KLASS_LOCATION = NamedLocationIdentity.immutable("Class._klass");
+    public static final LocationIdentity CLASS_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("Class._klass") {
+        @Override
+        public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
+            return foldIndirection(read, object, CLASS_MIRROR_LOCATION);
+        }
+    };
 
     @Fold
     public static int klassOffset() {
         return config().klassOffset;
     }
 
-    public static final LocationIdentity CLASS_ARRAY_KLASS_LOCATION = NamedLocationIdentity.mutable("Class._array_klass");
+    public static final LocationIdentity CLASS_ARRAY_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("Class._array_klass") {
+        @Override
+        public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
+            return foldIndirection(read, object, ARRAY_KLASS_COMPONENT_MIRROR);
+        }
+    };
 
     @Fold
     public static int arrayKlassOffset() {
@@ -661,6 +776,21 @@
         return config().classMirrorOffset;
     }
 
+    @Fold
+    public static int constantPoolSize() {
+        return config().constantPoolSize;
+    }
+
+    @Fold
+    public static int constantPoolHolderOffset() {
+        return config().constantPoolHolderOffset;
+    }
+
+    @Fold
+    public static int constantPoolLengthOffset() {
+        return config().constantPoolLengthOffset;
+    }
+
     public static final LocationIdentity HEAP_TOP_LOCATION = NamedLocationIdentity.mutable("HeapTop");
 
     @Fold
@@ -824,7 +954,26 @@
         }
     }
 
-    public static final LocationIdentity OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION = NamedLocationIdentity.immutable("ObjArrayKlass::_element_klass");
+    public static final LocationIdentity OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("ObjArrayKlass::_element_klass") {
+        @Override
+        public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
+            ValueNode javaObject = findReadHub(object);
+            if (javaObject != null) {
+                ResolvedJavaType type = StampTool.typeOrNull(javaObject);
+                if (type != null && type.isArray()) {
+                    ResolvedJavaType element = type.getComponentType();
+                    if (element != null && !element.isPrimitive() && !element.getElementalType().isInterface()) {
+                        AssumptionResult<ResolvedJavaType> leafType = element.findLeafConcreteSubtype();
+                        if (leafType != null) {
+                            object.graph().getAssumptions().record(leafType);
+                            return ConstantNode.forConstant(read.stamp(), leafType.getResult().getObjectHub(), tool.getMetaAccess());
+                        }
+                    }
+                }
+            }
+            return read;
+        }
+    };
 
     @Fold
     public static int arrayClassElementOffset() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue Jul 21 16:17:54 2015 +0200
@@ -27,6 +27,7 @@
 import jdk.internal.jvmci.meta.*;
 import jdk.internal.jvmci.service.*;
 import sun.reflect.*;
+import sun.reflect.ConstantPool;
 
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.spi.*;
@@ -39,6 +40,7 @@
         replacements.registerSubstitutions(System.class, SystemSubstitutions.class);
         replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class);
         replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class);
+        replacements.registerSubstitutions(ConstantPool.class, ConstantPoolSubstitutions.class);
         replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Tue Jul 21 16:17:54 2015 +0200
@@ -37,7 +37,6 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.Hints;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
@@ -229,38 +228,39 @@
 
         @Override
         protected Arguments makeArguments(InstanceOfUsageReplacer replacer, LoweringTool tool) {
+            Stamp hubStamp = tool.getStampProvider().createHubStamp(true);
             if (replacer.instanceOf instanceof InstanceOfNode) {
                 InstanceOfNode instanceOf = (InstanceOfNode) replacer.instanceOf;
                 ValueNode object = instanceOf.getValue();
                 Assumptions assumptions = instanceOf.graph().getAssumptions();
                 TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), assumptions, TypeCheckMinProfileHitProbability.getValue(), TypeCheckMaxHints.getValue());
                 final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type();
-                ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), instanceOf.graph());
+                ConstantNode hub = ConstantNode.forConstant(hubStamp, type.klass(), providers.getMetaAccess(), instanceOf.graph());
 
                 Arguments args;
 
                 StructuredGraph graph = instanceOf.graph();
                 if (hintInfo.hintHitProbability >= 1.0 && hintInfo.exact == null) {
-                    Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph);
+                    Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph, tool);
                     args = new Arguments(instanceofWithProfile, graph.getGuardsStage(), tool.getLoweringStage());
                     args.add("object", object);
-                    args.addVarargs("hints", KlassPointer.class, KlassPointerStamp.klassNonNull(), hints.hubs);
+                    args.addVarargs("hints", KlassPointer.class, hubStamp, hints.hubs);
                     args.addVarargs("hintIsPositive", boolean.class, StampFactory.forKind(Kind.Boolean), hints.isPositive);
                 } else if (hintInfo.exact != null) {
                     args = new Arguments(instanceofExact, graph.getGuardsStage(), tool.getLoweringStage());
                     args.add("object", object);
-                    args.add("exactHub", ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) hintInfo.exact).klass(), providers.getMetaAccess(), graph));
+                    args.add("exactHub", ConstantNode.forConstant(hubStamp, ((HotSpotResolvedObjectType) hintInfo.exact).klass(), providers.getMetaAccess(), graph));
                 } else if (type.isPrimaryType()) {
                     args = new Arguments(instanceofPrimary, graph.getGuardsStage(), tool.getLoweringStage());
                     args.add("hub", hub);
                     args.add("object", object);
                     args.addConst("superCheckOffset", type.superCheckOffset());
                 } else {
-                    Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph);
+                    Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph, tool);
                     args = new Arguments(instanceofSecondary, graph.getGuardsStage(), tool.getLoweringStage());
                     args.add("hub", hub);
                     args.add("object", object);
-                    args.addVarargs("hints", KlassPointer.class, KlassPointerStamp.klassNonNull(), hints.hubs);
+                    args.addVarargs("hints", KlassPointer.class, hubStamp, hints.hubs);
                     args.addVarargs("hintIsPositive", boolean.class, StampFactory.forKind(Kind.Boolean), hints.isPositive);
                 }
                 args.add("trueValue", replacer.trueValue);
@@ -275,7 +275,7 @@
                 ValueNode object = typeCheck.getValue();
                 Arguments args = new Arguments(instanceofExact, typeCheck.graph().getGuardsStage(), tool.getLoweringStage());
                 args.add("object", object);
-                args.add("exactHub", ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) typeCheck.type()).klass(), providers.getMetaAccess(), typeCheck.graph()));
+                args.add("exactHub", ConstantNode.forConstant(hubStamp, ((HotSpotResolvedObjectType) typeCheck.type()).klass(), providers.getMetaAccess(), typeCheck.graph()));
                 args.add("trueValue", replacer.trueValue);
                 args.add("falseValue", replacer.falseValue);
                 return args;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Jul 21 16:17:54 2015 +0200
@@ -47,7 +47,6 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.debug.*;
@@ -197,7 +196,8 @@
     @Snippet
     public static Object allocateArray(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
                     @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext) {
-        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false);
+        Object result = allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false);
+        return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
     }
 
     private static Object allocateArrayImpl(KlassPointer hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents,
@@ -219,7 +219,7 @@
             result = newArray(HotSpotBackend.NEW_ARRAY, hub, length);
         }
         profileAllocation("array", allocationSize, typeContext);
-        return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
+        return result;
     }
 
     @NodeIntrinsic(ForeignCallNode.class)
@@ -240,7 +240,12 @@
 
     @Snippet
     public static Object allocateArrayDynamic(Class<?> elementType, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
-                    @ConstantParameter Kind knownElementKind) {
+                    @ConstantParameter Kind knownElementKind, @ConstantParameter int knownLayoutHelper, Word prototypeMarkWord) {
+        Object result = allocateArrayDynamicImpl(elementType, length, fillContents, threadRegister, knownElementKind, knownLayoutHelper, prototypeMarkWord);
+        return result;
+    }
+
+    private static Object allocateArrayDynamicImpl(Class<?> elementType, int length, boolean fillContents, Register threadRegister, Kind knownElementKind, int knownLayoutHelper, Word prototypeMarkWord) {
         /*
          * We only need the dynamic check for void when we have no static information from
          * knownElementKind.
@@ -250,13 +255,11 @@
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
 
-        Word hub = loadWordFromObject(elementType, arrayKlassOffset(), CLASS_ARRAY_KLASS_LOCATION);
-        if (probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, hub.equal(Word.zero()) || !belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH))) {
-            return dynamicNewArrayStub(DYNAMIC_NEW_ARRAY, elementType, length);
+        KlassPointer klass = loadKlassFromObject(elementType, arrayKlassOffset(), CLASS_ARRAY_KLASS_LOCATION);
+        if (probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, klass.isNull() || length < 0)) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
-
-        KlassPointer klass = KlassPointer.fromWord(hub);
-        int layoutHelper = readLayoutHelper(klass);
+        int layoutHelper = knownElementKind != Kind.Illegal ? knownLayoutHelper : readLayoutHelper(klass);
         //@formatter:off
         // from src/share/vm/oops/klass.hpp:
         //
@@ -272,9 +275,9 @@
 
         int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
-        Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
 
-        return allocateArrayImpl(klass, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type", true);
+        Object result = allocateArrayImpl(klass, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type", true);
+        return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
     }
 
     /**
@@ -305,15 +308,19 @@
      *
      * @param size number of bytes to zero
      * @param memory beginning of object which is being zeroed
-     * @param constantSize is @ size} known to be constant in the snippet
+     * @param constantSize is {@code size} known to be constant in the snippet
      * @param startOffset offset to begin zeroing. May not be word aligned.
      * @param manualUnroll maximally unroll zeroing
      */
     private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) {
+        fillMemory(0, size, memory, constantSize, startOffset, manualUnroll, useSnippetCounters);
+    }
+
+    private static void fillMemory(long value, int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) {
         ReplacementsUtil.runtimeAssert((size & 0x7) == 0, "unaligned object size");
         int offset = startOffset;
         if ((offset & 0x7) != 0) {
-            memory.writeInt(offset, 0, INIT_LOCATION);
+            memory.writeInt(offset, (int) value, INIT_LOCATION);
             offset += 4;
         }
         ReplacementsUtil.runtimeAssert((offset & 0x7) == 0, "unaligned offset");
@@ -330,7 +337,7 @@
                 if (offset == size) {
                     break;
                 }
-                memory.initializeLong(offset, 0, INIT_LOCATION);
+                memory.initializeLong(offset, value, INIT_LOCATION);
             }
         } else {
             // Use Word instead of int to avoid extension to long in generated code
@@ -346,12 +353,26 @@
                 }
             }
             for (; off.rawValue() < size; off = off.add(8)) {
-                memory.initializeLong(off, 0, INIT_LOCATION);
+                memory.initializeLong(off, value, INIT_LOCATION);
             }
         }
     }
 
     /**
+     * Fill uninitialized memory with garbage value in a newly allocated object, unrolling as
+     * necessary and ensuring that stores are aligned.
+     *
+     * @param size number of bytes to zero
+     * @param memory beginning of object which is being zeroed
+     * @param constantSize is {@code  size} known to be constant in the snippet
+     * @param startOffset offset to begin zeroing. May not be word aligned.
+     * @param manualUnroll maximally unroll zeroing
+     */
+    private static void fillWithGarbage(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) {
+        fillMemory(0xfefefefefefefefeL, size, memory, constantSize, startOffset, manualUnroll, useSnippetCounters);
+    }
+
+    /**
      * Formats some allocated memory with an object header and zeroes out the rest. Disables asserts
      * since they can't be compiled in stubs.
      */
@@ -367,6 +388,8 @@
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
             zeroMemory(size, memory, constantSize, instanceHeaderSize(), false, useSnippetCounters);
+        } else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
+            fillWithGarbage(size, memory, constantSize, instanceHeaderSize(), false, useSnippetCounters);
         }
         return memory.toObject();
     }
@@ -396,6 +419,8 @@
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
             zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, useSnippetCounters);
+        } else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
+            fillWithGarbage(allocationSize, memory, false, headerSize, maybeUnroll, useSnippetCounters);
         }
         return memory.toObject();
     }
@@ -422,7 +447,7 @@
             StructuredGraph graph = newInstanceNode.graph();
             HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass();
             assert !type.isArray();
-            ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), graph);
+            ConstantNode hub = ConstantNode.forConstant(tool.getStampProvider().createHubStamp(true), type.klass(), providers.getMetaAccess(), graph);
             int size = instanceSize(type);
 
             Arguments args = new Arguments(allocateInstance, graph.getGuardsStage(), tool.getLoweringStage());
@@ -447,7 +472,7 @@
             ResolvedJavaType elementType = newArrayNode.elementType();
             HotSpotResolvedObjectType arrayType = (HotSpotResolvedObjectType) elementType.getArrayClass();
             Kind elementKind = elementType.getKind();
-            ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), arrayType.klass(), providers.getMetaAccess(), graph);
+            ConstantNode hub = ConstantNode.forConstant(tool.getStampProvider().createHubStamp(true), arrayType.klass(), providers.getMetaAccess(), graph);
             final int headerSize = runtime.getJVMCIRuntime().getArrayBaseOffset(elementKind);
             HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
             int log2ElementSize = CodeUtil.log2(lowerer.arrayScalingFactor(elementKind));
@@ -456,6 +481,7 @@
             args.add("hub", hub);
             ValueNode length = newArrayNode.length();
             args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
+            assert arrayType.prototypeMarkWord() == lookupArrayClass(tool, Kind.Object).prototypeMarkWord() : "all array types are assumed to have the same prototypeMarkWord";
             args.add("prototypeMarkWord", arrayType.prototypeMarkWord());
             args.addConst("headerSize", headerSize);
             args.addConst("log2ElementSize", log2ElementSize);
@@ -492,11 +518,20 @@
              * parameters cannot be null.
              */
             args.addConst("knownElementKind", newArrayNode.getKnownElementKind() == null ? Kind.Illegal : newArrayNode.getKnownElementKind());
-
+            if (newArrayNode.getKnownElementKind() != null) {
+                args.addConst("knownLayoutHelper", lookupArrayClass(tool, newArrayNode.getKnownElementKind()).layoutHelper());
+            } else {
+                args.addConst("knownLayoutHelper", 0);
+            }
+            args.add("prototypeMarkWord", lookupArrayClass(tool, Kind.Object).prototypeMarkWord());
             SnippetTemplate template = template(args);
             template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
         }
 
+        private static HotSpotResolvedObjectType lookupArrayClass(LoweringTool tool, Kind kind) {
+            return (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(kind == Kind.Object ? Object.class : kind.toJavaClass()).getArrayClass();
+        }
+
         public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) {
             StructuredGraph graph = newmultiarrayNode.graph();
             int rank = newmultiarrayNode.dimensionCount();
@@ -505,7 +540,7 @@
                 dims[i] = newmultiarrayNode.dimension(i);
             }
             HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newmultiarrayNode.type();
-            ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), graph);
+            ConstantNode hub = ConstantNode.forConstant(tool.getStampProvider().createHubStamp(true), type.klass(), providers.getMetaAccess(), graph);
 
             Arguments args = new Arguments(newmultiarray, graph.getGuardsStage(), tool.getLoweringStage());
             args.add("hub", hub);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Tue Jul 21 16:17:54 2015 +0200
@@ -115,7 +115,8 @@
 
     @Snippet(removeAllFrameStates = true)
     public static Object[] objectArrayClone(Object[] src) {
-        Object[] result = (Object[]) DynamicNewArrayNode.newUninitializedArray(GraalDirectives.guardingNonNull(src.getClass().getComponentType()), src.length, Kind.Object);
+        /* 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);
         ArrayCopyCallNode.disjointUninitializedArraycopy(src, 0, result, 0, src.length, Kind.Object);
         return result;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java	Tue Jul 21 16:17:54 2015 +0200
@@ -32,9 +32,9 @@
 import jdk.internal.jvmci.hotspot.*;
 import jdk.internal.jvmci.meta.*;
 
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.word.*;
 
@@ -122,13 +122,13 @@
         }
     }
 
-    static Hints createHints(TypeCheckHints hints, MetaAccessProvider metaAccess, boolean positiveOnly, StructuredGraph graph) {
+    static Hints createHints(TypeCheckHints hints, MetaAccessProvider metaAccess, boolean positiveOnly, StructuredGraph graph, LoweringTool tool) {
         ConstantNode[] hubs = new ConstantNode[hints.hints.length];
         boolean[] isPositive = new boolean[hints.hints.length];
         int index = 0;
         for (int i = 0; i < hubs.length; i++) {
             if (!positiveOnly || hints.hints[i].positive) {
-                hubs[index] = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) hints.hints[i].type).klass(), metaAccess, graph);
+                hubs[index] = ConstantNode.forConstant(tool.getStampProvider().createHubStamp(true), ((HotSpotResolvedObjectType) hints.hints[i].type).klass(), metaAccess, graph);
                 isPositive[index] = hints.hints[i].positive;
                 index++;
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -40,20 +40,30 @@
 
     private final SnippetTemplate.SnippetInfo snippet;
 
-    public ArrayCopySlowPathNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, SnippetTemplate.SnippetInfo snippet) {
+    /**
+     * Extra context for the slow path snippet.
+     */
+    private final Object argument;
+
+    public ArrayCopySlowPathNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, SnippetTemplate.SnippetInfo snippet, Object argument) {
         super(TYPE, src, srcPos, dest, destPos, length, elementKind, BytecodeFrame.INVALID_FRAMESTATE_BCI);
         assert StampTool.isPointerNonNull(src) && StampTool.isPointerNonNull(dest) : "must have been null checked";
         this.snippet = snippet;
+        this.argument = argument;
     }
 
     @NodeIntrinsic
     public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantNodeParameter Kind elementKind,
-                    @ConstantNodeParameter SnippetTemplate.SnippetInfo snippet);
+                    @ConstantNodeParameter SnippetTemplate.SnippetInfo snippet, @ConstantNodeParameter Object argument);
 
     public SnippetTemplate.SnippetInfo getSnippet() {
         return snippet;
     }
 
+    public Object getArgument() {
+        return argument;
+    }
+
     @Override
     public LocationIdentity getLocationIdentity() {
         if (elementKind != null) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Tue Jul 21 16:17:54 2015 +0200
@@ -38,7 +38,6 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -166,7 +165,8 @@
      * underlying type is really an array type.
      */
     @Snippet
-    public static void arraycopySlowPathIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Kind elementKind, @ConstantParameter SnippetInfo slowPath) {
+    public static void arraycopySlowPathIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Kind elementKind, @ConstantParameter SnippetInfo slowPath,
+                    @ConstantParameter Object slowPathArgument) {
         Object nonNullSrc = GraalDirectives.guardingNonNull(src);
         Object nonNullDest = GraalDirectives.guardingNonNull(dest);
         KlassPointer srcHub = loadHub(nonNullSrc);
@@ -180,7 +180,24 @@
             nonZeroLengthDynamicCounter.inc();
             nonZeroLengthDynamicCopiedCounter.add(length);
         }
-        ArrayCopySlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind, slowPath);
+        ArrayCopySlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind, slowPath, slowPathArgument);
+    }
+
+    /**
+     * Snippet for unrolled arraycopy.
+     */
+    @Snippet
+    public static void arraycopyUnrolledIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter int unrolledLength, @ConstantParameter Kind elementKind) {
+        Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+        Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
+        if (length == 0) {
+            zeroLengthDynamicCounter.inc();
+        } else {
+            nonZeroLengthDynamicCounter.inc();
+            nonZeroLengthDynamicCopiedCounter.add(length);
+        }
+        ArrayCopyUnrollNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, unrolledLength, elementKind);
     }
 
     @Snippet
@@ -357,6 +374,7 @@
         private final SnippetInfo arraycopyGenericSnippet = snippet("arraycopyGeneric");
 
         private final SnippetInfo arraycopySlowPathIntrinsicSnippet = snippet("arraycopySlowPathIntrinsic");
+        private final SnippetInfo arraycopyUnrolledIntrinsicSnippet = snippet("arraycopyUnrolledIntrinsic");
         private final SnippetInfo arraycopyExactIntrinsicSnippet = snippet("arraycopyExactIntrinsic");
         private final SnippetInfo arraycopyZeroLengthIntrinsicSnippet = snippet("arraycopyZeroLengthIntrinsic");
         private final SnippetInfo arraycopyPredictedExactIntrinsicSnippet = snippet("arraycopyPredictedExactIntrinsic");
@@ -414,14 +432,14 @@
             Kind componentKind = selectComponentKind(arraycopy);
             SnippetInfo snippetInfo = null;
             SnippetInfo slowPathSnippetInfo = null;
+            Object slowPathArgument = null;
 
             if (arraycopy.getLength().isConstant() && arraycopy.getLength().asJavaConstant().asLong() == 0) {
                 snippetInfo = arraycopyZeroLengthIntrinsicSnippet;
             } else if (arraycopy.isExact()) {
                 snippetInfo = arraycopyExactIntrinsicSnippet;
                 if (shouldUnroll(arraycopy.getLength())) {
-                    snippetInfo = arraycopySlowPathIntrinsicSnippet;
-                    slowPathSnippetInfo = arraycopyUnrolledWorkSnippet;
+                    snippetInfo = arraycopyUnrolledIntrinsicSnippet;
                 }
             } else {
                 if (componentKind == Kind.Object) {
@@ -432,6 +450,7 @@
                     if (srcComponentType != null && destComponentType != null && !srcComponentType.isPrimitive() && !destComponentType.isPrimitive()) {
                         snippetInfo = arraycopySlowPathIntrinsicSnippet;
                         slowPathSnippetInfo = checkcastArraycopyWorkSnippet;
+                        slowPathArgument = LocationIdentity.any();
                         /*
                          * Because this snippet has to use Sysytem.arraycopy as a slow path, we must
                          * pretend to kill any() so clear the componentKind.
@@ -451,6 +470,7 @@
                         if (predictedKind == Kind.Object) {
                             snippetInfo = arraycopySlowPathIntrinsicSnippet;
                             slowPathSnippetInfo = arraycopyPredictedObjectWorkSnippet;
+                            slowPathArgument = predictedKind;
                             componentKind = null;
                         } else {
                             snippetInfo = arraycopyPredictedExactIntrinsicSnippet;
@@ -467,9 +487,14 @@
             args.add("dest", arraycopy.getDestination());
             args.add("destPos", arraycopy.getDestinationPosition());
             args.add("length", arraycopy.getLength());
-            if (snippetInfo == arraycopySlowPathIntrinsicSnippet) {
+            if (snippetInfo == arraycopyUnrolledIntrinsicSnippet) {
+                args.addConst("unrolledLength", arraycopy.getLength().asJavaConstant().asInt());
+                args.addConst("elementKind", componentKind != null ? componentKind : Kind.Illegal);
+            } else if (snippetInfo == arraycopySlowPathIntrinsicSnippet) {
                 args.addConst("elementKind", componentKind != null ? componentKind : Kind.Illegal);
                 args.addConst("slowPath", slowPathSnippetInfo);
+                assert slowPathArgument != null;
+                args.addConst("slowPathArgument", slowPathArgument);
             } else if (snippetInfo == arraycopyExactIntrinsicSnippet || snippetInfo == arraycopyPredictedExactIntrinsicSnippet) {
                 assert componentKind != null;
                 args.addConst("elementKind", componentKind);
@@ -492,14 +517,14 @@
             args.add("nonNullDest", arraycopy.getDestination());
             args.add("destPos", arraycopy.getDestinationPosition());
             if (snippetInfo == arraycopyUnrolledWorkSnippet) {
-                args.addConst("length", arraycopy.getLength().asJavaConstant().asInt());
+                args.addConst("length", ((Integer) arraycopy.getArgument()).intValue());
                 args.addConst("elementKind", arraycopy.getElementKind());
             } else {
                 args.add("length", arraycopy.getLength());
             }
             if (snippetInfo == arraycopyPredictedObjectWorkSnippet) {
                 HotSpotResolvedObjectType arrayKlass = (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(Object[].class);
-                ValueNode objectArrayKlass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), arrayKlass.klass(), tool.getMetaAccess(), arraycopy.graph());
+                ValueNode objectArrayKlass = ConstantNode.forConstant(tool.getStampProvider().createHubStamp(true), arrayKlass.klass(), tool.getMetaAccess(), arraycopy.graph());
                 args.add("objectArrayKlass", objectArrayKlass);
                 args.addConst("counter", arraycopyCallCounters.get(Kind.Object));
                 args.addConst("copiedCounter", arraycopyCallCopiedCounters.get(Kind.Object));
@@ -507,6 +532,23 @@
             instantiate(args, arraycopy);
         }
 
+        public void lower(ArrayCopyUnrollNode arraycopy, LoweringTool tool) {
+            StructuredGraph graph = arraycopy.graph();
+            if (!graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                // Can't be lowered yet
+                return;
+            }
+            SnippetInfo snippetInfo = arraycopyUnrolledWorkSnippet;
+            Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("nonNullSrc", arraycopy.getSource());
+            args.add("srcPos", arraycopy.getSourcePosition());
+            args.add("nonNullDest", arraycopy.getDestination());
+            args.add("destPos", arraycopy.getDestinationPosition());
+            args.addConst("length", arraycopy.getUnrollLength());
+            args.addConst("elementKind", arraycopy.getElementKind());
+            template(args).instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args);
+        }
+
         /**
          * Instantiate the snippet template and fix up the FrameState of any Invokes of
          * System.arraycopy and propagate the captured bci in the ArrayCopySlowPathNode.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyUnrollNode.java	Tue Jul 21 16:17:54 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.hotspot.replacements.arraycopy;
+
+import static jdk.internal.jvmci.meta.LocationIdentity.*;
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo
+public class ArrayCopyUnrollNode extends ArrayRangeWriteNode implements MemoryCheckpoint.Single, Lowerable, MemoryAccess {
+
+    public static final NodeClass<ArrayCopyUnrollNode> TYPE = NodeClass.create(ArrayCopyUnrollNode.class);
+
+    @Input protected ValueNode src;
+    @Input protected ValueNode srcPos;
+    @Input protected ValueNode dest;
+    @Input protected ValueNode destPos;
+    @Input protected ValueNode length;
+
+    private Kind elementKind;
+
+    private int unrolledLength;
+
+    @OptionalInput(InputType.Memory) private MemoryNode lastLocationAccess;
+
+    public ArrayCopyUnrollNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, int unrolledLength, Kind elementKind) {
+        super(TYPE, StampFactory.forKind(Kind.Void));
+        this.src = src;
+        this.srcPos = srcPos;
+        this.dest = dest;
+        this.destPos = destPos;
+        this.length = length;
+        this.unrolledLength = unrolledLength;
+        assert elementKind != null && elementKind != Kind.Illegal;
+        this.elementKind = elementKind;
+    }
+
+    public ValueNode getSource() {
+        return src;
+    }
+
+    public ValueNode getSourcePosition() {
+        return srcPos;
+    }
+
+    public ValueNode getDestination() {
+        return dest;
+    }
+
+    public ValueNode getDestinationPosition() {
+        return destPos;
+    }
+
+    @Override
+    public ValueNode getLength() {
+        return length;
+    }
+
+    @Override
+    public ValueNode getArray() {
+        return dest;
+    }
+
+    @Override
+    public ValueNode getIndex() {
+        return destPos;
+    }
+
+    @Override
+    public boolean isObjectArray() {
+        return elementKind == Kind.Object;
+    }
+
+    @Override
+    public boolean isInitialization() {
+        return false;
+    }
+
+    @NodeIntrinsic
+    public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantNodeParameter int unrolledLength, @ConstantNodeParameter Kind elementKind);
+
+    public int getUnrollLength() {
+        return unrolledLength;
+    }
+
+    public Kind getElementKind() {
+        return elementKind;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        if (elementKind != null) {
+            return NamedLocationIdentity.getArrayLocation(elementKind);
+        }
+        return any();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    public void setLastLocationAccess(MemoryNode lla) {
+        updateUsagesInterface(lastLocationAccess, lla);
+        lastLocationAccess = lla;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue Jul 21 16:17:54 2015 +0200
@@ -22,14 +22,14 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
-import jdk.internal.jvmci.code.*;
-import jdk.internal.jvmci.hotspot.*;
-import jdk.internal.jvmci.meta.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 import static jdk.internal.jvmci.hotspot.HotSpotMetaAccessProvider.*;
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.hotspot.*;
+import jdk.internal.jvmci.meta.*;
 
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
@@ -37,7 +37,6 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
@@ -64,7 +63,7 @@
         Object[] args = new Object[count];
         assert checkConstArg(2, "intArrayHub");
         assert checkConstArg(3, "threadRegister");
-        args[2] = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), intArrayType.klass(), null);
+        args[2] = ConstantNode.forConstant(providers.getStampProvider().createHubStamp(true), intArrayType.klass(), null);
         args[3] = providers.getRegisters().getThreadRegister();
         return args;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Jul 21 16:17:54 2015 +0200
@@ -36,7 +36,6 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
@@ -64,7 +63,7 @@
         Object[] args = new Object[count];
         assert checkConstArg(1, "intArrayHub");
         assert checkConstArg(2, "threadRegister");
-        args[1] = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), intArrayType.klass(), null);
+        args[1] = ConstantNode.forConstant(providers.getStampProvider().createHubStamp(true), intArrayType.klass(), null);
         args[2] = providers.getRegisters().getThreadRegister();
         return args;
     }
@@ -187,7 +186,7 @@
                 // an int
                 int tlabFreeSpaceInInts = (int) tlabFreeSpaceInBytes >>> 2;
                 int length = ((alignmentReserveInBytes - headerSize) >>> 2) + tlabFreeSpaceInInts;
-                NewObjectSnippets.formatArray(intArrayHub, -1, length, headerSize, top, intArrayMarkWord, false, false, false);
+                NewObjectSnippets.formatArray(intArrayHub, 0, length, headerSize, top, intArrayMarkWord, false, false, false);
 
                 long allocated = thread.readLong(threadAllocatedBytesOffset(), TLAB_THREAD_ALLOCATED_BYTES_LOCATION);
                 allocated = allocated + top.subtract(readTlabStart(thread)).rawValue();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/HotSpotWordTypes.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/HotSpotWordTypes.java	Tue Jul 21 16:17:54 2015 +0200
@@ -25,7 +25,6 @@
 import jdk.internal.jvmci.meta.*;
 
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -48,11 +47,17 @@
      */
     private final ResolvedJavaType methodPointerType;
 
-    public HotSpotWordTypes(MetaAccessProvider metaAccess, Kind wordKind) {
+    private final Stamp klassPointerStamp;
+
+    private final Stamp methodPointerStamp;
+
+    public HotSpotWordTypes(MetaAccessProvider metaAccess, Kind wordKind, Stamp klassPointerStamp, Stamp methodPointerStamp) {
         super(metaAccess, wordKind);
         this.metaspacePointerType = metaAccess.lookupJavaType(MetaspacePointer.class);
         this.klassPointerType = metaAccess.lookupJavaType(KlassPointer.class);
         this.methodPointerType = metaAccess.lookupJavaType(MethodPointer.class);
+        this.klassPointerStamp = klassPointerStamp;
+        this.methodPointerStamp = methodPointerStamp;
     }
 
     @Override
@@ -74,10 +79,18 @@
     @Override
     public Stamp getWordStamp(ResolvedJavaType type) {
         if (type.equals(klassPointerType)) {
-            return KlassPointerStamp.klass();
+            return klassPointerStamp;
         } else if (type.equals(methodPointerType)) {
-            return MethodPointerStamp.method();
+            return methodPointerStamp;
         }
         return super.getWordStamp(type);
     }
+
+    public Stamp getKlassPointerStamp() {
+        return klassPointerStamp;
+    }
+
+    public Stamp getMethodPointerStamp() {
+        return methodPointerStamp;
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParser.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParser.java	Tue Jul 21 16:17:54 2015 +0200
@@ -1325,7 +1325,7 @@
         // be conservative if information was not recorded (could result in endless
         // recompiles otherwise)
         Invoke invoke;
-        if (graphBuilderConfig.omitAllExceptionEdges() ||
+        if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_NO_EXCEPTION || graphBuilderConfig.omitAllExceptionEdges() ||
                         (!StressInvokeWithExceptionNode.getValue() && optimisticOpts.useExceptionProbability() && profilingInfo != null && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE)) {
             invoke = createInvoke(callTarget, resultType);
         } else {
@@ -1426,6 +1426,8 @@
         return false;
     }
 
+    InlineInfo lastInlineInfo;
+
     private boolean tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod, JavaType returnType) {
         boolean canBeInlined = forceInliningEverything || parsingIntrinsic() || targetMethod.canBeInlined();
         if (!canBeInlined) {
@@ -1437,13 +1439,13 @@
         }
 
         for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
-            InlineInfo inlineInfo = plugin.shouldInlineInvoke(this, targetMethod, args, returnType);
-            if (inlineInfo != null) {
-                if (inlineInfo.getMethodToInline() == null) {
+            lastInlineInfo = plugin.shouldInlineInvoke(this, targetMethod, args, returnType);
+            if (lastInlineInfo != null) {
+                if (lastInlineInfo.getMethodToInline() == null) {
                     /* Do not inline, and do not ask the remaining plugins. */
                     return false;
                 } else {
-                    return inline(targetMethod, inlineInfo.getMethodToInline(), inlineInfo.isIntrinsic(), args);
+                    return inline(targetMethod, lastInlineInfo.getMethodToInline(), lastInlineInfo.isIntrinsic(), args);
                 }
             }
         }
@@ -3024,7 +3026,9 @@
                 ResolvedJavaType singleType = profile.asSingleType();
                 if (singleType != null) {
                     LogicNode typeCheck = append(TypeCheckNode.create(singleType, object));
-                    append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
+                    if (!typeCheck.isTautology()) {
+                        append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
+                    }
                     instanceOfNode = LogicConstantNode.forBoolean(resolvedType.isAssignableFrom(singleType));
                 }
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ConstantLoadTest.java	Tue Jul 21 16:17:54 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.jtt.micro;
+
+import org.junit.*;
+
+import com.oracle.graal.jtt.*;
+
+public class ConstantLoadTest extends JTTTest {
+
+    private static final class MyClass {
+        public long a;
+        public long b;
+
+        MyClass(long a, long b) {
+            this.a = a;
+            this.b = b;
+        }
+    }
+
+    private static final MyClass myClass = new MyClass(Long.MIN_VALUE, Long.MAX_VALUE);
+    private static final long myLong = Long.MAX_VALUE;
+
+    public static long test(int arg) {
+        if (arg == 0) {
+            return myClass.a / arg + myLong;
+        }
+        if (arg == 1) {
+            return myClass.b - arg + myLong;
+        }
+        long r = 1;
+        for (int i = 0; i < arg; i++) {
+            r *= i;
+        }
+        return r;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/VarArgs_Unroll.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.jtt.micro;
+
+import org.junit.*;
+
+import com.oracle.graal.jtt.*;
+
+/*
+ */
+public class VarArgs_Unroll extends JTTTest {
+
+    public static boolean test(String a, String b) {
+        return check(a, b);
+    }
+
+    private static boolean check(String... args) {
+        if (args.length == 0) {
+            return true;
+        }
+        String s = args[0];
+        for (String t : args) {
+            if (!t.equals(s)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "ab", "ab");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "ab", "abc");
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java	Tue Jul 21 16:17:54 2015 +0200
@@ -78,8 +78,8 @@
         this.lengthValue = length;
 
         // Allocate some temporaries.
-        this.temp1 = tool.newVariable(LIRKind.derivedReference(tool.target().wordKind));
-        this.temp2 = tool.newVariable(LIRKind.derivedReference(tool.target().wordKind));
+        this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().wordKind));
+        this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().wordKind));
         this.temp3 = tool.newVariable(LIRKind.value(tool.target().wordKind));
         this.temp4 = tool.newVariable(LIRKind.value(tool.target().wordKind));
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java	Tue Jul 21 16:17:54 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -36,7 +36,7 @@
  *
  * <pre>
  *   Base       Contents
- * 
+ *
  *            :                                :  -----
  *   caller   | incoming overflow argument n   |    ^
  *   frame    :     ...                        :    | positive
@@ -74,8 +74,8 @@
 
     private StackSlot rbpSpillSlot;
 
-    public AMD64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig) {
-        super(codeCache, registerConfig);
+    public AMD64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) {
+        super(codeCache, registerConfig, referenceMapFactory);
         // (negative) offset relative to sp + total frame size
         initialSpillSize = returnAddressSize() + calleeSaveAreaSize();
         spillSize = initialSpillSize;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Tue Jul 21 16:17:54 2015 +0200
@@ -673,6 +673,10 @@
                 assert NumUtil.isShort(imm) : "Is not in short range: " + imm;
                 AMD64MIOp.MOV.emit(masm, OperandSize.WORD, dest, (int) imm);
                 break;
+            case Char:
+                assert NumUtil.isUShort(imm) : "Is not in char range: " + imm;
+                AMD64MIOp.MOV.emit(masm, OperandSize.WORD, dest, (int) imm);
+                break;
             case Int:
             case Float:
                 assert NumUtil.isInt(imm) : "Is not in int range: " + imm;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/phases/StackMoveOptimizationPhase.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/phases/StackMoveOptimizationPhase.java	Tue Jul 21 16:17:54 2015 +0200
@@ -38,6 +38,13 @@
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.phases.*;
 
+/**
+ * Replaces sequential {@link AMD64StackMove}s of the same type with a single
+ * {@link AMD64MultiStackMove} to avoid storing/restoring the scratch register multiple times.
+ *
+ * Note: this phase must be inserted <b>after</b> {@link RedundantMoveElimination} phase because
+ * {@link AMD64MultiStackMove} are not probably detected.
+ */
 public class StackMoveOptimizationPhase extends PostAllocationOptimizationPhase {
     public static class Options {
         // @formatter:off
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/ConstantStackCastTest.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,88 @@
+/*
+ * 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.jtt;
+
+import static jdk.internal.jvmci.code.ValueUtil.*;
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.common.*;
+import jdk.internal.jvmci.meta.*;
+
+import org.junit.*;
+
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+
+/**
+ * Tests move from a constant to a wider stack slot (e.g. byte constant to integer stack slot).
+ */
+public class ConstantStackCastTest extends LIRTest {
+
+    private static class LoadConstantStackSpec extends LIRTestSpecification {
+        protected final LIRKind dstKind;
+        protected final LIRKind srcKind;
+
+        public LoadConstantStackSpec(LIRKind dstKind, LIRKind srcKind) {
+            this.dstKind = dstKind;
+            this.srcKind = srcKind;
+        }
+
+        @Override
+        public void generate(LIRGeneratorTool gen, Value value) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            // create slots
+            StackSlotValue s1 = frameMapBuilder.allocateSpillSlot(dstKind);
+            // move stuff around
+            Value srcValue = isConstant(value) ? getConstant(srcKind, value) : value;
+            gen.emitMove(s1, srcValue);
+            gen.emitBlackhole(s1);
+            setResult(gen.emitMove(s1));
+        }
+
+        private static PrimitiveConstant getConstant(LIRKind srcKind, Value value) {
+
+            switch ((Kind) srcKind.getPlatformKind()) {
+                case Byte:
+                    return JavaConstant.forByte((byte) asConstant(value).asInt());
+                default:
+                    throw JVMCIError.shouldNotReachHere("Kind not supported: " + srcKind);
+            }
+        }
+    }
+
+    private static final LoadConstantStackSpec stackCopyByte = new LoadConstantStackSpec(LIRKind.value(Kind.Int), LIRKind.value(Kind.Byte));
+
+    @LIRIntrinsic
+    public static byte testCopyByte(@SuppressWarnings("unused") LoadConstantStackSpec spec, byte value) {
+        return value;
+    }
+
+    public byte testByte(byte value) {
+        return testCopyByte(stackCopyByte, value);
+    }
+
+    @Test
+    public void runByte() throws Throwable {
+        runTest("testByte", (byte) 0);
+    }
+
+}
--- a/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/StackMoveTest.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/StackMoveTest.java	Tue Jul 21 16:17:54 2015 +0200
@@ -83,11 +83,11 @@
 
     @Test
     public void runInt() throws Throwable {
-        runTest("testInt", Integer.MIN_VALUE, supply(() -> new int[3]));
+        runTest("testInt", Integer.MIN_VALUE, supply(() -> new int[4]));
         runTest("testInt", -1, supply(() -> new int[4]));
-        runTest("testInt", 0, supply(() -> new int[3]));
-        runTest("testInt", 1, supply(() -> new int[3]));
-        runTest("testInt", Integer.MAX_VALUE, supply(() -> new int[3]));
+        runTest("testInt", 0, supply(() -> new int[4]));
+        runTest("testInt", 1, supply(() -> new int[4]));
+        runTest("testInt", Integer.MAX_VALUE, supply(() -> new int[4]));
     }
 
     /*
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Tue Jul 21 16:17:54 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -210,8 +210,8 @@
             this.result = result;
             this.x = x;
             this.y = y;
-            this.scratch1 = gen.newVariable(LIRKind.derive(x, y));
-            this.scratch2 = gen.newVariable(LIRKind.derive(x, y));
+            this.scratch1 = gen.newVariable(LIRKind.combine(x, y));
+            this.scratch2 = gen.newVariable(LIRKind.combine(x, y));
             this.state = state;
         }
 
@@ -245,8 +245,8 @@
             this.result = result;
             this.x = x;
             this.y = y;
-            this.scratch1 = gen.newVariable(LIRKind.derive(x, y));
-            this.scratch2 = gen.newVariable(LIRKind.derive(x, y));
+            this.scratch1 = gen.newVariable(LIRKind.combine(x, y));
+            this.scratch2 = gen.newVariable(LIRKind.combine(x, y));
         }
 
         @Override
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java	Tue Jul 21 16:17:54 2015 +0200
@@ -83,8 +83,8 @@
         this.lengthValue = length;
 
         // Allocate some temporaries.
-        this.temp1 = tool.newVariable(LIRKind.derivedReference(tool.target().wordKind));
-        this.temp2 = tool.newVariable(LIRKind.derivedReference(tool.target().wordKind));
+        this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().wordKind));
+        this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().wordKind));
         this.temp3 = tool.newVariable(LIRKind.value(tool.target().wordKind));
         this.temp4 = tool.newVariable(LIRKind.value(tool.target().wordKind));
         this.temp5 = tool.newVariable(LIRKind.value(tool.target().wordKind));
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java	Tue Jul 21 16:17:54 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -62,7 +62,7 @@
         this.opcode = opcode;
         this.result = result;
         this.input = input;
-        scratch = gen.newVariable(LIRKind.derive(input));
+        scratch = gen.newVariable(LIRKind.combine(input));
     }
 
     @Override
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java	Tue Jul 21 16:17:54 2015 +0200
@@ -22,15 +22,16 @@
  */
 package com.oracle.graal.lir.sparc;
 
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+import static jdk.internal.jvmci.code.ValueUtil.*;
+import static jdk.internal.jvmci.sparc.SPARC.*;
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
 import jdk.internal.jvmci.meta.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-import static jdk.internal.jvmci.code.ValueUtil.*;
-import static jdk.internal.jvmci.sparc.SPARC.*;
 
 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.Sethix;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
@@ -81,7 +82,7 @@
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
             if (!emitted) {
                 emitCallPrefixCode(crb, masm);
-                directCall(crb, masm, callTarget, null, true, state);
+                directCall(crb, masm, callTarget, null, state);
             } else {
                 int after = masm.position();
                 if (after - before == 4) {
@@ -165,7 +166,7 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            directCall(crb, masm, callTarget, null, false, state);
+            directCall(crb, masm, callTarget, null, state);
         }
     }
 
@@ -180,15 +181,13 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            directCall(crb, masm, callTarget, o7, false, state);
+            try (ScratchRegister scratch = masm.getScratchRegister()) {
+                directCall(crb, masm, callTarget, scratch.getRegister(), state);
+            }
         }
     }
 
-    public static void directCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) {
-        if (align) {
-            // We don't need alignment on SPARC.
-        }
-
+    public static void directCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info) {
         int before;
         if (scratch != null) {
             // offset might not fit a 30-bit displacement, generate an
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Tue Jul 21 16:17:54 2015 +0200
@@ -38,6 +38,7 @@
 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.*;
@@ -311,12 +312,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 {
@@ -403,7 +407,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);
@@ -414,7 +419,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;
         }
@@ -424,9 +429,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;
@@ -452,10 +479,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(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 {
@@ -486,8 +518,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
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Tue Jul 21 16:17:54 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -75,8 +75,8 @@
  */
 public final class SPARCFrameMap extends FrameMap {
 
-    public SPARCFrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig) {
-        super(codeCache, registerConfig);
+    public SPARCFrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) {
+        super(codeCache, registerConfig, referenceMapFactory);
         // Initial spill size is set to register save area size (SPARC register window)
         initialSpillSize = 0;
         spillSize = initialSpillSize;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCLIRInstruction.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCLIRInstruction.java	Tue Jul 21 16:17:54 2015 +0200
@@ -101,5 +101,10 @@
                 return new SizeEstimate(instructionSize, 0);
             }
         }
+
+        @Override
+        public String toString() {
+            return "SE[i=" + instructionSize + ", c=" + constantSize + "]";
+        }
     }
 }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCLoadConstantTableBaseOp.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCLoadConstantTableBaseOp.java	Tue Jul 21 16:17:54 2015 +0200
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 import static jdk.internal.jvmci.code.ValueUtil.*;
-import jdk.internal.jvmci.code.CompilationResult.DataSectionReference;
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.meta.*;
 
@@ -71,16 +70,11 @@
     @Override
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
         Register baseRegister = asRegister(base);
-        DataSectionReference ref = new DataSectionReference();
-        ref.setOffset(0);
-        crb.compilationResult.recordDataPatch(masm.position(), ref);
-        // TODO: (sa) Make this relocation shorter (right now it takes always 8 instructions)
-        new SPARCMacroAssembler.Setx(0, baseRegister, true).emit(masm);
-        /**
-         * Place the base register into the center of the reachable 8k range. This bias is reflected
-         * in CodeInstaller::pd_patch_DataSectionReference (jvmciCodeInstaller_sparc.cpp)
-         */
-        masm.sub(baseRegister, -1 & ~((1 << 12) - 1), baseRegister);
+        int beforePosition = masm.position();
+        masm.rdpc(baseRegister);
+        // Must match with CodeInstaller::pd_patch_DataSectionReference
+        masm.add(baseRegister, (int) SPARCAssembler.minSimm(13), baseRegister);
+        masm.sub(baseRegister, beforePosition, baseRegister);
     }
 
     public AllocatableValue getResult() {
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Tue Jul 21 16:17:54 2015 +0200
@@ -635,13 +635,13 @@
                     JavaConstant constant) {
         if (constant.isDefaultForKind() || constant.isNull()) {
             SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result);
-            emitStore(g0.asValue(LIRKind.derive(input)), resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm);
+            emitStore(g0.asValue(LIRKind.combine(input)), resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm);
         } else {
             try (ScratchRegister sc = masm.getScratchRegister()) {
-                Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.derive(constant));
+                Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(constant));
                 const2reg(crb, masm, scratchRegisterValue, constantTableBase, constant, SPARCDelayedControlTransfer.DUMMY);
                 SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result);
-                emitStore(scratchRegisterValue, resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm);
+                emitStore(scratchRegisterValue, resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm);
             }
         }
     }
@@ -649,7 +649,7 @@
     public static void stack2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) {
         try (ScratchRegister sc = masm.getScratchRegister()) {
             SPARCAddress inputAddress = (SPARCAddress) crb.asAddress(input);
-            Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.derive(input));
+            Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(input));
             emitLoad(crb, masm, inputAddress, scratchRegisterValue, false, input.getPlatformKind(), SPARCDelayedControlTransfer.DUMMY, null);
             SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result);
             emitStore(scratchRegisterValue, resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Tue Jul 21 16:17:54 2015 +0200
@@ -31,6 +31,7 @@
 
 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.*;
 
 /**
@@ -44,6 +45,8 @@
     public final LabelRef exceptionEdge;
     protected DebugInfo debugInfo;
 
+    private ValueSet liveBasePointers;
+
     public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge) {
         this.topFrame = topFrame;
         this.virtualObjects = virtualObjects;
@@ -73,6 +76,9 @@
                 processValues(inst, obj.getValues(), proc);
             }
         }
+        if (liveBasePointers != null) {
+            liveBasePointers.forEach(inst, OperandMode.ALIVE, STATE_FLAGS, proc);
+        }
     }
 
     /**
@@ -89,6 +95,9 @@
                 processValues(inst, obj.getValues(), proc);
             }
         }
+        if (liveBasePointers != null) {
+            liveBasePointers.forEach(inst, OperandMode.ALIVE, STATE_FLAGS, proc);
+        }
     }
 
     /**
@@ -169,7 +178,15 @@
      * @param canHaveRegisters True if there can be any register map entries.
      */
     public void initDebugInfo(FrameMap frameMap, boolean canHaveRegisters) {
-        debugInfo = new DebugInfo(topFrame, frameMap.initReferenceMap(canHaveRegisters), virtualObjects);
+        debugInfo = new DebugInfo(topFrame, virtualObjects);
+    }
+
+    public ValueSet getLiveBasePointers() {
+        return liveBasePointers;
+    }
+
+    public void setLiveBasePointers(ValueSet liveBasePointers) {
+        this.liveBasePointers = liveBasePointers;
     }
 
     @Override
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Tue Jul 21 16:17:54 2015 +0200
@@ -47,8 +47,8 @@
     @Override
     protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
                     BenchmarkCounterFactory counterFactory) {
-        Optimization redundantMoveElimination = new Optimization();
-        redundantMoveElimination.doOptimize(lirGenRes.getLIR(), lirGenRes.getFrameMap());
+        Optimization redundantMoveElimination = new Optimization(lirGenRes.getFrameMap());
+        redundantMoveElimination.doOptimize(lirGenRes.getLIR());
     }
 
     /**
@@ -98,19 +98,29 @@
          */
         int[] eligibleRegs;
 
-        Map<StackSlot, Integer> stackIndices = CollectionsFactory.newMap();
+        /**
+         * A map from the {@link StackSlot} {@link #getOffset offset} to an index into the state.
+         * StackSlots of different kinds that map to the same location will map to the same index.
+         */
+        Map<Integer, Integer> stackIndices = CollectionsFactory.newMap();
 
         int numRegs;
 
+        private final FrameMap frameMap;
+
         /*
          * Pseudo value for a not yet assigned location.
          */
         static final int INIT_VALUE = 0;
 
+        public Optimization(FrameMap frameMap) {
+            this.frameMap = frameMap;
+        }
+
         /**
          * The main method doing the elimination of redundant moves.
          */
-        private void doOptimize(LIR lir, FrameMap frameMap) {
+        private void doOptimize(LIR lir) {
 
             try (Indent indent = Debug.logAndIndent("eliminate redundant moves")) {
 
@@ -165,8 +175,9 @@
                             }
                         } else if (isStackSlot(dest)) {
                             StackSlot stackSlot = (StackSlot) dest;
-                            if (!stackIndices.containsKey(stackSlot) && stackIndices.size() < maxStackLocations) {
-                                stackIndices.put(stackSlot, stackIndices.size());
+                            Integer offset = getOffset(stackSlot);
+                            if (!stackIndices.containsKey(offset) && stackIndices.size() < maxStackLocations) {
+                                stackIndices.put(offset, stackIndices.size());
                             }
                         }
                     }
@@ -184,6 +195,10 @@
             }
         }
 
+        private int getOffset(StackSlot stackSlot) {
+            return stackSlot.getOffset(frameMap.totalFrameSize());
+        }
+
         /**
          * Calculates the entry and exit states for all basic blocks.
          *
@@ -480,7 +495,7 @@
             }
             if (isStackSlot(location)) {
                 StackSlot slot = (StackSlot) location;
-                Integer index = stackIndices.get(slot);
+                Integer index = stackIndices.get(getOffset(slot));
                 if (index != null) {
                     return index.intValue() + numRegs;
                 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Tue Jul 21 16:17:54 2015 +0200
@@ -152,12 +152,12 @@
      */
     private final int firstVariableNumber;
 
-    LinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig) {
+    LinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, List<? extends AbstractBlockBase<?>> sortedBlocks) {
         this.res = res;
         this.ir = res.getLIR();
         this.moveFactory = spillMoveFactory;
         this.frameMapBuilder = res.getFrameMapBuilder();
-        this.sortedBlocks = ir.linearScanOrder();
+        this.sortedBlocks = sortedBlocks;
         this.registerAttributes = regAllocConfig.getRegisterConfig().getAttributesMap();
         this.regAllocConfig = regAllocConfig;
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Tue Jul 21 16:17:54 2015 +0200
@@ -203,7 +203,7 @@
                 for (int j = 0; j < numInst; j++) {
                     final LIRInstruction op = instructions.get(j);
 
-                    try (Indent indent2 = Debug.logAndIndent("handle op %d", op.id())) {
+                    try (Indent indent2 = Debug.logAndIndent("handle op %d: %s", op.id(), op)) {
                         op.visitEachInput(useConsumer);
                         op.visitEachAlive(useConsumer);
                         /*
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Tue Jul 21 16:17:54 2015 +0200
@@ -53,9 +53,9 @@
                     RegisterAllocationConfig registerAllocationConfig) {
         final LinearScan allocator;
         if (LinearScanPhase.SSA_LSRA.getValue()) {
-            allocator = new SSALinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig);
+            allocator = new SSALinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, linearScanOrder);
         } else {
-            allocator = new LinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig);
+            allocator = new LinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, linearScanOrder);
         }
         allocator.allocate(target, lirGenRes, codeEmittingOrder, linearScanOrder, spillMoveFactory, registerAllocationConfig);
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java	Tue Jul 21 16:17:54 2015 +0200
@@ -781,16 +781,7 @@
             spillCollectInactiveAny(interval);
 
             if (Debug.isLogEnabled()) {
-                try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
-                    for (Register reg : availableRegs) {
-                        int i = reg.number;
-                        try (Indent indent3 = Debug.logAndIndent("reg %d: usePos: %d, blockPos: %d, intervals: ", i, usePos[i], blockPos[i])) {
-                            for (int j = 0; j < spillIntervals[i].size(); j++) {
-                                Debug.log("%d ", spillIntervals[i].get(j).operandNumber);
-                            }
-                        }
-                    }
-                }
+                printRegisterState();
             }
 
             // the register must be free at least until this position
@@ -820,10 +811,11 @@
                 }
 
                 if (firstUsage <= interval.from() + 1) {
-                    String description = "cannot spill interval that is used in first instruction (possible reason: no register found) firstUsage=" + firstUsage + ", interval.from()=" +
-                                    interval.from() + "; already used candidates: " + Arrays.toString(availableRegs);
+                    String description = "cannot spill interval (" + interval + ") that is used in first instruction (possible reason: no register found) firstUsage=" + firstUsage +
+                                    ", interval.from()=" + interval.from() + "; already used candidates: " + Arrays.toString(availableRegs);
                     // assign a reasonable register and do a bailout in product mode to avoid errors
                     allocator.assignSpillSlot(interval);
+                    Debug.dump(allocator.ir, description);
                     allocator.printIntervals(description);
                     throw new OutOfRegistersException("LinearScan: no register found", description);
                 }
@@ -853,6 +845,19 @@
         }
     }
 
+    void printRegisterState() {
+        try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
+            for (Register reg : availableRegs) {
+                int i = reg.number;
+                try (Indent indent3 = Debug.logAndIndent("reg %d: usePos: %d, blockPos: %d, intervals: ", i, usePos[i], blockPos[i])) {
+                    for (int j = 0; j < spillIntervals[i].size(); j++) {
+                        Debug.log("%s ", spillIntervals[i].get(j));
+                    }
+                }
+            }
+        }
+    }
+
     boolean noAllocationPossible(Interval interval) {
         if (allocator.callKillsRegisters) {
             // fast calculation of intervals that can never get a register because the
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Tue Jul 21 15:16:00 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,459 +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.alloc.lsra;
-
-import static jdk.internal.jvmci.code.ValueUtil.*;
-
-import java.util.*;
-import java.util.function.*;
-
-import jdk.internal.jvmci.code.*;
-import jdk.internal.jvmci.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.lir.*;
-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.gen.*;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
-import com.oracle.graal.lir.phases.*;
-
-/**
- * Mark all live references for a frame state. The frame state use this information to build the OOP
- * maps.
- */
-public final class LocationMarker extends AllocationPhase {
-
-    public static class Options {
-        // @formatter:off
-        @Option(help = "Use decoupled pass for location marking (instead of using LSRA marking)", type = OptionType.Debug)
-        public static final OptionValue<Boolean> UseLocationMarker = new OptionValue<>(true);
-        // @formatter:on
-    }
-
-    @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
-        new Marker<B>(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build();
-    }
-
-    /**
-     * Ensures that an element is only in the worklist once.
-     *
-     * @param <T>
-     */
-    static class UniqueWorkList<T extends AbstractBlockBase<T>> extends ArrayDeque<T> {
-        private static final long serialVersionUID = 8009554570990975712L;
-        BitSet valid;
-
-        public UniqueWorkList(int size) {
-            this.valid = new BitSet(size);
-        }
-
-        @Override
-        public T poll() {
-            T result = super.poll();
-            if (result != null) {
-                valid.set(result.getId(), false);
-            }
-            return result;
-        }
-
-        @Override
-        public boolean add(T pred) {
-            if (!valid.get(pred.getId())) {
-                valid.set(pred.getId(), true);
-                return super.add(pred);
-            }
-            return false;
-        }
-
-        @Override
-        public boolean addAll(Collection<? extends T> collection) {
-            boolean changed = false;
-            for (T element : collection) {
-                if (!valid.get(element.getId())) {
-                    valid.set(element.getId(), true);
-                    super.add(element);
-                    changed = true;
-                }
-            }
-            return changed;
-        }
-    }
-
-    private static 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);
-        }
-
-        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(ReferenceMap refMap) {
-            for (Value v : values) {
-                if (v != null) {
-                    refMap.addLiveValue(v);
-                }
-            }
-        }
-
-        @Override
-        public int hashCode() {
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    private static final class Marker<T extends AbstractBlockBase<T>> {
-
-        private final class LiveValueSet implements Consumer<AbstractBlockBase<T>> {
-
-            public void accept(AbstractBlockBase<T> succ) {
-                putAll(liveInMap.get(succ));
-            }
-
-            private final ValueSet registers;
-            private final ValueSet stack;
-            private Set<Value> extraStack;
-
-            public LiveValueSet() {
-                registers = new ValueSet();
-                stack = new ValueSet();
-            }
-
-            public LiveValueSet(LiveValueSet s) {
-                registers = new ValueSet(s.registers);
-                stack = new ValueSet(s.stack);
-                if (s.extraStack != null) {
-                    extraStack = new HashSet<>(s.extraStack);
-                }
-            }
-
-            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);
-                    }
-                }
-            }
-
-            public void putAll(LiveValueSet v) {
-                registers.putAll(v.registers);
-                stack.putAll(v.stack);
-                if (v.extraStack != null) {
-                    if (extraStack == null) {
-                        extraStack = new HashSet<>();
-                    }
-                    extraStack.addAll(v.extraStack);
-                }
-            }
-
-            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.LiveValueSet) {
-                    LiveValueSet other = (LiveValueSet) 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(ReferenceMap refMap) {
-                registers.addLiveValues(refMap);
-                stack.addLiveValues(refMap);
-                if (extraStack != null) {
-                    for (Value v : extraStack) {
-                        refMap.addLiveValue(v);
-                    }
-                }
-            }
-        }
-
-        private final LIR lir;
-        private final FrameMap frameMap;
-        private final RegisterAttributes[] registerAttributes;
-        private final BlockMap<LiveValueSet> liveInMap;
-        private final BlockMap<LiveValueSet> liveOutMap;
-
-        private Marker(LIR lir, FrameMap frameMap) {
-            this.lir = lir;
-            this.frameMap = frameMap;
-            this.registerAttributes = frameMap.getRegisterConfig().getAttributesMap();
-            liveInMap = new BlockMap<>(lir.getControlFlowGraph());
-            liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
-        }
-
-        @SuppressWarnings("unchecked")
-        void build() {
-            UniqueWorkList<T> worklist = new UniqueWorkList<>(lir.getControlFlowGraph().getBlocks().size());
-            for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) {
-                worklist.add((T) lir.getControlFlowGraph().getBlocks().get(i));
-            }
-            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
-                liveInMap.put(block, new LiveValueSet());
-            }
-            while (!worklist.isEmpty()) {
-                AbstractBlockBase<T> block = worklist.poll();
-                processBlock(block, worklist);
-            }
-        }
-
-        /**
-         * Merge outSet with in-set of successors.
-         */
-        private boolean updateOutBlock(AbstractBlockBase<T> block) {
-            LiveValueSet union = new LiveValueSet();
-            block.getSuccessors().forEach(union);
-            LiveValueSet outSet = liveOutMap.get(block);
-            // check if changed
-            if (outSet == null || !union.equals(outSet)) {
-                liveOutMap.put(block, union);
-                return true;
-            }
-            return false;
-        }
-
-        private void processBlock(AbstractBlockBase<T> block, UniqueWorkList<T> worklist) {
-            if (updateOutBlock(block)) {
-                try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
-                    currentSet = new LiveValueSet(liveOutMap.get(block));
-                    List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-                    for (int i = instructions.size() - 1; i >= 0; i--) {
-                        LIRInstruction inst = instructions.get(i);
-                        processInstructionBottomUp(inst);
-                    }
-                    liveInMap.put(block, currentSet);
-                    currentSet = null;
-                    worklist.addAll(block.getPredecessors());
-                }
-            }
-        }
-
-        private static final EnumSet<OperandFlag> REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG);
-        private static final LIRKind REFERENCE_KIND = LIRKind.reference(Kind.Object);
-
-        private LiveValueSet currentSet;
-
-        /**
-         * Process all values of an instruction bottom-up, i.e. definitions before usages. Values
-         * that start or end at the current operation are not included.
-         */
-        private void processInstructionBottomUp(LIRInstruction op) {
-            try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
-                // kills
-
-                op.visitEachTemp(defConsumer);
-                op.visitEachOutput(defConsumer);
-                if (op.destroysCallerSavedRegisters()) {
-                    for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
-                        defConsumer.visitValue(reg.asValue(REFERENCE_KIND), OperandMode.TEMP, REGISTER_FLAG_SET);
-                    }
-                }
-
-                // gen - values that are considered alive for this state
-                op.visitEachAlive(useConsumer);
-                op.visitEachState(useConsumer);
-                // mark locations
-                op.forEachState(stateConsumer);
-                // gen
-                op.visitEachInput(useConsumer);
-            }
-        }
-
-        InstructionStateProcedure stateConsumer = new InstructionStateProcedure() {
-            public void doState(LIRInstruction inst, LIRFrameState info) {
-                markLocation(inst, info, currentSet);
-            }
-        };
-
-        ValueConsumer useConsumer = new ValueConsumer() {
-            public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                if (shouldProcessValue(operand)) {
-                    // no need to insert values and derived reference
-                    if (Debug.isLogEnabled()) {
-                        Debug.log("set operand: %s", operand);
-                    }
-                    currentSet.put(operand);
-                }
-            }
-        };
-
-        ValueConsumer defConsumer = new ValueConsumer() {
-            public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                if (shouldProcessValue(operand)) {
-                    if (Debug.isLogEnabled()) {
-                        Debug.log("clear operand: %s", operand);
-                    }
-                    currentSet.remove(operand);
-                } else {
-                    assert isIllegal(operand) || operand.getPlatformKind() != Kind.Illegal || mode == OperandMode.TEMP : String.format("Illegal PlatformKind is only allowed for TEMP mode: %s, %s",
-                                    operand, mode);
-                }
-            }
-        };
-
-        protected boolean shouldProcessValue(Value operand) {
-            return (isRegister(operand) && attributes(asRegister(operand)).isAllocatable() || isStackSlot(operand)) && operand.getPlatformKind() != Kind.Illegal;
-        }
-
-        /**
-         * This method does the actual marking.
-         */
-        private void markLocation(LIRInstruction op, LIRFrameState info, LiveValueSet values) {
-            if (!info.hasDebugInfo()) {
-                info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !frameMap.getRegisterConfig().areAllAllocatableRegistersCallerSaved());
-            }
-
-            ReferenceMap refMap = info.debugInfo().getReferenceMap();
-            refMap.reset();
-            frameMap.addLiveValues(refMap);
-            values.addLiveValues(refMap);
-            refMap.finish();
-        }
-
-        /**
-         * Gets an object describing the attributes of a given register according to this register
-         * configuration.
-         *
-         * @see LinearScan#attributes
-         */
-        private RegisterAttributes attributes(Register reg) {
-            return registerAttributes[reg.number];
-        }
-
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Tue Jul 21 16:17:54 2015 +0200
@@ -165,7 +165,15 @@
         }
         for (int i = 0; i < mappingTo.size(); i++) {
             Interval interval = mappingTo.get(i);
-            assert !usedRegs.contains(interval.location()) || interval.location().equals(mappingFrom.get(i).location()) : "stack slots used in mappingFrom must be disjoint to mappingTo";
+            assert !usedRegs.contains(interval.location()) || checkIntervalLocation(mappingFrom.get(i), interval, mappingFromOpr.get(i)) : "stack slots used in mappingFrom must be disjoint to mappingTo";
+        }
+    }
+
+    private static boolean checkIntervalLocation(Interval from, Interval to, Value fromOpr) {
+        if (from == null) {
+            return fromOpr != null;
+        } else {
+            return to.location().equals(from.location());
         }
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/RegisterVerifier.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/RegisterVerifier.java	Tue Jul 21 16:17:54 2015 +0200
@@ -29,6 +29,7 @@
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.common.*;
 import jdk.internal.jvmci.debug.*;
+import jdk.internal.jvmci.debug.Debug.Scope;
 import jdk.internal.jvmci.meta.*;
 
 import com.oracle.graal.compiler.common.cfg.*;
@@ -78,18 +79,20 @@
     }
 
     void verify(AbstractBlockBase<?> start) {
-        // setup input registers (method arguments) for first block
-        Interval[] inputState = new Interval[stateSize()];
-        setStateForBlock(start, inputState);
-        addToWorkList(start);
+        try (Scope s = Debug.scope("RegisterVerifier")) {
+            // setup input registers (method arguments) for first block
+            Interval[] inputState = new Interval[stateSize()];
+            setStateForBlock(start, inputState);
+            addToWorkList(start);
 
-        // main loop for verification
-        do {
-            AbstractBlockBase<?> block = workList.get(0);
-            workList.remove(0);
+            // main loop for verification
+            do {
+                AbstractBlockBase<?> block = workList.get(0);
+                workList.remove(0);
 
-            processBlock(block);
-        } while (!workList.isEmpty());
+                processBlock(block);
+            } while (!workList.isEmpty());
+        }
     }
 
     private void processBlock(AbstractBlockBase<?> block) {
@@ -98,17 +101,15 @@
             Interval[] inputState = copy(stateForBlock(block));
 
             try (Indent indent2 = Debug.logAndIndent("Input-State of intervals:")) {
-                for (int i = 0; i < stateSize(); i++) {
-                    if (inputState[i] != null) {
-                        Debug.log(" %4d", inputState[i].operandNumber);
-                    } else {
-                        Debug.log("   __");
-                    }
-                }
+                printState(inputState);
             }
 
             // process all operations of the block
-            processOperations(allocator.ir.getLIRforBlock(block), inputState);
+            processOperations(block, inputState);
+
+            try (Indent indent2 = Debug.logAndIndent("Output-State of intervals:")) {
+                printState(inputState);
+            }
 
             // iterate all successors
             for (AbstractBlockBase<?> succ : block.getSuccessors()) {
@@ -117,6 +118,18 @@
         }
     }
 
+    protected void printState(Interval[] inputState) {
+        for (int i = 0; i < stateSize(); i++) {
+            Register reg = allocator.registers[i];
+            assert reg.number == i;
+            if (inputState[i] != null) {
+                Debug.log(" %6s %4d  --  %s", reg, inputState[i].operandNumber, inputState[i]);
+            } else {
+                Debug.log(" %6s   __", reg);
+            }
+        }
+    }
+
     private void processSuccessor(AbstractBlockBase<?> block, Interval[] inputState) {
         Interval[] savedState = stateForBlock(block);
 
@@ -177,16 +190,19 @@
         }
     }
 
-    static boolean checkState(Interval[] inputState, Value reg, Interval interval) {
+    static boolean checkState(AbstractBlockBase<?> block, LIRInstruction op, Interval[] inputState, Value operand, Value reg, Interval interval) {
         if (reg != null && isRegister(reg)) {
             if (inputState[asRegister(reg).number] != interval) {
-                throw new JVMCIError("!! Error in register allocation: register %s does not contain interval %s but interval %s", reg, interval.operand, inputState[asRegister(reg).number]);
+                throw new JVMCIError(
+                                "Error in register allocation: operation (%s) in block %s expected register %s (operand %s) to contain the value of interval %s but data-flow says it contains interval %s",
+                                op, block, reg, operand, interval, inputState[asRegister(reg).number]);
             }
         }
         return true;
     }
 
-    void processOperations(List<LIRInstruction> ops, final Interval[] inputState) {
+    void processOperations(AbstractBlockBase<?> block, final Interval[] inputState) {
+        List<LIRInstruction> ops = allocator.ir.getLIRforBlock(block);
         InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
 
             @Override
@@ -198,7 +214,7 @@
                         interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
                     }
 
-                    assert checkState(inputState, interval.location(), interval.splitParent());
+                    assert checkState(block, op, inputState, interval.operand, interval.location(), interval.splitParent());
                 }
             }
         };
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScan.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScan.java	Tue Jul 21 16:17:54 2015 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.lir.alloc.lsra;
 
+import java.util.*;
+
 import jdk.internal.jvmci.code.*;
 import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.debug.Debug.*;
@@ -34,8 +36,8 @@
 
 final class SSALinearScan extends LinearScan {
 
-    SSALinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig) {
-        super(target, res, spillMoveFactory, regAllocConfig);
+    SSALinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, List<? extends AbstractBlockBase<?>> sortedBlocks) {
+        super(target, res, spillMoveFactory, regAllocConfig, sortedBlocks);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LiveValueSet.java	Tue Jul 21 16:17:54 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.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();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarker.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,170 @@
+/*
+ * 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 static jdk.internal.jvmci.code.ValueUtil.*;
+
+import java.util.*;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.debug.*;
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+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 abstract class LocationMarker<T extends AbstractBlockBase<T>, S extends LiveValueSet<S>> {
+
+    private final LIR lir;
+    private final BlockMap<S> liveInMap;
+    private final BlockMap<S> liveOutMap;
+
+    protected final FrameMap frameMap;
+
+    protected LocationMarker(LIR lir, FrameMap frameMap) {
+        this.lir = lir;
+        this.frameMap = frameMap;
+        liveInMap = new BlockMap<>(lir.getControlFlowGraph());
+        liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
+    }
+
+    protected abstract S newLiveValueSet();
+
+    protected abstract boolean shouldProcessValue(Value operand);
+
+    protected abstract void processState(LIRInstruction op, LIRFrameState info, S values);
+
+    @SuppressWarnings("unchecked")
+    void build() {
+        UniqueWorkList<T> worklist = new UniqueWorkList<>(lir.getControlFlowGraph().getBlocks().size());
+        for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) {
+            worklist.add((T) lir.getControlFlowGraph().getBlocks().get(i));
+        }
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            liveInMap.put(block, newLiveValueSet());
+        }
+        while (!worklist.isEmpty()) {
+            AbstractBlockBase<T> block = worklist.poll();
+            processBlock(block, worklist);
+        }
+    }
+
+    /**
+     * Merge outSet with in-set of successors.
+     */
+    private boolean updateOutBlock(AbstractBlockBase<T> block) {
+        S union = newLiveValueSet();
+        for (T succ : block.getSuccessors()) {
+            union.putAll(liveInMap.get(succ));
+        }
+        S outSet = liveOutMap.get(block);
+        // check if changed
+        if (outSet == null || !union.equals(outSet)) {
+            liveOutMap.put(block, union);
+            return true;
+        }
+        return false;
+    }
+
+    private void processBlock(AbstractBlockBase<T> block, UniqueWorkList<T> worklist) {
+        if (updateOutBlock(block)) {
+            try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
+                currentSet = liveOutMap.get(block).copy();
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                for (int i = instructions.size() - 1; i >= 0; i--) {
+                    LIRInstruction inst = instructions.get(i);
+                    processInstructionBottomUp(inst);
+                }
+                liveInMap.put(block, currentSet);
+                currentSet = null;
+                worklist.addAll(block.getPredecessors());
+            }
+        }
+    }
+
+    private static final EnumSet<OperandFlag> REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG);
+    private static final LIRKind REFERENCE_KIND = LIRKind.reference(Kind.Object);
+
+    private S currentSet;
+
+    /**
+     * Process all values of an instruction bottom-up, i.e. definitions before usages. Values that
+     * start or end at the current operation are not included.
+     */
+    private void processInstructionBottomUp(LIRInstruction op) {
+        try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
+            // kills
+
+            op.visitEachTemp(defConsumer);
+            op.visitEachOutput(defConsumer);
+            if (frameMap != null && op.destroysCallerSavedRegisters()) {
+                for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
+                    defConsumer.visitValue(reg.asValue(REFERENCE_KIND), OperandMode.TEMP, REGISTER_FLAG_SET);
+                }
+            }
+
+            // gen - values that are considered alive for this state
+            op.visitEachAlive(useConsumer);
+            op.visitEachState(useConsumer);
+            // mark locations
+            op.forEachState(stateConsumer);
+            // gen
+            op.visitEachInput(useConsumer);
+        }
+    }
+
+    InstructionStateProcedure stateConsumer = new InstructionStateProcedure() {
+        public void doState(LIRInstruction inst, LIRFrameState info) {
+            processState(inst, info, currentSet);
+        }
+    };
+
+    ValueConsumer useConsumer = new ValueConsumer() {
+        public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (shouldProcessValue(operand)) {
+                // no need to insert values and derived reference
+                if (Debug.isLogEnabled()) {
+                    Debug.log("set operand: %s", operand);
+                }
+                currentSet.put(operand);
+            }
+        }
+    };
+
+    ValueConsumer defConsumer = new ValueConsumer() {
+        public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (shouldProcessValue(operand)) {
+                if (Debug.isLogEnabled()) {
+                    Debug.log("clear operand: %s", operand);
+                }
+                currentSet.remove(operand);
+            } else {
+                assert isIllegal(operand) || operand.getPlatformKind() != Kind.Illegal || mode == OperandMode.TEMP : String.format("Illegal PlatformKind is only allowed for TEMP mode: %s, %s",
+                                operand, mode);
+            }
+        }
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarkerPhase.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,194 @@
+/*
+ * 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 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.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.phases.*;
+
+/**
+ * Mark all live references for a frame state. The frame state use this information to build the OOP
+ * maps.
+ */
+public final class LocationMarkerPhase extends AllocationPhase {
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        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);
+                    }
+                }
+            }
+        }
+
+        private final RegisterAttributes[] registerAttributes;
+
+        private Marker(LIR lir, FrameMap frameMap) {
+            super(lir, frameMap);
+            this.registerAttributes = frameMap.getRegisterConfig().getAttributesMap();
+        }
+
+        @Override
+        protected Marker<T>.RegStackValueSet newLiveValueSet() {
+            return new RegStackValueSet();
+        }
+
+        @Override
+        protected boolean shouldProcessValue(Value operand) {
+            return (isRegister(operand) && attributes(asRegister(operand)).isAllocatable() || isStackSlot(operand)) && operand.getPlatformKind() != Kind.Illegal;
+        }
+
+        /**
+         * This method does the actual marking.
+         */
+        @Override
+        protected void processState(LIRInstruction op, LIRFrameState info, RegStackValueSet values) {
+            if (!info.hasDebugInfo()) {
+                info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !frameMap.getRegisterConfig().areAllAllocatableRegistersCallerSaved());
+            }
+
+            ReferenceMapBuilder refMap = frameMap.newReferenceMapBuilder();
+            frameMap.addLiveValues(refMap);
+            values.addLiveValues(refMap);
+
+            info.debugInfo().setReferenceMap(refMap.finish(info));
+        }
+
+        /**
+         * Gets an object describing the attributes of a given register according to this register
+         * configuration.
+         */
+        private RegisterAttributes attributes(Register reg) {
+            return registerAttributes[reg.number];
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/MarkBasePointersPhase.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,121 @@
+/*
+ * 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 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.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.phases.*;
+
+/**
+ * Record all derived reference base pointers in a frame state.
+ */
+public final class MarkBasePointersPhase extends AllocationPhase {
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        new Marker<B>(lirGenRes.getLIR(), null).build();
+    }
+
+    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 ValueSet variables;
+
+            public BasePointersSet() {
+                variables = new ValueSet();
+            }
+
+            private BasePointersSet(BasePointersSet s) {
+                variables = new ValueSet(s.variables);
+            }
+
+            @Override
+            public Marker<T>.BasePointersSet copy() {
+                return new BasePointersSet(this);
+            }
+
+            @Override
+            public void put(Value v) {
+                Variable base = (Variable) v.getLIRKind().getDerivedReferenceBase();
+                variables.put(base.index, base);
+            }
+
+            @Override
+            public void putAll(BasePointersSet v) {
+                variables.putAll(v.variables);
+            }
+
+            @Override
+            public void remove(Value v) {
+                Variable base = (Variable) v.getLIRKind().getDerivedReferenceBase();
+                variables.put(base.index, null);
+            }
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public boolean equals(Object obj) {
+                if (obj instanceof Marker.BasePointersSet) {
+                    BasePointersSet other = (BasePointersSet) obj;
+                    return variables.equals(other.variables);
+                } else {
+                    return false;
+                }
+            }
+
+            @Override
+            public int hashCode() {
+                throw new UnsupportedOperationException();
+            }
+        }
+
+        private Marker(LIR lir, FrameMap frameMap) {
+            super(lir, frameMap);
+        }
+
+        @Override
+        protected Marker<T>.BasePointersSet newLiveValueSet() {
+            return new BasePointersSet();
+        }
+
+        @Override
+        protected boolean shouldProcessValue(Value operand) {
+            return operand.getLIRKind().isDerivedReference();
+        }
+
+        @Override
+        protected void processState(LIRInstruction op, LIRFrameState info, BasePointersSet values) {
+            info.setLiveBasePointers(new ValueSet(values.variables));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/UniqueWorkList.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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 com.oracle.graal.compiler.common.cfg.*;
+
+/**
+ * Ensures that an element is only in the worklist once.
+ *
+ * @param <T>
+ */
+class UniqueWorkList<T extends AbstractBlockBase<T>> extends ArrayDeque<T> {
+    private static final long serialVersionUID = 8009554570990975712L;
+    BitSet valid;
+
+    public UniqueWorkList(int size) {
+        this.valid = new BitSet(size);
+    }
+
+    @Override
+    public T poll() {
+        T result = super.poll();
+        if (result != null) {
+            valid.set(result.getId(), false);
+        }
+        return result;
+    }
+
+    @Override
+    public boolean add(T pred) {
+        if (!valid.get(pred.getId())) {
+            valid.set(pred.getId(), true);
+            return super.add(pred);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends T> collection) {
+        boolean changed = false;
+        for (T element : collection) {
+            if (!valid.get(element.getId())) {
+                valid.set(element.getId(), true);
+                super.add(element);
+                changed = true;
+            }
+        }
+        return changed;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/ValueSet.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,175 @@
+/*
+ * 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();
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMap.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMap.java	Tue Jul 21 16:17:54 2015 +0200
@@ -42,6 +42,13 @@
     private final TargetDescription target;
     private final RegisterConfig registerConfig;
 
+    public interface ReferenceMapBuilderFactory {
+
+        ReferenceMapBuilder newReferenceMapBuilder(int totalFrameSize);
+    }
+
+    private final ReferenceMapBuilderFactory referenceMapFactory;
+
     /**
      * The final frame size, not including the size of the
      * {@link Architecture#getReturnAddressSize() return address slot}. The value is only set after
@@ -86,12 +93,13 @@
      * Creates a new frame map for the specified method. The given registerConfig is optional, in
      * case null is passed the default RegisterConfig from the CodeCacheProvider will be used.
      */
-    public FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig) {
+    public FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) {
         this.target = codeCache.getTarget();
         this.registerConfig = registerConfig == null ? codeCache.getRegisterConfig() : registerConfig;
         this.frameSize = -1;
         this.outgoingSize = codeCache.getMinimumOutgoingSize();
         this.objectStackSlots = new ArrayList<>();
+        this.referenceMapFactory = referenceMapFactory;
     }
 
     public RegisterConfig getRegisterConfig() {
@@ -102,7 +110,7 @@
         return target;
     }
 
-    public void addLiveValues(ReferenceMap refMap) {
+    public void addLiveValues(ReferenceMapBuilder refMap) {
         for (Value value : objectStackSlots) {
             refMap.addLiveValue(value);
         }
@@ -319,8 +327,7 @@
         objectStackSlots.add(objectSlot);
     }
 
-    public ReferenceMap initReferenceMap(boolean hasRegisters) {
-        ReferenceMap refMap = getTarget().createReferenceMap(hasRegisters, frameSize() / getTarget().wordSize, totalFrameSize());
-        return refMap;
+    public ReferenceMapBuilder newReferenceMapBuilder() {
+        return referenceMapFactory.newReferenceMapBuilder(totalFrameSize());
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/ReferenceMapBuilder.java	Tue Jul 21 16:17:54 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.framemap;
+
+import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.lir.*;
+
+public abstract class ReferenceMapBuilder {
+
+    public abstract void addLiveValue(Value value);
+
+    public abstract ReferenceMap finish(LIRFrameState state);
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Jul 21 16:17:54 2015 +0200
@@ -397,7 +397,7 @@
         } else if (base.getLIRKind().isReference(0) && displacement == 0L && index.equals(Value.ILLEGAL)) {
             return LIRKind.reference(target().wordKind);
         } else {
-            return LIRKind.derivedReference(target().wordKind);
+            return LIRKind.unknownReference(target().wordKind);
         }
     }
 
@@ -420,4 +420,90 @@
     public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
         throw JVMCIError.unimplemented();
     }
+
+    // automatic derived reference handling
+
+    protected abstract Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags);
+
+    public final Variable emitAdd(Value aVal, Value bVal, boolean setFlags) {
+        LIRKind resultKind;
+        Value a = aVal;
+        Value b = bVal;
+
+        if (a.getKind().isNumericInteger()) {
+            LIRKind aKind = a.getLIRKind();
+            LIRKind bKind = b.getLIRKind();
+            assert a.getPlatformKind() == b.getPlatformKind();
+
+            if (aKind.isUnknownReference()) {
+                resultKind = aKind;
+            } else if (bKind.isUnknownReference()) {
+                resultKind = bKind;
+            } else if (aKind.isValue() && bKind.isValue()) {
+                resultKind = aKind;
+            } else if (aKind.isValue()) {
+                if (bKind.isDerivedReference()) {
+                    resultKind = bKind;
+                } else {
+                    AllocatableValue allocatable = asAllocatable(b);
+                    resultKind = bKind.makeDerivedReference(allocatable);
+                    b = allocatable;
+                }
+            } else if (bKind.isValue()) {
+                if (aKind.isDerivedReference()) {
+                    resultKind = aKind;
+                } else {
+                    AllocatableValue allocatable = asAllocatable(a);
+                    resultKind = aKind.makeDerivedReference(allocatable);
+                    a = allocatable;
+                }
+            } else {
+                resultKind = aKind.makeUnknownReference();
+            }
+        } else {
+            resultKind = LIRKind.combine(a, b);
+        }
+
+        return emitAdd(resultKind, a, b, setFlags);
+    }
+
+    protected abstract Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags);
+
+    public final Variable emitSub(Value aVal, Value bVal, boolean setFlags) {
+        LIRKind resultKind;
+        Value a = aVal;
+        Value b = bVal;
+
+        if (a.getKind().isNumericInteger()) {
+            LIRKind aKind = a.getLIRKind();
+            LIRKind bKind = b.getLIRKind();
+            assert a.getPlatformKind() == b.getPlatformKind();
+
+            if (aKind.isUnknownReference()) {
+                resultKind = aKind;
+            } else if (bKind.isUnknownReference()) {
+                resultKind = bKind;
+            }
+
+            if (aKind.isValue() && bKind.isValue()) {
+                resultKind = aKind;
+            } else if (bKind.isValue()) {
+                if (aKind.isDerivedReference()) {
+                    resultKind = aKind;
+                } else {
+                    AllocatableValue allocatable = asAllocatable(a);
+                    resultKind = aKind.makeDerivedReference(allocatable);
+                    a = allocatable;
+                }
+            } else if (aKind.isDerivedReference() && bKind.isDerivedReference() && aKind.getDerivedReferenceBase().equals(bKind.getDerivedReferenceBase())) {
+                resultKind = LIRKind.value(a.getPlatformKind());
+            } else {
+                resultKind = aKind.makeUnknownReference();
+            }
+        } else {
+            resultKind = LIRKind.combine(a, b);
+        }
+
+        return emitSub(resultKind, a, b, setFlags);
+    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationStage.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationStage.java	Tue Jul 21 16:17:54 2015 +0200
@@ -23,11 +23,13 @@
 package com.oracle.graal.lir.phases;
 
 import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.dfa.*;
 import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext;
 import com.oracle.graal.lir.stackslotalloc.*;
 
 public class AllocationStage extends LIRPhaseSuite<AllocationContext> {
     public AllocationStage() {
+        appendPhase(new MarkBasePointersPhase());
         appendPhase(new LinearScanPhase());
 
         // build frame map
@@ -37,6 +39,6 @@
             appendPhase(new SimpleStackSlotAllocator());
         }
         // currently we mark locations only if we do register allocation
-        appendPhase(new LocationMarker());
+        appendPhase(new LocationMarkerPhase());
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/EconomyAllocationStage.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/EconomyAllocationStage.java	Tue Jul 21 16:17:54 2015 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.lir.phases;
 
 import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.dfa.*;
 import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext;
 import com.oracle.graal.lir.stackslotalloc.*;
 
@@ -34,6 +35,6 @@
         appendPhase(new SimpleStackSlotAllocator());
 
         // currently we mark locations only if we do register allocation
-        appendPhase(new LocationMarker());
+        appendPhase(new LocationMarkerPhase());
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PostAllocationOptimizationStage.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PostAllocationOptimizationStage.java	Tue Jul 21 16:17:54 2015 +0200
@@ -35,7 +35,7 @@
         @Option(help = "", type = OptionType.Debug)
         public static final NestedBooleanOptionValue LIROptEdgeMoveOptimizer = new NestedBooleanOptionValue(LIROptimization, true);
         @Option(help = "", type = OptionType.Debug)
-        public static final NestedBooleanOptionValue LIROptControlFlowOptmizer = new NestedBooleanOptionValue(LIROptimization, true);
+        public static final NestedBooleanOptionValue LIROptControlFlowOptimizer = new NestedBooleanOptionValue(LIROptimization, true);
         @Option(help = "", type = OptionType.Debug)
         public static final NestedBooleanOptionValue LIROptRedundantMoveElimination = new NestedBooleanOptionValue(LIROptimization, true);
         @Option(help = "", type = OptionType.Debug)
@@ -51,7 +51,7 @@
         if (Options.LIROptEdgeMoveOptimizer.getValue()) {
             appendPhase(new EdgeMoveOptimizer());
         }
-        if (Options.LIROptControlFlowOptmizer.getValue()) {
+        if (Options.LIROptControlFlowOptimizer.getValue()) {
             appendPhase(new ControlFlowOptimizer());
         }
         if (Options.LIROptRedundantMoveElimination.getValue()) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSAUtils.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSAUtils.java	Tue Jul 21 16:17:54 2015 +0200
@@ -141,7 +141,7 @@
         for (AbstractBlockBase<?> pred : merge.getPredecessors()) {
             forEachPhiValuePair(lir, merge, pred, (phiIn, phiOut) -> {
                 assert phiIn.getLIRKind().equals(phiOut.getLIRKind()) ||
-                                (phiIn.getPlatformKind().equals(phiOut.getPlatformKind()) && phiIn.getLIRKind().isDerivedReference() && phiOut.getLIRKind().isValue());
+                                (phiIn.getPlatformKind().equals(phiOut.getPlatformKind()) && phiIn.getLIRKind().isUnknownReference() && phiOut.getLIRKind().isValue());
             });
         }
     }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Tue Jul 21 16:17:54 2015 +0200
@@ -133,14 +133,17 @@
             stride = IntegerConvertNode.convert(stride, stamp, graph());
             initNode = IntegerConvertNode.convert(initNode, stamp, graph());
         }
-        ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount, stride, initNode);
+        ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount);
+        if (!maxTripCount.stamp().isCompatible(stamp)) {
+            maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph());
+        }
         return add(graph, mul(graph, stride, sub(graph, maxTripCount, ConstantNode.forIntegerStamp(stamp, 1, graph))), initNode);
     }
 
     @Override
     public ValueNode exitValueNode() {
         Stamp stamp = phi.stamp();
-        ValueNode maxTripCount = loop.counted().maxTripCountNode();
+        ValueNode maxTripCount = loop.counted().maxTripCountNode(false);
         if (!maxTripCount.stamp().isCompatible(stamp)) {
             maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph());
         }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Tue Jul 21 16:17:54 2015 +0200
@@ -49,12 +49,13 @@
     }
 
     public ValueNode maxTripCountNode() {
-        return maxTripCountNode(false, iv.strideNode(), iv.initNode());
+        return maxTripCountNode(false);
     }
 
-    public ValueNode maxTripCountNode(boolean assumePositive, ValueNode strideNode, ValueNode initNode) {
+    public ValueNode maxTripCountNode(boolean assumePositive) {
         StructuredGraph graph = iv.valueNode().graph();
-        Stamp stamp = strideNode.stamp();
+        Stamp stamp = iv.valueNode().stamp();
+        ValueNode range = sub(graph, end, iv.initNode());
 
         ValueNode oneDirection;
         if (iv.direction() == Direction.Up) {
@@ -63,19 +64,12 @@
             assert iv.direction() == Direction.Down;
             oneDirection = ConstantNode.forIntegerStamp(stamp, -1, graph);
         }
-        ValueNode endNode;
-        if (!end.stamp().isCompatible(stamp)) {
-            endNode = IntegerConvertNode.convert(end, stamp, graph);
-        } else {
-            endNode = end;
-        }
-        ValueNode range = sub(graph, endNode, initNode);
         if (oneOff) {
             range = add(graph, range, oneDirection);
         }
         // round-away-from-zero divison: (range + stride -/+ 1) / stride
-        ValueNode denominator = add(graph, sub(graph, range, oneDirection), strideNode);
-        ValueNode div = divBefore(graph, loop.entryPoint(), denominator, strideNode);
+        ValueNode denominator = add(graph, sub(graph, range, oneDirection), iv.strideNode());
+        ValueNode div = divBefore(graph, loop.entryPoint(), denominator, iv.strideNode());
 
         if (assumePositive) {
             return div;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CanonicalizableLocation.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.memory.address.*;
+
+public interface CanonicalizableLocation {
+    ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -106,6 +106,23 @@
         if (stamp().equals(object().stamp())) {
             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;
+                        }
+                    }
+                }
+            }
+        }
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -25,13 +25,15 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 /**
  * Value {@link PhiNode}s merge data flow values at control flow merges.
  */
 @NodeInfo(nameTemplate = "Phi({i#values})")
-public class ValuePhiNode extends PhiNode {
+public class ValuePhiNode extends PhiNode implements ArrayLengthProvider {
 
     public static final NodeClass<ValuePhiNode> TYPE = NodeClass.create(ValuePhiNode.class);
     @Input protected NodeInputList<ValueNode> values;
@@ -65,4 +67,23 @@
         }
         return updateStamp(valuesStamp);
     }
+
+    public ValueNode length() {
+        if (merge() instanceof LoopBeginNode) {
+            return null;
+        }
+        ValueNode length = null;
+        for (ValueNode input : values()) {
+            ValueNode l = GraphUtil.arrayLength(input);
+            if (l == null) {
+                return null;
+            }
+            if (length == null) {
+                length = l;
+            } else if (length != l) {
+                return null;
+            }
+        }
+        return length;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AbsNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AbsNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -55,7 +55,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitMathAbs(builder.operand(getValue())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitMathAbs(nodeValueMap.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -109,15 +109,15 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value op1 = builder.operand(getX());
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        Value op1 = nodeValueMap.operand(getX());
         assert op1 != null : getX() + ", this=" + this;
-        Value op2 = builder.operand(getY());
-        if (!getY().isConstant() && !BinaryArithmeticNode.livesLonger(this, getY(), builder)) {
+        Value op2 = nodeValueMap.operand(getY());
+        if (!getY().isConstant() && !BinaryArithmeticNode.livesLonger(this, getY(), nodeValueMap)) {
             Value tmp = op1;
             op1 = op2;
             op2 = tmp;
         }
-        builder.setResult(this, gen.emitAdd(op1, op2, false));
+        nodeValueMap.setResult(this, gen.emitAdd(op1, op2, false));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -101,7 +101,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitAnd(builder.operand(getX()), builder.operand(getY())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitAnd(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -245,9 +245,9 @@
         }
     }
 
-    protected static boolean livesLonger(ValueNode after, ValueNode value, NodeMappableLIRBuilder builder) {
+    protected static boolean livesLonger(ValueNode after, ValueNode value, NodeValueMap nodeValueMap) {
         for (Node usage : value.usages()) {
-            if (usage != after && usage instanceof ValueNode && builder.hasOperand(usage)) {
+            if (usage != after && usage instanceof ValueNode && nodeValueMap.hasOperand(usage)) {
                 return true;
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/DivNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/DivNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -91,7 +91,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitDiv(builder.operand(getX()), builder.operand(getY()), null));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitDiv(nodeValueMap.operand(getX()), nodeValueMap.operand(getY()), null));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -113,7 +113,7 @@
         tool.getLowerer().lower(this, tool);
     }
 
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitFloatConvert(getFloatConvert(), builder.operand(getValue())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitFloatConvert(getFloatConvert(), nodeValueMap.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -85,7 +85,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitShl(builder.operand(getX()), builder.operand(getY())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitShl(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/MulNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/MulNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -93,14 +93,14 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value op1 = builder.operand(getX());
-        Value op2 = builder.operand(getY());
-        if (!getY().isConstant() && !BinaryArithmeticNode.livesLonger(this, getY(), builder)) {
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        Value op1 = nodeValueMap.operand(getX());
+        Value op2 = nodeValueMap.operand(getY());
+        if (!getY().isConstant() && !BinaryArithmeticNode.livesLonger(this, getY(), nodeValueMap)) {
             Value tmp = op1;
             op1 = op2;
             op2 = tmp;
         }
-        builder.setResult(this, gen.emitMul(op1, op2, false));
+        nodeValueMap.setResult(this, gen.emitMul(op1, op2, false));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -108,7 +108,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitNarrow(builder.operand(getValue()), getResultBits()));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitNarrow(nodeValueMap.operand(getValue()), getResultBits()));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -60,7 +60,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitNegate(builder.operand(getValue())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitNegate(nodeValueMap.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -56,7 +56,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitNot(builder.operand(getValue())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitNot(nodeValueMap.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -89,7 +89,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitOr(builder.operand(getX()), builder.operand(getY())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitOr(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -83,9 +83,9 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
         LIRKind kind = gen.getLIRKind(stamp());
-        builder.setResult(this, gen.emitReinterpret(kind, builder.operand(getValue())));
+        nodeValueMap.setResult(this, gen.emitReinterpret(kind, nodeValueMap.operand(getValue())));
     }
 
     public static ValueNode reinterpret(Kind toKind, ValueNode value) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RemNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RemNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -45,7 +45,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitRem(builder.operand(getX()), builder.operand(getY()), null));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitRem(nodeValueMap.operand(getX()), nodeValueMap.operand(getY()), null));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -97,8 +97,8 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitShr(builder.operand(getX()), builder.operand(getY())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitShr(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -103,7 +103,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitSignExtend(builder.operand(getValue()), getInputBits(), getResultBits()));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitSignExtend(nodeValueMap.operand(getValue()), getInputBits(), getResultBits()));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -43,7 +43,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitMathSqrt(builder.operand(getValue())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitMathSqrt(nodeValueMap.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SubNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SubNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -151,7 +151,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitSub(builder.operand(getX()), builder.operand(getY()), false));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitSub(nodeValueMap.operand(getX()), nodeValueMap.operand(getY()), false));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -85,8 +85,8 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitUShr(builder.operand(getX()), builder.operand(getY())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitUShr(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -90,7 +90,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitXor(builder.operand(getX()), builder.operand(getY())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitXor(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -116,7 +116,7 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitZeroExtend(builder.operand(getValue()), getInputBits(), getResultBits()));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitZeroExtend(nodeValueMap.operand(getValue()), getInputBits(), getResultBits()));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -82,7 +82,7 @@
         VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind);
         assert newVirtual.getFields().length == 1;
 
-        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, Collections.<MonitorIdNode> emptyList());
+        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, Collections.<MonitorIdNode> emptyList(), false);
         tool.replaceWithVirtual(newVirtual);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -67,7 +67,7 @@
         this(hubStamp(stampProvider, value), value, guard);
     }
 
-    public LoadHubNode(Stamp stamp, ValueNode value, ValueNode guard) {
+    private LoadHubNode(Stamp stamp, ValueNode value, ValueNode guard) {
         super(TYPE, stamp, (GuardingNode) guard);
         assert value != guard;
         this.value = value;
@@ -75,9 +75,6 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
-            return;
-        }
         tool.getLowerer().lower(this, tool);
     }
 
@@ -92,10 +89,18 @@
         return this;
     }
 
-    private static ValueNode findSynonym(ValueNode curValue, Stamp stamp, StructuredGraph graph, MetaAccessProvider metaAccess) {
+    public static ValueNode findSynonym(ValueNode curValue, Stamp stamp, StructuredGraph graph, MetaAccessProvider metaAccess) {
+        ResolvedJavaType exactType = findSynonymType(graph, metaAccess, curValue);
+        if (exactType != null) {
+            return ConstantNode.forConstant(stamp, exactType.getObjectHub(), metaAccess);
+        }
+        return null;
+    }
+
+    public static ResolvedJavaType findSynonymType(StructuredGraph graph, MetaAccessProvider metaAccess, ValueNode curValue) {
+        ResolvedJavaType exactType = null;
         if (metaAccess != null && curValue.stamp() instanceof ObjectStamp) {
             ObjectStamp objectStamp = (ObjectStamp) curValue.stamp();
-            ResolvedJavaType exactType = null;
             if (objectStamp.isExactType()) {
                 exactType = objectStamp.type();
             } else if (objectStamp.type() != null && graph != null && graph.getAssumptions() != null) {
@@ -105,12 +110,8 @@
                     graph.getAssumptions().record(leafConcreteSubtype);
                 }
             }
-
-            if (exactType != null) {
-                return ConstantNode.forConstant(stamp, exactType.getObjectHub(), metaAccess);
-            }
         }
-        return null;
+        return exactType;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -47,12 +47,25 @@
      */
     protected final Kind knownElementKind;
 
-    public DynamicNewArrayNode(ValueNode elementType, ValueNode length, boolean fillContents, Kind knownElementKind) {
-        this(TYPE, elementType, length, fillContents, knownElementKind, null);
+    public DynamicNewArrayNode(ValueNode elementType, ValueNode length, boolean fillContents) {
+        this(TYPE, elementType, length, fillContents, null, null, null);
+    }
+
+    public DynamicNewArrayNode(@InjectedNodeParameter MetaAccessProvider metaAccess, ValueNode elementType, ValueNode length, boolean fillContents, Kind knownElementKind) {
+        this(TYPE, elementType, length, fillContents, knownElementKind, null, metaAccess);
     }
 
-    protected DynamicNewArrayNode(NodeClass<? extends DynamicNewArrayNode> c, ValueNode elementType, ValueNode length, boolean fillContents, Kind knownElementKind, FrameState stateBefore) {
-        super(c, StampFactory.objectNonNull(), length, fillContents, stateBefore);
+    private static Stamp computeStamp(Kind knownElementKind, MetaAccessProvider metaAccess) {
+        if (knownElementKind != null && metaAccess != null) {
+            ResolvedJavaType arrayType = metaAccess.lookupJavaType(knownElementKind == Kind.Object ? Object.class : knownElementKind.toJavaClass()).getArrayClass();
+            return StampFactory.declaredNonNull(arrayType);
+        }
+        return StampFactory.objectNonNull();
+    }
+
+    protected DynamicNewArrayNode(NodeClass<? extends DynamicNewArrayNode> c, ValueNode elementType, ValueNode length, boolean fillContents, Kind knownElementKind, FrameState stateBefore,
+                    MetaAccessProvider metaAccess) {
+        super(c, computeStamp(knownElementKind, metaAccess), length, fillContents, stateBefore);
         this.elementType = elementType;
         this.knownElementKind = knownElementKind;
         assert knownElementKind != Kind.Void && knownElementKind != Kind.Illegal;
@@ -102,6 +115,10 @@
     @NodeIntrinsic
     private static native Object newArray(Class<?> componentType, int length, @ConstantNodeParameter boolean fillContents, @ConstantNodeParameter Kind knownElementKind);
 
+    public static Object newArray(Class<?> componentType, int length, Kind knownElementKind) {
+        return newArray(componentType, length, true, knownElementKind);
+    }
+
     public static Object newUninitializedArray(Class<?> componentType, int length, Kind knownElementKind) {
         return newArray(componentType, length, false, knownElementKind);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -84,7 +84,7 @@
                     state[i] = defaultForKind;
                 }
                 VirtualObjectNode virtualObject = createVirtualArrayNode(constantLength);
-                tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList());
+                tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList(), false);
                 tool.replaceWithVirtual(virtualObject);
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -79,7 +79,7 @@
             for (int i = 0; i < state.length; i++) {
                 state[i] = defaultFieldValue(fields[i]);
             }
-            tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList());
+            tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList(), false);
             tool.replaceWithVirtual(virtualObject);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -104,7 +104,7 @@
                 return LogicConstantNode.tautology();
             }
         } else {
-            if (exactType) {
+            if (exactType || !inputType.isAssignableFrom(type)) {
                 // since this type check failed for an exact type we know that it can never
                 // succeed at run time. we also don't care about null values, since they will
                 // also make the check fail.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/ReadNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/ReadNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -133,6 +133,13 @@
                     return length;
                 }
             }
+            if (locationIdentity instanceof CanonicalizableLocation) {
+                CanonicalizableLocation canonicalize = (CanonicalizableLocation) locationIdentity;
+                ValueNode result = canonicalize.canonicalizeRead(read, address, object, tool);
+                assert result != null && result.stamp().isCompatible(read.stamp());
+                return result;
+            }
+
         }
         return read;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRLowerable.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRLowerable.java	Tue Jul 21 16:17:54 2015 +0200
@@ -28,5 +28,5 @@
 
 public interface ArithmeticLIRLowerable extends ArithmeticOperation {
 
-    void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen);
+    void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Tue Jul 21 16:17:54 2015 +0200
@@ -37,7 +37,7 @@
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 
-public interface NodeLIRBuilderTool extends NodeMappableLIRBuilder {
+public interface NodeLIRBuilderTool extends NodeValueMap {
 
     // TODO (je) remove and move into the Node
     LIRFrameState state(DeoptimizingNode deopt);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeMappableLIRBuilder.java	Tue Jul 21 15:16:00 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2014, 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.nodes.spi;
-
-import jdk.internal.jvmci.meta.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-
-public interface NodeMappableLIRBuilder {
-
-    Value operand(Node object);
-
-    boolean hasOperand(Node object);
-
-    Value setResult(ValueNode x, Value operand);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeValueMap.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, 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.nodes.spi;
+
+import jdk.internal.jvmci.meta.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+public interface NodeValueMap {
+
+    /**
+     * Returns the operand that has been previously initialized by
+     * {@link #setResult(ValueNode, Value)} with the result of an instruction. It's a code
+     * generation error to ask for the operand of ValueNode that doesn't have one yet.
+     *
+     * @param node A node that produces a result value.
+     */
+    Value operand(Node node);
+
+    /**
+     * @return {@code true} if there is an {@link Value operand} associated with the {@code node} in
+     *         the current block.
+     */
+    boolean hasOperand(Node node);
+
+    /**
+     * Associates {@code operand} with the {@code node} in the current block.
+     *
+     * @return {@code operand}
+     */
+    Value setResult(ValueNode node, Value operand);
+
+    /**
+     * Gets the the {@link ValueNode} that produced a {@code value}. If the {@code value} is not
+     * associated with a {@link ValueNode} {@code null} is returned.
+     *
+     * This method is intended for debugging purposes only.
+     */
+    ValueNode valueForOperand(Value value);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/StampProvider.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/StampProvider.java	Tue Jul 21 16:17:54 2015 +0200
@@ -36,6 +36,11 @@
     Stamp createHubStamp(ObjectStamp object);
 
     /**
+     * Create the stamp of a possibly null hub.
+     */
+    Stamp createHubStamp(boolean nonNull);
+
+    /**
      * Create the stamp of a pointer to a method.
      */
     Stamp createMethodStamp();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Tue Jul 21 16:17:54 2015 +0200
@@ -52,6 +52,10 @@
         public abstract MonitorIdNode removeLock();
 
         public abstract ValueNode getMaterializedValue();
+
+        public abstract void setEnsureVirtualized(boolean ensureVirtualized);
+
+        public abstract boolean getEnsureVirtualized();
     }
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Tue Jul 21 16:17:54 2015 +0200
@@ -67,8 +67,9 @@
      * @param virtualObject the new virtual object.
      * @param entryState the initial state of the virtual object's fields.
      * @param locks the initial locking depths.
+     * @param ensureVirtualized true if this object needs to stay virtual
      */
-    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks);
+    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
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -36,10 +36,12 @@
 public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Simplifiable {
 
     public static final NodeClass<CommitAllocationNode> TYPE = NodeClass.create(CommitAllocationNode.class);
+
     @Input NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this);
     @Input NodeInputList<ValueNode> values = new NodeInputList<>(this);
     @Input(InputType.Association) NodeInputList<MonitorIdNode> locks = new NodeInputList<>(this);
     protected ArrayList<Integer> lockIndexes = new ArrayList<>(Arrays.asList(0));
+    protected ArrayList<Boolean> ensureVirtual = new ArrayList<>();
 
     public CommitAllocationNode() {
         super(TYPE, StampFactory.forVoid());
@@ -57,6 +59,10 @@
         return locks.subList(lockIndexes.get(objIndex), lockIndexes.get(objIndex + 1));
     }
 
+    public List<Boolean> getEnsureVirtual() {
+        return ensureVirtual;
+    }
+
     @Override
     public boolean verify() {
         assertTrue(virtualObjects.size() + 1 == lockIndexes.size(), "lockIndexes size doesn't match " + virtualObjects + ", " + lockIndexes);
@@ -66,11 +72,17 @@
             valueCount += virtual.entryCount();
         }
         assertTrue(values.size() == valueCount, "values size doesn't match");
+        assertTrue(virtualObjects.size() == ensureVirtual.size(), "ensureVirtual size doesn't match");
         return super.verify();
     }
 
     @Override
     public void lower(LoweringTool tool) {
+        for (int i = 0; i < virtualObjects.size(); i++) {
+            if (ensureVirtual.get(i)) {
+                EnsureVirtualizedNode.ensureVirtualFailure(this, virtualObjects.get(i).stamp());
+            }
+        }
         tool.getLowerer().lower(this, tool);
     }
 
@@ -90,7 +102,7 @@
         for (int i = 0; i < virtualObjects.size(); i++) {
             VirtualObjectNode virtualObject = virtualObjects.get(i);
             int entryCount = virtualObject.entryCount();
-            tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), getLocks(i));
+            tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), getLocks(i), ensureVirtual.get(i));
             pos += entryCount;
         }
         tool.delete();
@@ -166,6 +178,7 @@
             List<VirtualObjectNode> newVirtualObjects = new ArrayList<>(usedCount);
             List<MonitorIdNode> newLocks = new ArrayList<>(usedCount);
             ArrayList<Integer> newLockIndexes = new ArrayList<>(usedCount + 1);
+            ArrayList<Boolean> newEnsureVirtual = new ArrayList<>(usedCount);
             newLockIndexes.add(0);
             List<ValueNode> newValues = new ArrayList<>();
             int valuePos = 0;
@@ -176,6 +189,7 @@
                     newLocks.addAll(getLocks(objIndex));
                     newLockIndexes.add(newLocks.size());
                     newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount()));
+                    newEnsureVirtual.add(ensureVirtual.get(objIndex));
                 }
                 valuePos += virtualObject.entryCount();
             }
@@ -186,6 +200,7 @@
             values.clear();
             values.addAll(newValues);
             lockIndexes = newLockIndexes;
+            ensureVirtual = newEnsureVirtual;
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,68 @@
+/*
+ * 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.nodes.virtual;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
+
+@NodeInfo
+public final class EnsureVirtualizedNode extends FixedWithNextNode implements Virtualizable, Lowerable {
+
+    public static final NodeClass<EnsureVirtualizedNode> TYPE = NodeClass.create(EnsureVirtualizedNode.class);
+
+    @Input ValueNode object;
+    private final boolean localOnly;
+
+    public EnsureVirtualizedNode(ValueNode object, boolean localOnly) {
+        super(TYPE, StampFactory.forVoid());
+        this.object = object;
+        this.localOnly = localOnly;
+    }
+
+    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());
+                throw GraphUtil.approxSourceException(this, exception);
+            }
+            if (!localOnly) {
+                state.setEnsureVirtualized(true);
+            }
+            tool.delete();
+        }
+    }
+
+    public void lower(LoweringTool tool) {
+        ensureVirtualFailure(this, object.stamp());
+    }
+
+    public static void ensureVirtualFailure(Node location, Stamp stamp) {
+        Throwable exception = new VerificationError("Object should not be materialized (stamp=%s):", stamp);
+        throw GraphUtil.approxSourceException(location, exception);
+    }
+}
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Jul 21 16:17:54 2015 +0200
@@ -314,7 +314,7 @@
         out.print("tid ").print(nodeToString(node)).println(COLUMN_END);
 
         if (nodeLirGenerator != null) {
-            Value operand = nodeLirGenerator.getNodeOperands().get(node);
+            Value operand = nodeLirGenerator.hasOperand(node) ? nodeLirGenerator.operand(node) : null;
             if (operand != null) {
                 out.print("result ").print(operand.toString()).println(COLUMN_END);
             }
@@ -418,11 +418,10 @@
 
     private String stateValueToString(ValueNode value) {
         String result = nodeToString(value);
-        if (nodeLirGenerator != null && nodeLirGenerator.getNodeOperands() != null && value != null) {
-            Value operand = nodeLirGenerator.getNodeOperands().get(value);
-            if (operand != null) {
-                result += ": " + operand;
-            }
+        if (nodeLirGenerator != null && value != null && nodeLirGenerator.hasOperand(value)) {
+            Value operand = nodeLirGenerator.operand(value);
+            assert operand != null;
+            result += ": " + operand;
         }
         return result;
     }
@@ -456,9 +455,9 @@
                 inst.forEachState(state -> {
                     if (state.hasDebugInfo()) {
                         DebugInfo di = state.debugInfo();
-                        stateString.append(debugInfoToString(di.getBytecodePosition(), di.getReferenceMap(), di.getCalleeSaveInfo()));
+                        stateString.append(debugInfoToString(di.getBytecodePosition(), di.getReferenceMap(), state.getLiveBasePointers(), di.getCalleeSaveInfo()));
                     } else {
-                        stateString.append(debugInfoToString(state.topFrame, null, null));
+                        stateString.append(debugInfoToString(state.topFrame, null, state.getLiveBasePointers(), null));
                     }
                 });
                 if (stateString.length() > 0) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java	Tue Jul 21 16:17:54 2015 +0200
@@ -29,6 +29,8 @@
 import jdk.internal.jvmci.debug.*;
 import jdk.internal.jvmci.meta.*;
 
+import com.oracle.graal.lir.dfa.*;
+
 /**
  * Utility for printing compilation related data structures at various compilation phases. The
  * output format is such that it can then be fed to the <a
@@ -112,12 +114,18 @@
     /**
      * Formats given debug info as a multi line string.
      */
-    protected String debugInfoToString(BytecodePosition codePos, ReferenceMap refMap, RegisterSaveLayout calleeSaveInfo) {
+    protected String debugInfoToString(BytecodePosition codePos, ReferenceMap refMap, ValueSet liveBasePointers, RegisterSaveLayout calleeSaveInfo) {
         StringBuilder sb = new StringBuilder();
         if (refMap != null) {
+            sb.append("reference-map: ");
             sb.append(refMap.toString());
             sb.append("\n");
         }
+        if (liveBasePointers != null) {
+            sb.append("live-base-pointers: ");
+            sb.append(liveBasePointers);
+            sb.append("\n");
+        }
 
         if (calleeSaveInfo != null) {
             sb.append("callee-save-info:");
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -54,7 +54,7 @@
         return this;
     }
 
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getValue())));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        nodeValueMap.setResult(this, gen.emitFloatConvert(op, nodeValueMap.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathIntrinsicNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathIntrinsicNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -76,9 +76,9 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator lirGen) {
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator lirGen) {
         AMD64ArithmeticLIRGenerator gen = (AMD64ArithmeticLIRGenerator) lirGen;
-        Value input = builder.operand(getValue());
+        Value input = nodeValueMap.operand(getValue());
         Value result;
         switch (operation()) {
             case LOG:
@@ -99,7 +99,7 @@
             default:
                 throw JVMCIError.shouldNotReachHere();
         }
-        builder.setResult(this, result);
+        nodeValueMap.setResult(this, result);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DerivedOopTest.java	Tue Jul 21 16:17:54 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.replacements.test;
+
+import java.util.*;
+
+import jdk.internal.jvmci.meta.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+import com.oracle.graal.word.nodes.*;
+
+/**
+ * Tests for derived oops in reference maps.
+ */
+public class DerivedOopTest extends GraalCompilerTest implements Snippets {
+
+    private static class Pointers {
+        public long basePointer;
+        public long internalPointer;
+
+        public long delta() {
+            return internalPointer - basePointer;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof Pointers)) {
+                return false;
+            }
+
+            Pointers other = (Pointers) obj;
+            return this.delta() == other.delta();
+        }
+
+        @Override
+        public int hashCode() {
+            return (int) delta();
+        }
+    }
+
+    private static class Result {
+        public Pointers beforeGC;
+        public Pointers afterGC;
+
+        public Result() {
+            beforeGC = new Pointers();
+            afterGC = new Pointers();
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((afterGC == null) ? 0 : afterGC.hashCode());
+            result = prime * result + ((beforeGC == null) ? 0 : beforeGC.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof Result)) {
+                return false;
+            }
+            Result other = (Result) obj;
+            return Objects.equals(this.beforeGC, other.beforeGC) && Objects.equals(this.afterGC, other.afterGC);
+        }
+    }
+
+    @Test
+    public void testFieldOffset() {
+        Result r = new Result();
+        test("fieldOffsetSnippet", r, 16L);
+
+        Assert.assertEquals(r.beforeGC.delta(), r.afterGC.delta());
+    }
+
+    static long getRawPointer(Object obj) {
+        // fake implementation for interpreter
+        return obj.hashCode();
+    }
+
+    static long getRawPointerIntrinsic(Object obj) {
+        return Word.fromObject(obj).rawValue();
+    }
+
+    public static Result fieldOffsetSnippet(Result obj, long offset) {
+        long internalPointer = getRawPointer(obj) + offset;
+
+        // make sure the internal pointer is computed before the safepoint
+        GraalDirectives.blackhole(internalPointer);
+
+        obj.beforeGC.basePointer = getRawPointer(obj);
+        obj.beforeGC.internalPointer = internalPointer;
+
+        System.gc();
+
+        obj.afterGC.basePointer = getRawPointer(obj);
+        obj.afterGC.internalPointer = internalPointer;
+
+        return obj;
+    }
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins plugins = super.getDefaultGraphBuilderPlugins();
+        Registration r = new Registration(plugins.getInvocationPlugins(), DerivedOopTest.class);
+
+        ResolvedJavaMethod intrinsic = getResolvedJavaMethod("getRawPointerIntrinsic");
+        r.register1("getRawPointer", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                b.intrinsify(targetMethod, intrinsic, new ValueNode[]{arg});
+                return true;
+            }
+        });
+
+        return plugins;
+    }
+
+    @Override
+    protected boolean checkHighTierGraph(StructuredGraph graph) {
+        assert graph.getNodes().filter(WordCastNode.class).count() > 0 : "DerivedOopTest.toLong should be intrinsified";
+        return super.checkHighTierGraph(graph);
+    }
+}
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Tue Jul 21 16:17:54 2015 +0200
@@ -25,11 +25,14 @@
 import java.util.*;
 
 import jdk.internal.jvmci.code.CompilationResult.*;
+import jdk.internal.jvmci.debug.*;
+import jdk.internal.jvmci.debug.Debug.*;
 import jdk.internal.jvmci.meta.*;
 
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.replacements.test.CheckCastTest.Depth12;
@@ -430,4 +433,64 @@
         test("conditionalInstantiation", new StringBuilder());
         test("conditionalInstantiation", 1);
     }
+
+    public boolean exactlyObject(Thread thread) {
+        return thread != null && ((Object) thread).getClass() == Object.class;
+    }
+
+    public boolean exactlyObjectArray(Thread[] threads) {
+        return threads != null && ((Object[]) threads).getClass() == Object[].class;
+    }
+
+    public boolean exactlyString(Thread thread) {
+        return thread != null && ((Object) thread).getClass() == String.class;
+    }
+
+    public boolean exactlyStringArray(Thread[] threads) {
+        return threads != null && ((Object[]) threads).getClass() == String[].class;
+    }
+
+    @SuppressWarnings("cast")
+    public boolean instanceofStringArray(Thread[] threads) {
+        return threads != null && ((Object[]) threads) instanceof String[];
+    }
+
+    @SuppressWarnings("cast")
+    public boolean instanceofString(Thread thread) {
+        return thread != null && ((Object) thread) instanceof String;
+    }
+
+    /**
+     * {@link TypeCheckNode} and {@link InstanceOfNode} should be equivalently powerful when
+     * comparing disjoint types.
+     */
+    @Test
+    public void testTypeCheck() {
+        testConstantReturn("exactlyObject", 0);
+        testConstantReturn("exactlyObjectArray", 0);
+        testConstantReturn("exactlyString", 0);
+        testConstantReturn("exactlyStringArray", 0);
+        testConstantReturn("instanceofString", 0);
+        testConstantReturn("instanceofStringArray", 0);
+    }
+
+    private void testConstantReturn(String name, Object value) {
+        StructuredGraph result = buildGraph(name);
+        ReturnNode ret = result.getNodes(ReturnNode.TYPE).first();
+        assertDeepEquals(1, result.getNodes(ReturnNode.TYPE).count());
+
+        assertDeepEquals(true, ret.result().isConstant());
+        assertDeepEquals(value, ret.result().asJavaConstant().asBoxedPrimitive());
+    }
+
+    protected StructuredGraph buildGraph(final String snippet) {
+        try (Scope s = Debug.scope("InstanceOfTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            compile(graph.method(), graph);
+            Debug.dump(graph, snippet);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Tue Jul 21 16:17:54 2015 +0200
@@ -87,7 +87,7 @@
         } else if (n instanceof ArrayLengthNode) {
             lowerArrayLengthNode((ArrayLengthNode) n, tool);
         } else if (n instanceof LoadHubNode) {
-            lowerLoadHubNode((LoadHubNode) n);
+            lowerLoadHubNode((LoadHubNode) n, tool);
         } else if (n instanceof MonitorEnterNode) {
             lowerMonitorEnterNode((MonitorEnterNode) n, tool, graph);
         } else if (n instanceof CompareAndSwapNode) {
@@ -118,7 +118,7 @@
     }
 
     private void lowerTypeCheckNode(TypeCheckNode n, LoweringTool tool, StructuredGraph graph) {
-        ValueNode hub = createReadHub(graph, n.getValue(), null);
+        ValueNode hub = createReadHub(graph, n.getValue(), null, tool);
         ValueNode clazz = graph.unique(ConstantNode.forConstant(tool.getStampProvider().createHubStamp((ObjectStamp) n.getValue().stamp()), n.type().getObjectHub(), tool.getMetaAccess()));
         LogicNode objectEquals = graph.unique(PointerEqualsNode.create(hub, clazz));
         n.replaceAndDelete(objectEquals);
@@ -211,7 +211,7 @@
         Kind elementKind = loadIndexed.elementKind();
         Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
 
-        PiNode pi = getBoundsCheckedIndex(loadIndexed, tool);
+        PiNode pi = getBoundsCheckedIndex(loadIndexed, tool, null);
         ValueNode checkedIndex = pi;
         if (checkedIndex == null) {
             checkedIndex = loadIndexed.index();
@@ -232,7 +232,8 @@
     protected void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
         StructuredGraph graph = storeIndexed.graph();
 
-        PiNode pi = getBoundsCheckedIndex(storeIndexed, tool);
+        GuardingNode[] nullCheckReturn = new GuardingNode[1];
+        PiNode pi = getBoundsCheckedIndex(storeIndexed, tool, nullCheckReturn);
         ValueNode checkedIndex;
         GuardingNode boundsCheck;
         if (pi == null) {
@@ -263,8 +264,14 @@
                     value = storeCheck;
                 }
             } else {
-                ValueNode arrayClass = createReadHub(graph, array, boundsCheck);
-                ValueNode componentHub = createReadArrayComponentHub(graph, arrayClass, storeIndexed);
+                /*
+                 * The guard on the read hub should be the null check of the array that was
+                 * introduced earlier.
+                 */
+                GuardingNode nullCheck = nullCheckReturn[0];
+                assert nullCheckReturn[0] != null || createNullCheck(array, storeIndexed, tool) == null;
+                ValueNode arrayClass = createReadHub(graph, array, nullCheck, tool);
+                ValueNode componentHub = createReadArrayComponentHub(graph, arrayClass, storeIndexed, tool);
                 checkCastNode = graph.add(new CheckCastDynamicNode(componentHub, value, true));
                 graph.addBeforeFixed(storeIndexed, checkCastNode);
                 value = checkCastNode;
@@ -294,12 +301,15 @@
         graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
     }
 
-    protected void lowerLoadHubNode(LoadHubNode loadHub) {
+    protected void lowerLoadHubNode(LoadHubNode loadHub, LoweringTool tool) {
         StructuredGraph graph = loadHub.graph();
+        if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
+            return;
+        }
         if (graph.getGuardsStage().allowsFloatingGuards()) {
             return;
         }
-        ValueNode hub = createReadHub(graph, loadHub.getValue(), loadHub.getGuard());
+        ValueNode hub = createReadHub(graph, loadHub.getValue(), loadHub.getGuard(), tool);
         graph.replaceFloating(loadHub, hub);
     }
 
@@ -665,11 +675,11 @@
         return value;
     }
 
-    protected abstract ValueNode createReadHub(StructuredGraph graph, ValueNode object, GuardingNode guard);
+    protected abstract ValueNode createReadHub(StructuredGraph graph, ValueNode object, GuardingNode guard, LoweringTool tool);
 
-    protected abstract ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor);
+    protected abstract ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor, LoweringTool tool);
 
-    protected PiNode getBoundsCheckedIndex(AccessIndexedNode n, LoweringTool tool) {
+    protected PiNode getBoundsCheckedIndex(AccessIndexedNode n, LoweringTool tool, GuardingNode[] nullCheckReturn) {
         StructuredGraph graph = n.graph();
         ValueNode array = n.array();
         ValueNode arrayLength = readArrayLength(array, tool.getConstantReflection());
@@ -678,7 +688,11 @@
             AddressNode address = createOffsetAddress(graph, array, arrayLengthOffset());
             ReadNode readArrayLength = graph.add(new ReadNode(address, ARRAY_LENGTH_LOCATION, stamp, BarrierType.NONE));
             graph.addBeforeFixed(n, readArrayLength);
-            readArrayLength.setGuard(createNullCheck(array, readArrayLength, tool));
+            GuardingNode nullCheck = createNullCheck(array, readArrayLength, tool);
+            if (nullCheckReturn != null) {
+                nullCheckReturn[0] = nullCheck;
+            }
+            readArrayLength.setGuard(nullCheck);
             arrayLength = readArrayLength;
         } else {
             arrayLength = arrayLength.isAlive() ? arrayLength : graph.addOrUniqueWithInputs(arrayLength);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsUtil.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsUtil.java	Tue Jul 21 16:17:54 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -31,12 +31,12 @@
         // empty
     }
 
-    private static final boolean REPLACEMENTS_ASSERTIONS_ENABLED;
+    public static final boolean REPLACEMENTS_ASSERTIONS_ENABLED;
 
     static {
         boolean assertionsEnabled = false;
         assert (assertionsEnabled = true) != false;
-        REPLACEMENTS_ASSERTIONS_ENABLED = assertionsEnabled && GraalOptions.ImmutableCode.getValue() == null;
+        REPLACEMENTS_ASSERTIONS_ENABLED = assertionsEnabled && GraalOptions.ImmutableCode.getValue() == false;
     }
 
     /**
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Tue Jul 21 16:17:54 2015 +0200
@@ -46,6 +46,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.replacements.nodes.arithmetic.*;
 
@@ -127,7 +128,7 @@
         Registration r = new Registration(plugins, Array.class);
         r.register2("newInstance", Class.class, int.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode componentType, ValueNode length) {
-                b.addPush(Kind.Object, new DynamicNewArrayNode(componentType, length, true, null));
+                b.addPush(Kind.Object, new DynamicNewArrayNode(componentType, length, true));
                 return true;
             }
         });
@@ -663,6 +664,19 @@
                 return true;
             }
         });
+
+        r.register1("ensureVirtualized", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                b.add(new EnsureVirtualizedNode(object, false));
+                return true;
+            }
+        });
+        r.register1("ensureVirtualizedHere", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                b.add(new EnsureVirtualizedNode(object, true));
+                return true;
+            }
+        });
     }
 
     private static void registerJMHBlackholePlugins(InvocationPlugins plugins) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -66,7 +66,7 @@
     /*
      * Looks at the given stamp and determines if it is an exact type (or can be assumed to be an
      * exact type) and if it is a cloneable type.
-     *
+     * 
      * If yes, then the exact type is returned, otherwise it returns null.
      */
     protected static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions, MetaAccessProvider metaAccess) {
@@ -99,7 +99,7 @@
                     newEntryState[i] = originalState.getEntry(i);
                 }
                 VirtualObjectNode newVirtual = originalVirtual.duplicate();
-                tool.createVirtualObject(newVirtual, newEntryState, Collections.<MonitorIdNode> emptyList());
+                tool.createVirtualObject(newVirtual, newEntryState, Collections.<MonitorIdNode> emptyList(), false);
                 tool.replaceWithVirtual(newVirtual);
             }
         } else {
@@ -120,7 +120,7 @@
                     state[i] = loads[i] = new LoadFieldNode(obj, fields[i]);
                     tool.addNode(loads[i]);
                 }
-                tool.createVirtualObject(newVirtual, state, Collections.<MonitorIdNode> emptyList());
+                tool.createVirtualObject(newVirtual, state, Collections.<MonitorIdNode> emptyList(), false);
                 tool.replaceWithVirtual(newVirtual);
             }
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/arithmetic/IntegerMulHighNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/arithmetic/IntegerMulHighNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -83,10 +83,10 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value a = builder.operand(getX());
-        Value b = builder.operand(getY());
-        builder.setResult(this, gen.emitMulHigh(a, b));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        Value a = nodeValueMap.operand(getX());
+        Value b = nodeValueMap.operand(getY());
+        nodeValueMap.setResult(this, gen.emitMulHigh(a, b));
     }
 
     public static int multiplyHigh(int x, int y) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/arithmetic/UnsignedMulHighNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/arithmetic/UnsignedMulHighNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -88,10 +88,10 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value a = builder.operand(getX());
-        Value b = builder.operand(getY());
-        builder.setResult(this, gen.emitUMulHigh(a, b));
+    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
+        Value a = nodeValueMap.operand(getX());
+        Value b = nodeValueMap.operand(getY());
+        nodeValueMap.setResult(this, gen.emitUMulHigh(a, b));
     }
 
     public static int multiplyHighUnsigned(int x, int y) {
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Jul 21 16:17:54 2015 +0200
@@ -121,6 +121,14 @@
     }
 
     @Override
+    public TruffleCompiler getTruffleCompiler() {
+        if (truffleCompiler == null) {
+            truffleCompiler = DefaultTruffleCompiler.create();
+        }
+        return truffleCompiler;
+    }
+
+    @Override
     public RootCallTarget createCallTarget(RootNode rootNode) {
         return createCallTargetImpl(null, rootNode);
     }
@@ -213,9 +221,9 @@
 
     @Override
     public void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous) {
-        if (truffleCompiler == null) {
-            truffleCompiler = DefaultTruffleCompiler.create();
-        }
+        /* Ensure compiler is created. */
+        getTruffleCompiler();
+
         Runnable r = new Runnable() {
             @Override
             public void run() {
--- a/graal/com.oracle.graal.truffle.test/sl/TestDeoptInInlinedFunction.sl	Tue Jul 21 15:16:00 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-/* 
- * This tests that simple arithmetic gets inlined.
- */
-function add(a, b) {
-    deoptimizeWhenCompiled(a == 50); 
-    return a + b;
-}
-
-
-function test() {
-    i = 0;
-    while (i < 100) {
-        i = add(i, 1);
-    }
-    return i;
-}
-
-function main() {
-    waitForOptimization(callUntilOptimized(test, 1 == 2));
-    test();
-}  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestDeoptInInlinedFunction.sl.disable	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,21 @@
+/* 
+ * This tests that simple arithmetic gets inlined.
+ */
+function add(a, b) {
+    deoptimizeWhenCompiled(a == 50); 
+    return a + b;
+}
+
+
+function test() {
+    i = 0;
+    while (i < 100) {
+        i = add(i, 1);
+    }
+    return i;
+}
+
+function main() {
+    waitForOptimization(callUntilOptimized(test, 1 == 2));
+    test();
+}  
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java	Tue Jul 21 16:17:54 2015 +0200
@@ -52,6 +52,7 @@
         @CompilationFinal private final FrameSlot[] stack;
 
         public Program(String name, byte[] bytecodes, int maxLocals, int maxStack) {
+            super(MockLanguage.class, null, null);
             this.name = name;
             this.bytecodes = bytecodes;
             locals = new FrameSlot[maxLocals];
@@ -438,7 +439,7 @@
         protected final FrameSlot returnSlot;
 
         public InstArrayProgram(String name, Inst[] inst, FrameSlot returnSlot, FrameDescriptor fd) {
-            super(null, fd);
+            super(MockLanguage.class, null, fd);
             this.name = name;
             this.inst = inst;
             this.returnSlot = returnSlot;
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ControlFlowExceptionPartialEvaluationTest.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ControlFlowExceptionPartialEvaluationTest.java	Tue Jul 21 16:17:54 2015 +0200
@@ -24,7 +24,9 @@
 
 import org.junit.*;
 
+import com.oracle.graal.truffle.*;
 import com.oracle.graal.truffle.test.nodes.*;
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
@@ -47,6 +49,21 @@
         assertPartialEvalEquals("constant42", new RootTestNode(fd, "catchSlowPathAndControlFlowException", result));
     }
 
+    @Test
+    public void catchControlFlowExceptionWithLoopExplosion() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new CatchControlFlowExceptionTestNode(new BlockTestNode(new ThrowControlFlowExceptionTestNode()));
+        assertPartialEvalEquals("constant42", new RootTestNode(fd, "catchControlFlowExceptionWithLoopExplosion", result));
+    }
+
+    @Test
+    public void catchControlFlowExceptionFromCall() {
+        Assume.assumeTrue(TruffleCompilerOptions.TruffleFunctionInlining.getValue());
+        CallTarget callTarget = Truffle.getRuntime().createCallTarget(new RootTestNode(new FrameDescriptor(), "throwControlFlowException", new ThrowControlFlowExceptionTestNode()));
+        AbstractTestNode result = new CatchControlFlowExceptionTestNode(new CallTestNode(callTarget));
+        assertPartialEvalEquals("constant42", new RootTestNode(new FrameDescriptor(), "catchControlFlowExceptionFromCall", result));
+    }
+
     public static class ThrowControlFlowExceptionTestNode extends AbstractTestNode {
         @Override
         public int execute(VirtualFrame frame) {
@@ -94,4 +111,42 @@
             return child.execute(frame);
         }
     }
+
+    public static class BlockTestNode extends AbstractTestNode {
+        @Children private final AbstractTestNode[] statements;
+
+        public BlockTestNode(AbstractTestNode... statements) {
+            this.statements = statements;
+        }
+
+        @Override
+        public int execute(VirtualFrame frame) {
+            return executeSpecial(frame);
+        }
+
+        /*
+         * A statically resolvable method, so that ExplodeLoop annotation is visible during parsing.
+         */
+        @ExplodeLoop
+        private int executeSpecial(VirtualFrame frame) {
+            int result = 0;
+            for (AbstractTestNode statement : statements) {
+                result = statement.execute(frame);
+            }
+            return result;
+        }
+    }
+
+    public static class CallTestNode extends AbstractTestNode {
+        @Child private DirectCallNode callNode;
+
+        public CallTestNode(CallTarget callTarget) {
+            this.callNode = Truffle.getRuntime().createDirectCallNode(callTarget);
+        }
+
+        @Override
+        public int execute(VirtualFrame frame) {
+            return (int) callNode.call(frame, new Object[0]);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/MockLanguage.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,31 @@
+/*
+ * 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.truffle.test;
+
+import com.oracle.truffle.api.TruffleLanguage;
+
+public abstract class MockLanguage extends TruffleLanguage {
+    public MockLanguage(Env env) {
+        super(env);
+    }
+}
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/RootTestNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/RootTestNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.truffle.test.nodes;
 
+import com.oracle.graal.truffle.test.MockLanguage;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
@@ -33,7 +34,7 @@
     @Child AbstractTestNode node;
 
     public RootTestNode(FrameDescriptor descriptor, String name, AbstractTestNode node) {
-        super(null, descriptor);
+        super(MockLanguage.class, null, descriptor);
         this.name = name;
         this.node = node;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Tue Jul 21 16:17:54 2015 +0200
@@ -66,6 +66,8 @@
         Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
     }
 
+    public abstract TruffleCompiler getTruffleCompiler();
+
     private static <T extends PrioritizedServiceProvider> T loadPrioritizedServiceProvider(Class<T> clazz) {
         Iterable<T> providers = Services.load(clazz);
         T bestFactory = null;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -183,7 +183,7 @@
         @Child private OptimizedOSRLoopNode loopNode;
 
         public OSRRootNode(OptimizedOSRLoopNode loop) {
-            super(loop.getSourceSection(), loop.getRootNode().getFrameDescriptor());
+            super(TruffleLanguage.class, loop.getSourceSection(), loop.getRootNode().getFrameDescriptor());
             this.loopNode = loop;
         }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Jul 21 16:17:54 2015 +0200
@@ -97,6 +97,22 @@
         }
     }
 
+    public Providers getProviders() {
+        return providers;
+    }
+
+    public SnippetReflectionProvider getSnippetReflection() {
+        return snippetReflection;
+    }
+
+    public ResolvedJavaMethod[] getCompilationRootMethods() {
+        return new ResolvedJavaMethod[]{callRootMethod, callInlinedMethod};
+    }
+
+    public ResolvedJavaMethod[] getNeverInlineMethods() {
+        return new ResolvedJavaMethod[]{callSiteProxyMethod, callDirectMethod};
+    }
+
     public StructuredGraph createGraph(final OptimizedCallTarget callTarget, AllowAssumptions allowAssumptions) {
         try (Scope c = Debug.scope("TruffleTree")) {
             Debug.dump(callTarget, "truffle tree");
@@ -158,11 +174,12 @@
 
         @Override
         public InlineInfo shouldInlineInvoke(GraphBuilderContext builder, ResolvedJavaMethod original, ValueNode[] arguments, JavaType returnType) {
-            if (original.getAnnotation(TruffleBoundary.class) != null) {
-                return InlineInfo.DO_NOT_INLINE;
+            TruffleBoundary truffleBoundary = original.getAnnotation(TruffleBoundary.class);
+            if (truffleBoundary != null) {
+                return truffleBoundary.throwsControlFlowException() ? InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION : InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
             }
             if (replacements.hasSubstitution(original, builder.bci())) {
-                return InlineInfo.DO_NOT_INLINE;
+                return InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
             }
             assert !builder.parsingIntrinsic();
 
@@ -226,18 +243,21 @@
 
         @Override
         public InlineInfo shouldInlineInvoke(GraphBuilderContext builder, ResolvedJavaMethod original, ValueNode[] arguments, JavaType returnType) {
-            if (invocationPlugins.lookupInvocation(original) != null || loopExplosionPlugin.shouldExplodeLoops(original)) {
-                return InlineInfo.DO_NOT_INLINE;
+            if (invocationPlugins.lookupInvocation(original) != null) {
+                return InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
+            } else if (loopExplosionPlugin.shouldExplodeLoops(original)) {
+                return InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION;
             }
-            if (original.getAnnotation(TruffleBoundary.class) != null) {
-                return InlineInfo.DO_NOT_INLINE;
+            TruffleBoundary truffleBoundary = original.getAnnotation(TruffleBoundary.class);
+            if (truffleBoundary != null) {
+                return truffleBoundary.throwsControlFlowException() ? InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION : InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
             }
             if (replacements.hasSubstitution(original, builder.bci())) {
-                return InlineInfo.DO_NOT_INLINE;
+                return InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
             }
 
             if (original.equals(callSiteProxyMethod) || original.equals(callDirectMethod)) {
-                return InlineInfo.DO_NOT_INLINE;
+                return InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION;
             }
             if (hasMethodHandleArgument(arguments)) {
                 /*
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/ReadOnlyFrame.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/ReadOnlyFrame.java	Tue Jul 21 16:17:54 2015 +0200
@@ -24,6 +24,7 @@
 
 import jdk.internal.jvmci.common.*;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.*;
 
 class ReadOnlyFrame implements Frame {
@@ -33,102 +34,127 @@
         this.delegate = delegate;
     }
 
+    @TruffleBoundary
     public FrameDescriptor getFrameDescriptor() {
         return delegate.getFrameDescriptor();
     }
 
+    @TruffleBoundary
     public Object[] getArguments() {
         return delegate.getArguments().clone();
     }
 
+    @TruffleBoundary
     public Object getObject(FrameSlot slot) throws FrameSlotTypeException {
         return delegate.getObject(slot);
     }
 
+    @TruffleBoundary
     public void setObject(FrameSlot slot, Object value) {
         throw JVMCIError.shouldNotReachHere();
     }
 
+    @TruffleBoundary
     public byte getByte(FrameSlot slot) throws FrameSlotTypeException {
         return delegate.getByte(slot);
     }
 
+    @TruffleBoundary
     public void setByte(FrameSlot slot, byte value) {
         throw JVMCIError.shouldNotReachHere();
     }
 
+    @TruffleBoundary
     public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException {
         return delegate.getBoolean(slot);
     }
 
+    @TruffleBoundary
     public void setBoolean(FrameSlot slot, boolean value) {
         throw JVMCIError.shouldNotReachHere();
     }
 
+    @TruffleBoundary
     public int getInt(FrameSlot slot) throws FrameSlotTypeException {
         return delegate.getInt(slot);
     }
 
+    @TruffleBoundary
     public void setInt(FrameSlot slot, int value) {
         throw JVMCIError.shouldNotReachHere();
     }
 
+    @TruffleBoundary
     public long getLong(FrameSlot slot) throws FrameSlotTypeException {
         return delegate.getLong(slot);
     }
 
+    @TruffleBoundary
     public void setLong(FrameSlot slot, long value) {
         throw JVMCIError.shouldNotReachHere();
     }
 
+    @TruffleBoundary
     public float getFloat(FrameSlot slot) throws FrameSlotTypeException {
         return delegate.getFloat(slot);
     }
 
+    @TruffleBoundary
     public void setFloat(FrameSlot slot, float value) {
         throw JVMCIError.shouldNotReachHere();
     }
 
+    @TruffleBoundary
     public double getDouble(FrameSlot slot) throws FrameSlotTypeException {
         return delegate.getDouble(slot);
     }
 
+    @TruffleBoundary
     public void setDouble(FrameSlot slot, double value) {
         throw JVMCIError.shouldNotReachHere();
     }
 
+    @TruffleBoundary
     public Object getValue(FrameSlot slot) {
         return delegate.getValue(slot);
     }
 
+    @TruffleBoundary
     public MaterializedFrame materialize() {
         throw JVMCIError.shouldNotReachHere();
     }
 
+    @TruffleBoundary
     public boolean isObject(FrameSlot slot) {
         return delegate.isObject(slot);
     }
 
+    @TruffleBoundary
     public boolean isByte(FrameSlot slot) {
         return delegate.isByte(slot);
     }
 
+    @TruffleBoundary
     public boolean isBoolean(FrameSlot slot) {
         return delegate.isBoolean(slot);
     }
 
+    @TruffleBoundary
     public boolean isInt(FrameSlot slot) {
         return delegate.isInt(slot);
     }
 
+    @TruffleBoundary
     public boolean isLong(FrameSlot slot) {
         return delegate.isLong(slot);
     }
 
+    @TruffleBoundary
     public boolean isFloat(FrameSlot slot) {
         return delegate.isFloat(slot);
     }
 
+    @TruffleBoundary
     public boolean isDouble(FrameSlot slot) {
         return delegate.isDouble(slot);
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java	Tue Jul 21 16:17:54 2015 +0200
@@ -99,6 +99,10 @@
         }
     }
 
+    public GraphBuilderConfiguration getGraphBuilderConfiguration() {
+        return config;
+    }
+
     protected abstract PartialEvaluator createPartialEvaluator();
 
     public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) {
@@ -152,6 +156,11 @@
 
         CompilationResult result = null;
         try (DebugCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); DebugCloseable c = CompilationMemUse.start()) {
+            SpeculationLog speculationLog = graph.getSpeculationLog();
+            if (speculationLog != null) {
+                speculationLog.collectFailedSpeculations();
+            }
+
             CodeCacheProvider codeCache = providers.getCodeCache();
             CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
             CompilationResult compilationResult = new CompilationResult(name);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -25,7 +25,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.truffle.api.frame.*;
 
 /**
  * Intrinsic node for materializing a Truffle frame.
@@ -44,7 +43,4 @@
     public ValueNode getFrame() {
         return frame;
     }
-
-    @NodeIntrinsic
-    public static native MaterializedFrame materialize(VirtualFrame frame);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Tue Jul 21 16:17:54 2015 +0200
@@ -182,12 +182,12 @@
             graph().getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) frameDescriptor.getVersion()));
         }
 
-        tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, Collections.<MonitorIdNode> emptyList());
+        tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, Collections.<MonitorIdNode> emptyList(), false);
         if (virtualFramePrimitiveArray != null) {
-            tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, Collections.<MonitorIdNode> emptyList());
+            tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, Collections.<MonitorIdNode> emptyList(), false);
         }
         if (virtualFrameTagArray != null) {
-            tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, Collections.<MonitorIdNode> emptyList());
+            tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, Collections.<MonitorIdNode> emptyList(), false);
         }
 
         assert frameFields.length == 5 || frameFields.length == 3;
@@ -202,7 +202,7 @@
         if (tagsField != null) {
             frameEntryState[frameFieldList.indexOf(tagsField)] = virtualFrameTagArray;
         }
-        tool.createVirtualObject(virtualFrame, frameEntryState, Collections.<MonitorIdNode> emptyList());
+        tool.createVirtualObject(virtualFrame, frameEntryState, Collections.<MonitorIdNode> emptyList(), false);
         tool.replaceWithVirtual(virtualFrame);
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Tue Jul 21 16:17:54 2015 +0200
@@ -49,28 +49,31 @@
     private ValueNode[] entries;
     private ValueNode materializedValue;
     private LockState locks;
+    private boolean ensureVirtualized;
 
     private EscapeObjectState cachedState;
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, List<MonitorIdNode> locks) {
-        this(virtual, entries, state, (LockState) null);
+    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, List<MonitorIdNode> locks, boolean ensureVirtualized) {
+        this(virtual, entries, state, (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) {
+    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, LockState locks, boolean ensureVirtualized) {
         this.virtual = virtual;
         this.entries = entries;
         this.state = state;
         this.locks = locks;
+        this.ensureVirtualized = ensureVirtualized;
     }
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks) {
+    public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks, boolean ensureVirtualized) {
         this.virtual = virtual;
         this.materializedValue = materializedValue;
         this.state = state;
         this.locks = locks;
+        this.ensureVirtualized = ensureVirtualized;
     }
 
     private ObjectState(ObjectState other) {
@@ -80,6 +83,7 @@
         locks = other.locks;
         state = other.state;
         cachedState = other.cachedState;
+        ensureVirtualized = other.ensureVirtualized;
     }
 
     public ObjectState cloneState() {
@@ -185,6 +189,16 @@
     }
 
     @Override
+    public void setEnsureVirtualized(boolean ensureVirtualized) {
+        this.ensureVirtualized = ensureVirtualized;
+    }
+
+    @Override
+    public boolean getEnsureVirtualized() {
+        return ensureVirtualized;
+    }
+
+    @Override
     public String toString() {
         StringBuilder str = new StringBuilder().append('{');
         if (locks != null) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Tue Jul 21 16:17:54 2015 +0200
@@ -74,7 +74,8 @@
         List<ValueNode> values = new ArrayList<>(8);
         List<List<MonitorIdNode>> locks = new ArrayList<>(2);
         List<ValueNode> otherAllocations = new ArrayList<>(2);
-        materializeWithCommit(fixed, virtual, objects, locks, values, otherAllocations, state);
+        List<Boolean> ensureVirtual = new ArrayList<>(2);
+        materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations, state);
 
         materializeEffects.add("materializeBefore", (graph, obsoleteNodes) -> {
             for (ValueNode otherAllocation : otherAllocations) {
@@ -102,6 +103,7 @@
                 for (List<MonitorIdNode> monitorIds : locks) {
                     commit.addLocks(monitorIds);
                 }
+                commit.getEnsureVirtual().addAll(ensureVirtual);
 
                 assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.getUsageCount();
                 List<AllocatedObjectNode> materializedValues = commit.usages().filter(AllocatedObjectNode.class).snapshot();
@@ -115,7 +117,7 @@
     }
 
     private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<List<MonitorIdNode>> locks, List<ValueNode> values,
-                    List<ValueNode> otherAllocations, EscapeState state) {
+                    List<Boolean> ensureVirtual, List<ValueNode> otherAllocations, EscapeState state) {
         ObjectState obj = getObjectState(virtual);
 
         ValueNode[] entries = obj.getEntries();
@@ -125,6 +127,7 @@
         if (representation instanceof AllocatedObjectNode) {
             objects.add((AllocatedObjectNode) representation);
             locks.add(LockState.asList(obj.getLocks()));
+            ensureVirtual.add(obj.getEnsureVirtualized());
             int pos = values.size();
             while (values.size() < pos + entries.length) {
                 values.add(null);
@@ -133,7 +136,7 @@
                 if (entries[i] instanceof VirtualObjectNode) {
                     ObjectState entryObj = getObjectState((VirtualObjectNode) entries[i]);
                     if (entryObj.isVirtual()) {
-                        materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, otherAllocations, state);
+                        materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, ensureVirtual, otherAllocations, state);
                     }
                     values.set(pos + i, entryObj.getMaterializedValue());
                 } else {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Jul 21 16:17:54 2015 +0200
@@ -562,7 +562,7 @@
                         materialized |= mergeObjectStates(object, objStates, states);
                     } else {
                         if (uniqueMaterializedValue != null) {
-                            newState.addObject(object, new ObjectState(object, uniqueMaterializedValue, EscapeState.Materialized, null));
+                            newState.addObject(object, new ObjectState(object, uniqueMaterializedValue, EscapeState.Materialized, null, false));
                         } else {
                             PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(Kind.Object));
                             mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi");
@@ -574,7 +574,7 @@
                                 }
                                 setPhiInput(materializedValuePhi, i, obj.getMaterializedValue());
                             }
-                            newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null));
+                            newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null, false));
                         }
                     }
                 }
@@ -615,6 +615,7 @@
          */
         private boolean mergeObjectStates(VirtualObjectNode object, ObjectState[] objStates, List<BlockT> blockStates) {
             boolean compatible = true;
+            boolean ensureVirtual = true;
             ValueNode[] values = objStates[0].getEntries().clone();
 
             // determine all entries that have a two-slot value
@@ -622,6 +623,7 @@
             outer: for (int i = 0; i < objStates.length; i++) {
                 ValueNode[] entries = objStates[i].getEntries();
                 int valueIndex = 0;
+                ensureVirtual &= objStates[i].getEnsureVirtualized();
                 while (valueIndex < values.length) {
                     Kind otherKind = entries[valueIndex].getKind();
                     Kind entryKind = object.entryKind(valueIndex);
@@ -705,7 +707,7 @@
                         values[i] = phi;
                     }
                 }
-                newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, objStates[0].getLocks()));
+                newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, objStates[0].getLocks(), ensureVirtual));
                 return materialized;
             } else {
                 // not compatible: materialize in all predecessors
@@ -716,7 +718,7 @@
                     ensureMaterialized(blockStates.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
                     setPhiInput(materializedValuePhi, i, obj.getMaterializedValue());
                 }
-                newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null));
+                newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null, false));
                 return true;
             }
         }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Tue Jul 21 15:16:00 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Tue Jul 21 16:17:54 2015 +0200
@@ -151,7 +151,7 @@
     }
 
     @Override
-    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks) {
+    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks, boolean ensureVirtualized) {
         VirtualUtil.trace("{{%s}} ", current);
         if (!virtualObject.isAlive()) {
             effects.addFloatingNode(virtualObject, "newVirtualObject");
@@ -166,7 +166,7 @@
                 }
             }
         }
-        state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks));
+        state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks, ensureVirtualized));
         closure.addAndMarkAlias(virtualObject, virtualObject);
         PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment();
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotSymbol.java	Tue Jul 21 16:17:54 2015 +0200
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2013, 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 jdk.internal.jvmci.hotspot;
+
+import static jdk.internal.jvmci.common.UnsafeAccess.*;
+import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Represents a metaspace {@code Symbol}.
+ */
+public class HotSpotSymbol {
+
+    private final long metaspaceSymbol;
+
+    public HotSpotSymbol(long metaspaceSymbol) {
+        assert metaspaceSymbol != 0;
+        this.metaspaceSymbol = metaspaceSymbol;
+    }
+
+    /**
+     * Decodes this {@code Symbol} and returns the symbol string as {@link java.lang.String}.
+     *
+     * @return the decoded string, or null if there was a decoding error
+     */
+    public String asString() {
+        return readModifiedUTF8(asByteArray());
+    }
+
+    /**
+     * Reads the modified UTF-8 string in {@code buf} and converts it to a {@link String}. The
+     * implementation is taken from {@link java.io.DataInputStream#readUTF(DataInput)} and adapted
+     * to operate on a {@code byte} array directly for performance reasons.
+     *
+     * @see java.io.DataInputStream#readUTF(DataInput)
+     */
+    private static String readModifiedUTF8(byte[] buf) {
+        final int utflen = buf.length;
+        byte[] bytearr = null;
+        char[] chararr = new char[utflen];
+
+        int c;
+        int char2;
+        int char3;
+        int count = 0;
+        int chararrCount = 0;
+
+        bytearr = buf;
+
+        while (count < utflen) {
+            c = bytearr[count] & 0xff;
+            if (c > 127) {
+                break;
+            }
+            count++;
+            chararr[chararrCount++] = (char) c;
+        }
+
+        while (count < utflen) {
+            c = bytearr[count] & 0xff;
+            switch (c >> 4) {
+                case 0:
+                case 1:
+                case 2:
+                case 3:
+                case 4:
+                case 5:
+                case 6:
+                case 7:
+                    /* 0xxxxxxx */
+                    count++;
+                    chararr[chararrCount++] = (char) c;
+                    break;
+                case 12:
+                case 13:
+                    /* 110x xxxx 10xx xxxx */
+                    count += 2;
+                    if (count > utflen) {
+                        // malformed input: partial character at end
+                        return null;
+                    }
+                    char2 = bytearr[count - 1];
+                    if ((char2 & 0xC0) != 0x80) {
+                        // malformed input around byte
+                        return null;
+                    }
+                    chararr[chararrCount++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
+                    break;
+                case 14:
+                    /* 1110 xxxx 10xx xxxx 10xx xxxx */
+                    count += 3;
+                    if (count > utflen) {
+                        // malformed input: partial character at end
+                        return null;
+                    }
+                    char2 = bytearr[count - 2];
+                    char3 = bytearr[count - 1];
+                    if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) {
+                        // malformed input around byte
+                        return null;
+                    }
+                    chararr[chararrCount++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
+                    break;
+                default:
+                    /* 10xx xxxx, 1111 xxxx */
+                    // malformed input around byte
+                    return null;
+            }
+        }
+        // The number of chars produced may be less than utflen
+        char[] value = Arrays.copyOf(chararr, chararrCount);
+        return new String(value);
+    }
+
+    private byte[] asByteArray() {
+        final int length = getLength();
+        byte[] result = new byte[length];
+        for (int index = 0; index < length; index++) {
+            result[index] = getByteAt(index);
+        }
+        return result;
+    }
+
+    private int getLength() {
+        return unsafe.getShort(metaspaceSymbol + runtime().getConfig().symbolLengthOffset);
+    }
+
+    private byte getByteAt(int index) {
+        return unsafe.getByte(metaspaceSymbol + runtime().getConfig().symbolBodyOffset + index);
+    }
+}
--- a/mx.graal/mx_graal.py	Tue Jul 21 15:16:00 2015 +0200
+++ b/mx.graal/mx_graal.py	Tue Jul 21 16:17:54 2015 +0200
@@ -337,7 +337,7 @@
                 mx.abort('Unknown DaCapo : ' + dacapo)
             iterations = sanitycheck.dacapoSanityWarmup[dacapo][sanitycheck.SanityCheckLevel.Benchmark]
             if iterations > 0:
-                benchmarks += [sanitycheck.getDacapo(dacapo, iterations)]
+                benchmarks += [sanitycheck.getDacapo(dacapo, ['-n', str(iterations)])]
 
     if 'scaladacapo' in args or 'all' in args:
         benchmarks += sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Benchmark)
--- a/mx.graal/suite.py	Tue Jul 21 15:16:00 2015 +0200
+++ b/mx.graal/suite.py	Tue Jul 21 16:17:54 2015 +0200
@@ -671,6 +671,7 @@
         "com.oracle.graal.compiler",
         "com.oracle.graal.lir.sparc"
       ],
+      "annotationProcessors" : ["com.oracle.graal.compiler.match.processor"],
       "checkstyle" : "com.oracle.graal.graph",
       "annotationProcessors" : [
         "GRAAL_NODEINFO_PROCESSOR",
@@ -926,6 +927,10 @@
         "GRAAL_TRUFFLE",
         "truffle:TRUFFLE_SL",
       ],
+      "exclude" : [
+        "TRUFFLE",
+        "TRUFFLE_DSL_PROCESSOR",
+      ],
     },
 
     "GRAAL_NODEINFO_PROCESSOR" : {