changeset 14062:09d41e2f8dc7

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Fri, 28 Feb 2014 16:19:10 +0100
parents a3cd3403a958 (current diff) 692452c4cfb6 (diff)
children 60637fc3fa8c
files graal/com.oracle.graal.asm/src/com/oracle/graal/asm/AbstractAssembler.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/GraphKit.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java
diffstat 109 files changed, 1788 insertions(+), 1304 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/SimpleAssemblerTest.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/SimpleAssemblerTest.java	Fri Feb 28 16:19:10 2014 +0100
@@ -30,7 +30,6 @@
 import com.oracle.graal.api.code.CompilationResult.ConstantData;
 import com.oracle.graal.api.code.CompilationResult.RawData;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.Buffer;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.asm.test.*;
 
@@ -41,12 +40,12 @@
         CodeGenTest test = new CodeGenTest() {
 
             @Override
-            public Buffer generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+            public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
                 AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
                 Register ret = registerConfig.getReturnRegister(Kind.Int);
                 asm.movl(ret, 8472);
                 asm.ret(0);
-                return asm.codeBuffer;
+                return asm.close(true);
             }
         };
         assertReturn("intStub", test, 8472);
@@ -57,13 +56,13 @@
         CodeGenTest test = new CodeGenTest() {
 
             @Override
-            public Buffer generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+            public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
                 AMD64MacroAssembler asm = new AMD64MacroAssembler(target, registerConfig);
                 Register ret = registerConfig.getReturnRegister(Kind.Double);
-                compResult.recordDataReference(asm.codeBuffer.position(), new ConstantData(Constant.forDouble(84.72), 8));
+                compResult.recordDataReference(asm.position(), new ConstantData(Constant.forDouble(84.72), 8));
                 asm.movdbl(ret, asm.getPlaceholder());
                 asm.ret(0);
-                return asm.codeBuffer;
+                return asm.close(true);
             }
         };
         assertReturn("doubleStub", test, 84.72);
@@ -74,16 +73,16 @@
         CodeGenTest test = new CodeGenTest() {
 
             @Override
-            public Buffer generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+            public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
                 AMD64MacroAssembler asm = new AMD64MacroAssembler(target, registerConfig);
                 Register ret = registerConfig.getReturnRegister(Kind.Double);
 
                 byte[] rawBytes = new byte[8];
                 ByteBuffer.wrap(rawBytes).order(ByteOrder.nativeOrder()).putDouble(84.72);
-                compResult.recordDataReference(asm.codeBuffer.position(), new RawData(rawBytes, 8));
+                compResult.recordDataReference(asm.position(), new RawData(rawBytes, 8));
                 asm.movdbl(ret, asm.getPlaceholder());
                 asm.ret(0);
-                return asm.codeBuffer;
+                return asm.close(true);
             }
         };
         assertReturn("doubleStub", test, 84.72);
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Fri Feb 28 16:19:10 2014 +0100
@@ -34,7 +34,7 @@
 /**
  * This class implements an assembler that can encode most X86 instructions.
  */
-public class AMD64Assembler extends AbstractAssembler {
+public class AMD64Assembler extends Assembler {
 
     private static final int MinEncodingNeedsRex = 8;
 
@@ -746,7 +746,7 @@
     public void jcc(ConditionFlag cc, int jumpTarget, boolean forceDisp32) {
         int shortSize = 2;
         int longSize = 6;
-        long disp = jumpTarget - codeBuffer.position();
+        long disp = jumpTarget - position();
         if (!forceDisp32 && isByte(disp - shortSize)) {
             // 0111 tttn #8-bit disp
             emitByte(0x70 | cc.getValue());
@@ -769,7 +769,7 @@
             // is the same however, seems to be rather unlikely case.
             // Note: use jccb() if label to be bound is very close to get
             // an 8-bit displacement
-            l.addPatchAt(codeBuffer.position());
+            l.addPatchAt(position());
             emitByte(0x0F);
             emitByte(0x80 | cc.getValue());
             emitInt(0);
@@ -781,13 +781,13 @@
         if (l.isBound()) {
             int shortSize = 2;
             int entry = l.position();
-            assert isByte(entry - (codeBuffer.position() + shortSize)) : "Dispacement too large for a short jmp";
-            long disp = entry - codeBuffer.position();
+            assert isByte(entry - (position() + shortSize)) : "Dispacement too large for a short jmp";
+            long disp = entry - position();
             // 0111 tttn #8-bit disp
             emitByte(0x70 | cc.getValue());
             emitByte((int) ((disp - shortSize) & 0xFF));
         } else {
-            l.addPatchAt(codeBuffer.position());
+            l.addPatchAt(position());
             emitByte(0x70 | cc.getValue());
             emitByte(0);
         }
@@ -796,7 +796,7 @@
     public final void jmp(int jumpTarget, boolean forceDisp32) {
         int shortSize = 2;
         int longSize = 5;
-        long disp = jumpTarget - codeBuffer.position();
+        long disp = jumpTarget - position();
         if (!forceDisp32 && isByte(disp - shortSize)) {
             emitByte(0xEB);
             emitByte((int) ((disp - shortSize) & 0xFF));
@@ -816,7 +816,7 @@
             // the forward jump will not run beyond 256 bytes, use jmpb to
             // force an 8-bit displacement.
 
-            l.addPatchAt(codeBuffer.position());
+            l.addPatchAt(position());
             emitByte(0xE9);
             emitInt(0);
         }
@@ -832,13 +832,13 @@
         if (l.isBound()) {
             int shortSize = 2;
             int entry = l.position();
-            assert isByte((entry - codeBuffer.position()) + shortSize) : "Dispacement too large for a short jmp";
-            long offs = entry - codeBuffer.position();
+            assert isByte((entry - position()) + shortSize) : "Dispacement too large for a short jmp";
+            long offs = entry - position();
             emitByte(0xEB);
             emitByte((int) ((offs - shortSize) & 0xFF));
         } else {
 
-            l.addPatchAt(codeBuffer.position());
+            l.addPatchAt(position());
             emitByte(0xEB);
             emitByte(0);
         }
@@ -2446,21 +2446,21 @@
 
     @Override
     protected final void patchJumpTarget(int branch, int branchTarget) {
-        int op = codeBuffer.getByte(branch);
+        int op = getByte(branch);
         assert op == 0xE8 // call
                         ||
                         op == 0x00 // jump table entry
                         || op == 0xE9 // jmp
                         || op == 0xEB // short jmp
                         || (op & 0xF0) == 0x70 // short jcc
-                        || op == 0x0F && (codeBuffer.getByte(branch + 1) & 0xF0) == 0x80 // jcc
+                        || op == 0x0F && (getByte(branch + 1) & 0xF0) == 0x80 // jcc
         : "Invalid opcode at patch point branch=" + branch + ", branchTarget=" + branchTarget + ", op=" + op;
 
         if (op == 0x00) {
-            int offsetToJumpTableBase = codeBuffer.getShort(branch + 1);
+            int offsetToJumpTableBase = getShort(branch + 1);
             int jumpTableBase = branch - offsetToJumpTableBase;
             int imm32 = branchTarget - jumpTableBase;
-            codeBuffer.emitInt(imm32, branch);
+            emitInt(imm32, branch);
         } else if (op == 0xEB || (op & 0xF0) == 0x70) {
 
             // short offset operators (jmp and jcc)
@@ -2472,7 +2472,7 @@
             if (!NumUtil.isByte(imm8)) {
                 throw new InternalError("branch displacement out of range: " + imm8);
             }
-            codeBuffer.emitByte(imm8, branch + 1);
+            emitByte(imm8, branch + 1);
 
         } else {
 
@@ -2482,7 +2482,7 @@
             }
 
             int imm32 = branchTarget - (branch + 4 + off);
-            codeBuffer.emitInt(imm32, branch + off);
+            emitInt(imm32, branch + off);
         }
     }
 
@@ -2492,8 +2492,8 @@
 
     @Override
     public void align(int modulus) {
-        if (codeBuffer.position() % modulus != 0) {
-            nop(modulus - (codeBuffer.position() % modulus));
+        if (position() % modulus != 0) {
+            nop(modulus - (position() % modulus));
         }
     }
 
--- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/AbstractHSAILAssembler.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/AbstractHSAILAssembler.java	Fri Feb 28 16:19:10 2014 +0100
@@ -28,7 +28,7 @@
 /**
  * The platform-dependent base class for the HSAIL assembler.
  */
-public abstract class AbstractHSAILAssembler extends AbstractAssembler {
+public abstract class AbstractHSAILAssembler extends Assembler {
 
     public AbstractHSAILAssembler(TargetDescription target) {
         super(target);
--- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/AbstractPTXAssembler.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/AbstractPTXAssembler.java	Fri Feb 28 16:19:10 2014 +0100
@@ -28,7 +28,7 @@
 /**
  * The platform-dependent base class for the PTX assembler.
  */
-public abstract class AbstractPTXAssembler extends AbstractAssembler {
+public abstract class AbstractPTXAssembler extends Assembler {
 
     public AbstractPTXAssembler(TargetDescription target) {
         super(target);
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri Feb 28 16:19:10 2014 +0100
@@ -33,7 +33,7 @@
 /**
  * This class implements an assembler that can encode most SPARC instructions.
  */
-public abstract class SPARCAssembler extends AbstractAssembler {
+public abstract class SPARCAssembler extends Assembler {
 
     /**
      * Constructs an assembler for the SPARC architecture.
@@ -89,7 +89,7 @@
         }
 
         public static Fmt00a read(SPARCAssembler masm, int pos) {
-            final int inst = masm.codeBuffer.getInt(pos);
+            final int inst = masm.getInt(pos);
 
             // Make sure it's the right instruction:
             final int op = (inst & OP_MASK) >> OP_SHIFT;
@@ -105,7 +105,7 @@
 
         public void write(SPARCAssembler masm, int pos) {
             verify();
-            masm.codeBuffer.emitInt(getInstructionBits(), pos);
+            masm.emitInt(getInstructionBits(), pos);
         }
 
         public void emit(SPARCAssembler masm) {
@@ -253,7 +253,7 @@
         }
 
         public static Fmt00c read(SPARCAssembler masm, int pos) {
-            final int inst = masm.codeBuffer.getInt(pos);
+            final int inst = masm.getInt(pos);
 
             // Make sure it's the right instruction:
             final int op = (inst & OP_MASK) >> OP_SHIFT;
@@ -274,13 +274,13 @@
 
         public void write(SPARCAssembler masm, int pos) {
             verify();
-            masm.codeBuffer.emitInt(getInstructionBits(), pos);
+            masm.emitInt(getInstructionBits(), pos);
         }
 
         public void emit(SPARCAssembler masm) {
             if (label != null) {
                 final int pos = label.isBound() ? label.position() : patchUnbound(masm, label);
-                final int disp = pos - masm.codeBuffer.position();
+                final int disp = pos - masm.position();
                 setDisp19(disp);
             }
             verify();
@@ -288,7 +288,7 @@
         }
 
         private static int patchUnbound(SPARCAssembler masm, Label label) {
-            label.addPatchAt(masm.codeBuffer.position());
+            label.addPatchAt(masm.position());
             return 0;
         }
 
@@ -370,7 +370,7 @@
         }
 
         public static Fmt01 read(SPARCAssembler masm, int pos) {
-            final int inst = masm.codeBuffer.getInt(pos);
+            final int inst = masm.getInt(pos);
 
             // Make sure it's the right instruction:
             final int op = (inst & OP_MASK) >> OP_SHIFT;
@@ -386,7 +386,7 @@
 
         public void write(SPARCAssembler masm, int pos) {
             verify();
-            masm.codeBuffer.emitInt(getInstructionBits(), pos);
+            masm.emitInt(getInstructionBits(), pos);
         }
 
         public void emit(SPARCAssembler masm) {
@@ -550,7 +550,7 @@
         }
 
         public static Fmt10 read(SPARCAssembler masm, int pos) {
-            final int inst = masm.codeBuffer.getInt(pos);
+            final int inst = masm.getInt(pos);
 
             // Make sure it's the right instruction:
             final int op = (inst & OP_MASK) >> OP_SHIFT;
@@ -571,7 +571,7 @@
 
         public void write(SPARCAssembler masm, int pos) {
             verify();
-            masm.codeBuffer.emitInt(getInstructionBits(), pos);
+            masm.emitInt(getInstructionBits(), pos);
         }
 
         public void emit(SPARCAssembler masm) {
@@ -696,7 +696,7 @@
         }
 
         public static Fmt11 read(SPARCAssembler masm, int pos) {
-            final int inst = masm.codeBuffer.getInt(pos);
+            final int inst = masm.getInt(pos);
 
             // Make sure it's the right instruction:
             final int op = (inst & OP_MASK) >> OP_SHIFT;
@@ -716,7 +716,7 @@
 
         public void write(SPARCAssembler masm, int pos) {
             verify();
-            masm.codeBuffer.emitInt(getInstructionBits(), pos);
+            masm.emitInt(getInstructionBits(), pos);
         }
 
         public void emit(SPARCAssembler masm) {
@@ -832,7 +832,7 @@
         }
 
         public static Fmt10c read(SPARCAssembler masm, int pos) {
-            final int inst = masm.codeBuffer.getInt(pos);
+            final int inst = masm.getInt(pos);
 
             // Make sure it's the right instruction:
             final int op = (inst & OP_MASK) >> OP_SHIFT;
@@ -852,7 +852,7 @@
 
         public void write(SPARCAssembler masm, int pos) {
             verify();
-            masm.codeBuffer.emitInt(getInstructionBits(), pos);
+            masm.emitInt(getInstructionBits(), pos);
         }
 
         public void emit(SPARCAssembler masm) {
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Fri Feb 28 16:19:10 2014 +0100
@@ -42,8 +42,8 @@
 
     @Override
     public void align(int modulus) {
-        if (codeBuffer.position() % modulus != 0) {
-            final int count = modulus - (codeBuffer.position() % modulus);
+        if (position() % modulus != 0) {
+            final int count = modulus - (position() % modulus);
             for (int i = 0; i < count; i++) {
                 new Nop().emit(this);
             }
@@ -364,7 +364,7 @@
             int lo = (int) (value & ~0);
 
             // This is the same logic as MacroAssembler::internal_set.
-            final int startPc = masm.codeBuffer.position();
+            final int startPc = masm.position();
 
             if (hi == 0 && lo >= 0) {
                 new Sethi(hi22(lo), dst).emit(masm);
@@ -399,7 +399,7 @@
             }
             // Pad out the instruction sequence so it can be patched later.
             if (forceRelocatable) {
-                while (masm.codeBuffer.position() < (startPc + (INSTRUCTION_SIZE * 4))) {
+                while (masm.position() < (startPc + (INSTRUCTION_SIZE * 4))) {
                     new Nop().emit(masm);
                 }
             }
--- a/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Fri Feb 28 16:19:10 2014 +0100
@@ -29,7 +29,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.asm.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.runtime.*;
 import com.oracle.graal.test.*;
@@ -40,8 +39,7 @@
     protected final CodeCacheProvider codeCache;
 
     public interface CodeGenTest {
-
-        Buffer generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc);
+        byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc);
     }
 
     public AssemblerTest() {
@@ -60,8 +58,8 @@
         CallingConvention cc = CodeUtil.getCallingConvention(codeCache, CallingConvention.Type.JavaCallee, method, false);
 
         CompilationResult compResult = new CompilationResult();
-        Buffer codeBuffer = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);
-        compResult.setTargetCode(codeBuffer.close(true), codeBuffer.position());
+        byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);
+        compResult.setTargetCode(targetCode, targetCode.length);
 
         InstalledCode code = codeCache.addMethod(method, compResult, null);
 
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/AbstractAssembler.java	Wed Feb 26 13:09:16 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.asm;
-
-import java.nio.*;
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-
-/**
- * The platform-independent base class for the assembler.
- */
-public abstract class AbstractAssembler {
-
-    public final TargetDescription target;
-    public final Buffer codeBuffer;
-
-    public AbstractAssembler(TargetDescription target) {
-        this.target = target;
-
-        if (target.arch.getByteOrder() == ByteOrder.BIG_ENDIAN) {
-            this.codeBuffer = new Buffer.BigEndian();
-        } else {
-            this.codeBuffer = new Buffer.LittleEndian();
-        }
-    }
-
-    public void bind(Label l) {
-        assert !l.isBound() : "can bind label only once";
-        l.bind(codeBuffer.position());
-        l.patchInstructions(this);
-    }
-
-    public abstract void align(int modulus);
-
-    public abstract void jmp(Label l);
-
-    protected abstract void patchJumpTarget(int branch, int jumpTarget);
-
-    private Map<Label, String> nameMap;
-
-    /**
-     * Creates a name for a label.
-     * 
-     * @param l the label for which a name is being created
-     * @param id a label identifier that is unique with the scope of this assembler
-     * @return a label name in the form of "L123"
-     */
-    protected String createLabelName(Label l, int id) {
-        return "L" + id;
-    }
-
-    /**
-     * Gets a name for a label, creating it if it does not yet exist. By default, the returned name
-     * is only unique with the scope of this assembler.
-     */
-    public String nameOf(Label l) {
-        if (nameMap == null) {
-            nameMap = new HashMap<>();
-        }
-        String name = nameMap.get(l);
-        if (name == null) {
-            name = createLabelName(l, nameMap.size());
-            nameMap.put(l, name);
-        }
-        return name;
-    }
-
-    protected final void emitByte(int x) {
-        codeBuffer.emitByte(x);
-    }
-
-    protected final void emitShort(int x) {
-        codeBuffer.emitShort(x);
-    }
-
-    protected final void emitInt(int x) {
-        codeBuffer.emitInt(x);
-    }
-
-    protected final void emitLong(long x) {
-        codeBuffer.emitLong(x);
-    }
-
-    /**
-     * Some GPU architectures have a text based encoding.
-     */
-    protected final void emitString(String x) {
-        codeBuffer.emitString(x);
-    }
-
-    // XXX for pretty-printing
-    protected final void emitString0(String x) {
-        codeBuffer.emitString0(x);
-    }
-
-    /**
-     * This is used by the CompilationResultBuilder to convert a {@link StackSlot} to an
-     * {@link AbstractAddress}.
-     */
-    public abstract AbstractAddress makeAddress(Register base, int displacement);
-
-    /**
-     * Returns a target specific placeholder address that can be used for code patching.
-     */
-    public abstract AbstractAddress getPlaceholder();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java	Fri Feb 28 16:19:10 2014 +0100
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.asm;
+
+import java.nio.*;
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+
+/**
+ * The platform-independent base class for the assembler.
+ */
+public abstract class Assembler {
+
+    public final TargetDescription target;
+
+    /**
+     * Backing code buffer.
+     */
+    private final Buffer codeBuffer;
+
+    public Assembler(TargetDescription target) {
+        this.target = target;
+        if (target.arch.getByteOrder() == ByteOrder.BIG_ENDIAN) {
+            this.codeBuffer = new Buffer.BigEndian();
+        } else {
+            this.codeBuffer = new Buffer.LittleEndian();
+        }
+    }
+
+    /**
+     * Returns the current position of the underlying code buffer.
+     * 
+     * @return current position in code buffer
+     */
+    public int position() {
+        return codeBuffer.position();
+    }
+
+    public final void emitByte(int x) {
+        codeBuffer.emitByte(x);
+    }
+
+    public final void emitShort(int x) {
+        codeBuffer.emitShort(x);
+    }
+
+    public final void emitInt(int x) {
+        codeBuffer.emitInt(x);
+    }
+
+    public final void emitLong(long x) {
+        codeBuffer.emitLong(x);
+    }
+
+    public final void emitByte(int b, int pos) {
+        codeBuffer.emitByte(b, pos);
+    }
+
+    public final void emitShort(int b, int pos) {
+        codeBuffer.emitShort(b, pos);
+    }
+
+    public final void emitInt(int b, int pos) {
+        codeBuffer.emitInt(b, pos);
+    }
+
+    public final void emitLong(long b, int pos) {
+        codeBuffer.emitLong(b, pos);
+    }
+
+    public final int getByte(int pos) {
+        return codeBuffer.getByte(pos);
+    }
+
+    public final int getShort(int pos) {
+        return codeBuffer.getShort(pos);
+    }
+
+    public final int getInt(int pos) {
+        return codeBuffer.getInt(pos);
+    }
+
+    private static final String NEWLINE = System.getProperty("line.separator");
+
+    /**
+     * Some GPU architectures have a text based encoding.
+     */
+    public final void emitString(String x) {
+        emitString0("\t");  // XXX REMOVE ME pretty-printing
+        emitString0(x);
+        emitString0(NEWLINE);
+    }
+
+    // XXX for pretty-printing
+    public final void emitString0(String x) {
+        codeBuffer.emitBytes(x.getBytes(), 0, x.length());
+    }
+
+    public void emitString(String s, int pos) {
+        codeBuffer.emitBytes(s.getBytes(), pos);
+    }
+
+    /**
+     * Closes this assembler. No extra data can be written to this assembler after this call.
+     * 
+     * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not
+     *            including) {@code position()} is returned
+     * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
+     */
+    public byte[] close(boolean trimmedCopy) {
+        return codeBuffer.close(trimmedCopy);
+    }
+
+    public void bind(Label l) {
+        assert !l.isBound() : "can bind label only once";
+        l.bind(position());
+        l.patchInstructions(this);
+    }
+
+    public abstract void align(int modulus);
+
+    public abstract void jmp(Label l);
+
+    protected abstract void patchJumpTarget(int branch, int jumpTarget);
+
+    private Map<Label, String> nameMap;
+
+    /**
+     * Creates a name for a label.
+     * 
+     * @param l the label for which a name is being created
+     * @param id a label identifier that is unique with the scope of this assembler
+     * @return a label name in the form of "L123"
+     */
+    protected String createLabelName(Label l, int id) {
+        return "L" + id;
+    }
+
+    /**
+     * Gets a name for a label, creating it if it does not yet exist. By default, the returned name
+     * is only unique with the scope of this assembler.
+     */
+    public String nameOf(Label l) {
+        if (nameMap == null) {
+            nameMap = new HashMap<>();
+        }
+        String name = nameMap.get(l);
+        if (name == null) {
+            name = createLabelName(l, nameMap.size());
+            nameMap.put(l, name);
+        }
+        return name;
+    }
+
+    /**
+     * This is used by the CompilationResultBuilder to convert a {@link StackSlot} to an
+     * {@link AbstractAddress}.
+     */
+    public abstract AbstractAddress makeAddress(Register base, int displacement);
+
+    /**
+     * Returns a target specific placeholder address that can be used for code patching.
+     */
+    public abstract AbstractAddress getPlaceholder();
+}
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java	Fri Feb 28 16:19:10 2014 +0100
@@ -28,7 +28,7 @@
  * Code buffer management for the assembler. Support for little endian and big endian architectures
  * is implemented using subclasses.
  */
-public abstract class Buffer {
+abstract class Buffer {
 
     protected byte[] data;
     protected int position;
@@ -105,19 +105,6 @@
         position = emitLong(b, position);
     }
 
-    private static final String NEWLINE = System.getProperty("line.separator");
-
-    public void emitString(String s) {
-        position = emitString("\t", position);  // XXX REMOVE ME pretty-printing
-        position = emitString(s, position);
-        position = emitString(NEWLINE, position);
-    }
-
-    // XXX for pretty-printing
-    public void emitString0(String s) {
-        emitBytes(s.getBytes(), 0, s.length());
-    }
-
     public int emitBytes(byte[] arr, int pos) {
         final int len = arr.length;
         final int newPos = pos + len;
@@ -140,10 +127,6 @@
 
     public abstract int emitLong(long b, int pos);
 
-    public int emitString(String s, int pos) {
-        return emitBytes(s.getBytes(), pos);
-    }
-
     public int getByte(int pos) {
         return data[pos] & 0xff;
     }
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Label.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Label.java	Fri Feb 28 16:19:10 2014 +0100
@@ -34,8 +34,7 @@
 
     /**
      * References to instructions that jump to this unresolved label. These instructions need to be
-     * patched when the label is bound using the {@link #patchInstructions(AbstractAssembler)}
-     * method.
+     * patched when the label is bound using the {@link #patchInstructions(Assembler)} method.
      */
     private ArrayList<Integer> patchPositions = null;
 
@@ -82,7 +81,7 @@
         patchPositions.add(branchLocation);
     }
 
-    protected void patchInstructions(AbstractAssembler masm) {
+    protected void patchInstructions(Assembler masm) {
         assert isBound() : "Label should be bound";
         if (patchPositions != null) {
             int target = position;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Fri Feb 28 16:19:10 2014 +0100
@@ -28,6 +28,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
@@ -278,7 +279,7 @@
 
     @SuppressWarnings("unused")
     public static void testNewNodeSnippet() {
-        new IntegerAddNode(Kind.Int, null, null);
+        new IntegerAddNode(new IntegerStamp(32, false, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0xFFFFFFFF), null, null);
     }
 
     /**
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri Feb 28 16:19:10 2014 +0100
@@ -70,7 +70,7 @@
     /**
      * Creates the assembler used to emit the machine code.
      */
-    protected abstract AbstractAssembler createAssembler(FrameMap frameMap);
+    protected abstract Assembler createAssembler(FrameMap frameMap);
 
     /**
      * Creates the object used to fill in the details of a given compilation result.
--- a/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java	Fri Feb 28 16:19:10 2014 +0100
@@ -111,7 +111,7 @@
         AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
 
         gen.generateCode(asm);
-        byte[] expectedCode = asm.codeBuffer.close(true);
+        byte[] expectedCode = asm.close(true);
 
         // Only compare up to expectedCode.length bytes to ignore
         // padding instructions adding during code installation
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri Feb 28 16:19:10 2014 +0100
@@ -98,9 +98,9 @@
                         disp -= frameSize;
                     }
                     crb.blockComment("[stack overflow check]");
-                    int pos = asm.codeBuffer.position();
+                    int pos = asm.position();
                     asm.movq(new AMD64Address(rsp, -disp), AMD64.rax);
-                    assert i > 0 || !isVerifiedEntryPoint || asm.codeBuffer.position() - pos >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE;
+                    assert i > 0 || !isVerifiedEntryPoint || asm.position() - pos >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE;
                 }
             }
         }
@@ -141,14 +141,14 @@
                     asm.nop(PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE);
                 }
             } else {
-                int verifiedEntryPointOffset = asm.codeBuffer.position();
+                int verifiedEntryPointOffset = asm.position();
                 if (!isStub && pagesToBang > 0) {
                     emitStackOverflowCheck(crb, pagesToBang, false, true);
-                    assert asm.codeBuffer.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE;
+                    assert asm.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE;
                 }
-                if (!isStub && asm.codeBuffer.position() == verifiedEntryPointOffset) {
+                if (!isStub && asm.position() == verifiedEntryPointOffset) {
                     asm.subqWide(rsp, frameSize);
-                    assert asm.codeBuffer.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE;
+                    assert asm.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE;
                 } else {
                     asm.decrementq(rsp, frameSize);
                 }
@@ -174,7 +174,7 @@
                 CalleeSaveLayout csl = crb.frameMap.registerConfig.getCalleeSaveLayout();
 
                 if (csl != null && csl.size != 0) {
-                    crb.compilationResult.setRegisterRestoreEpilogueOffset(asm.codeBuffer.position());
+                    crb.compilationResult.setRegisterRestoreEpilogueOffset(asm.position());
                     // saved all registers, restore all registers
                     int frameToCSA = crb.frameMap.offsetToCalleeSaveArea();
                     asm.restore(csl, frameToCSA);
@@ -187,7 +187,7 @@
     }
 
     @Override
-    protected AbstractAssembler createAssembler(FrameMap frameMap) {
+    protected Assembler createAssembler(FrameMap frameMap) {
         return new AMD64MacroAssembler(getTarget(), frameMap.registerConfig);
     }
 
@@ -206,7 +206,7 @@
         boolean omitFrame = CanOmitFrame.getValue() && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame() && !gen.hasForeignCall();
 
         Stub stub = gen.getStub();
-        AbstractAssembler masm = createAssembler(frameMap);
+        Assembler masm = createAssembler(frameMap);
         HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null, omitFrame);
         CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult);
         crb.setFrameSize(frameMap.frameSize());
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java	Fri Feb 28 16:19:10 2014 +0100
@@ -133,12 +133,12 @@
                     encodeKlassPointer(masm, asRegister(scratch), heapBaseReg, encoding);
                 }
                 if (state != null) {
-                    crb.recordImplicitException(masm.codeBuffer.position(), state);
+                    crb.recordImplicitException(masm.position(), state);
                 }
                 masm.movl(address.toAddress(), asRegister(scratch));
             }
             if (state != null) {
-                crb.recordImplicitException(masm.codeBuffer.position(), state);
+                crb.recordImplicitException(masm.position(), state);
             }
             masm.movl(address.toAddress(), asRegister(scratch));
         }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Fri Feb 28 16:19:10 2014 +0100
@@ -81,7 +81,7 @@
             // This move will be patched to load the safepoint page from a data segment
             // co-located with the immutable code.
             asm.movq(scratch, (AMD64Address) crb.recordDataReferenceInCode(pollingPageAddress, alignment));
-            final int pos = asm.codeBuffer.position();
+            final int pos = asm.position();
             crb.recordMark(atReturn ? MARK_POLL_RETURN_FAR : MARK_POLL_FAR);
             if (state != null) {
                 crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
@@ -90,14 +90,14 @@
         } else if (isPollingPageFar(config)) {
             asm.movq(scratch, config.safepointPollingAddress);
             crb.recordMark(atReturn ? MARK_POLL_RETURN_FAR : MARK_POLL_FAR);
-            final int pos = asm.codeBuffer.position();
+            final int pos = asm.position();
             if (state != null) {
                 crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
             }
             asm.testl(rax, new AMD64Address(scratch));
         } else {
             crb.recordMark(atReturn ? MARK_POLL_RETURN_NEAR : MARK_POLL_NEAR);
-            final int pos = asm.codeBuffer.position();
+            final int pos = asm.position();
             if (state != null) {
                 crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
             }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Fri Feb 28 16:19:10 2014 +0100
@@ -58,7 +58,6 @@
 public class HSAILHotSpotBackend extends HotSpotBackend {
 
     private Map<String, String> paramTypeMap = new HashMap<>();
-    private Buffer codeBuffer;
     private final boolean deviceInitialized;
 
     public HSAILHotSpotBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) {
@@ -193,14 +192,6 @@
         return new HSAILHotSpotLIRGenerator(graph, getProviders(), getRuntime().getConfig(), frameMap, cc, lir);
     }
 
-    public String getPartialCodeString() {
-        if (codeBuffer == null) {
-            return "";
-        }
-        byte[] data = codeBuffer.copyData(0, codeBuffer.position());
-        return (data == null ? "" : new String(data));
-    }
-
     class HotSpotFrameContext implements FrameContext {
 
         public boolean hasFrame() {
@@ -219,14 +210,14 @@
     }
 
     @Override
-    protected AbstractAssembler createAssembler(FrameMap frameMap) {
+    protected Assembler createAssembler(FrameMap frameMap) {
         return new HSAILAssembler(getTarget());
     }
 
     @Override
     public CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
         FrameMap frameMap = lirGen.frameMap;
-        AbstractAssembler masm = createAssembler(frameMap);
+        Assembler masm = createAssembler(frameMap);
         HotSpotFrameContext frameContext = new HotSpotFrameContext();
         CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult);
         crb.setFrameSize(frameMap.frameSize());
@@ -237,9 +228,9 @@
     public void emitCode(CompilationResultBuilder crb, LIRGenerator lirGen, ResolvedJavaMethod method) {
         assert method != null : lirGen.getGraph() + " is not associated with a method";
         // Emit the prologue.
-        codeBuffer = crb.asm.codeBuffer;
-        codeBuffer.emitString0("version 0:95: $full : $large;");
-        codeBuffer.emitString("");
+        Assembler asm = crb.asm;
+        asm.emitString0("version 0:95: $full : $large;");
+        asm.emitString("");
 
         Signature signature = method.getSignature();
         int sigParamCount = signature.getParameterCount(false);
@@ -284,10 +275,10 @@
             }
         }
 
-        codeBuffer.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method);
-        codeBuffer.emitString("");
-        codeBuffer.emitString0("kernel &run (");
-        codeBuffer.emitString("");
+        asm.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method);
+        asm.emitString("");
+        asm.emitString0("kernel &run (");
+        asm.emitString("");
 
         FrameMap frameMap = crb.frameMap;
         RegisterConfig regConfig = frameMap.registerConfig;
@@ -322,9 +313,9 @@
             if (i != totalParamCount - 1) {
                 str += ",";
             }
-            codeBuffer.emitString(str);
+            asm.emitString(str);
         }
-        codeBuffer.emitString(") {");
+        asm.emitString(") {");
 
         /*
          * End of parameters start of prolog code. Emit the load instructions for loading of the
@@ -332,7 +323,7 @@
          * loaded up front but will be loaded as needed.
          */
         for (int i = 0; i < nonConstantParamCount; i++) {
-            codeBuffer.emitString("ld_kernarg_" + paramHsailSizes[i] + "  " + HSAIL.mapRegister(cc.getArgument(i)) + ", [" + paramNames[i] + "];");
+            asm.emitString("ld_kernarg_" + paramHsailSizes[i] + "  " + HSAIL.mapRegister(cc.getArgument(i)) + ", [" + paramNames[i] + "];");
         }
 
         /*
@@ -340,16 +331,16 @@
          * the register as if it were the last of the nonConstant parameters.
          */
         String workItemReg = "$s" + Integer.toString(asRegister(cc.getArgument(nonConstantParamCount)).encoding());
-        codeBuffer.emitString("workitemabsid_u32 " + workItemReg + ", 0;");
+        asm.emitString("workitemabsid_u32 " + workItemReg + ", 0;");
 
         /*
          * Note the logic used for this spillseg size is to leave space and then go back and patch
          * in the correct size once we have generated all the instructions. This should probably be
          * done in a more robust way by implementing something like codeBuffer.insertString.
          */
-        int spillsegDeclarationPosition = codeBuffer.position() + 1;
+        int spillsegDeclarationPosition = asm.position() + 1;
         String spillsegTemplate = "align 4 spill_u8 %spillseg[123456];";
-        codeBuffer.emitString(spillsegTemplate);
+        asm.emitString(spillsegTemplate);
         // Emit object array load prologue here.
         if (isObjectLambda) {
             boolean useCompressedOops = getRuntime().getConfig().useCompressedOops;
@@ -359,37 +350,37 @@
             // so tempReg can be the next higher $d register
             String tmpReg = "$d" + (asRegister(cc.getArgument(nonConstantParamCount - 1)).encoding() + 1);
             // Convert gid to long.
-            codeBuffer.emitString("cvt_u64_s32 " + tmpReg + ", " + workItemReg + "; // Convert gid to long");
+            asm.emitString("cvt_u64_s32 " + tmpReg + ", " + workItemReg + "; // Convert gid to long");
             // Adjust index for sizeof ref. Where to pull this size from?
-            codeBuffer.emitString("mul_u64 " + tmpReg + ", " + tmpReg + ", " + (useCompressedOops ? 4 : 8) + "; // Adjust index for sizeof ref");
+            asm.emitString("mul_u64 " + tmpReg + ", " + tmpReg + ", " + (useCompressedOops ? 4 : 8) + "; // Adjust index for sizeof ref");
             // Adjust for actual data start.
-            codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + arrayElementsOffset + "; // Adjust for actual elements data start");
+            asm.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + arrayElementsOffset + "; // Adjust for actual elements data start");
             // Add to array ref ptr.
-            codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + iterationObjArgReg + "; // Add to array ref ptr");
+            asm.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + iterationObjArgReg + "; // Add to array ref ptr");
             // Load the object into the parameter reg.
             if (useCompressedOops) {
 
                 // Load u32 into the d 64 reg since it will become an object address
-                codeBuffer.emitString("ld_global_u32 " + tmpReg + ", " + "[" + tmpReg + "]" + "; // Load compressed ptr from array");
+                asm.emitString("ld_global_u32 " + tmpReg + ", " + "[" + tmpReg + "]" + "; // Load compressed ptr from array");
 
                 long narrowOopBase = getRuntime().getConfig().narrowOopBase;
                 long narrowOopShift = getRuntime().getConfig().narrowOopShift;
 
                 if (narrowOopBase == 0 && narrowOopShift == 0) {
                     // No more calculation to do, mov to target register
-                    codeBuffer.emitString("mov_b64 " + iterationObjArgReg + ", " + tmpReg + "; // no shift or base addition");
+                    asm.emitString("mov_b64 " + iterationObjArgReg + ", " + tmpReg + "; // no shift or base addition");
                 } else {
                     if (narrowOopBase == 0) {
-                        codeBuffer.emitString("shl_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopShift + "; // do narrowOopShift");
+                        asm.emitString("shl_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopShift + "; // do narrowOopShift");
                     } else if (narrowOopShift == 0) {
-                        codeBuffer.emitString("add_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopBase + "; // add narrowOopBase");
+                        asm.emitString("add_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopBase + "; // add narrowOopBase");
                     } else {
-                        codeBuffer.emitString("mad_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + (1 << narrowOopShift) + ", " + narrowOopBase + "; // shift and add narrowOopBase");
+                        asm.emitString("mad_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + (1 << narrowOopShift) + ", " + narrowOopBase + "; // shift and add narrowOopBase");
                     }
                 }
 
             } else {
-                codeBuffer.emitString("ld_global_u64 " + iterationObjArgReg + ", " + "[" + tmpReg + "]" + "; // Load from array element into parameter reg");
+                asm.emitString("ld_global_u64 " + iterationObjArgReg + ", " + "[" + tmpReg + "]" + "; // Load from array element into parameter reg");
             }
         }
         // Prologue done, Emit code for the LIR.
@@ -405,9 +396,10 @@
         } else {
             spillsegStringFinal = spillsegTemplate.replace("123456", String.format("%6d", maxStackSize));
         }
-        codeBuffer.emitString(spillsegStringFinal, spillsegDeclarationPosition);
+        asm.emitString(spillsegStringFinal, spillsegDeclarationPosition);
+
         // Emit the epilogue.
-        codeBuffer.emitString0("};");
-        codeBuffer.emitString("");
+        asm.emitString0("};");
+        asm.emitString("");
     }
 }
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Fri Feb 28 16:19:10 2014 +0100
@@ -261,24 +261,24 @@
 
         LIRInstruction op;
 
-        void emitDeclarations(Buffer codeBuffer) {
+        void emitDeclarations(Assembler asm) {
             for (Integer i : unsigned8) {
-                codeBuffer.emitString(".reg .u8 %r" + i.intValue() + ";");
+                asm.emitString(".reg .u8 %r" + i.intValue() + ";");
             }
             for (Integer i : signed32) {
-                codeBuffer.emitString(".reg .s32 %r" + i.intValue() + ";");
+                asm.emitString(".reg .s32 %r" + i.intValue() + ";");
             }
             for (Integer i : signed64) {
-                codeBuffer.emitString(".reg .s64 %r" + i.intValue() + ";");
+                asm.emitString(".reg .s64 %r" + i.intValue() + ";");
             }
             for (Integer i : unsigned64) {
-                codeBuffer.emitString(".reg .u64 %r" + i.intValue() + ";");
+                asm.emitString(".reg .u64 %r" + i.intValue() + ";");
             }
             for (Integer i : float32) {
-                codeBuffer.emitString(".reg .f32 %r" + i.intValue() + ";");
+                asm.emitString(".reg .f32 %r" + i.intValue() + ";");
             }
             for (Integer i : float64) {
-                codeBuffer.emitString(".reg .f64 %r" + i.intValue() + ";");
+                asm.emitString(".reg .f64 %r" + i.intValue() + ";");
             }
         }
 
@@ -360,7 +360,7 @@
         // - has no incoming arguments passed on the stack
         // - has no instructions with debug info
         FrameMap frameMap = lirGen.frameMap;
-        AbstractAssembler masm = createAssembler(frameMap);
+        Assembler masm = createAssembler(frameMap);
         PTXFrameContext frameContext = new PTXFrameContext();
         CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult);
         crb.setFrameSize(0);
@@ -368,7 +368,7 @@
     }
 
     @Override
-    protected AbstractAssembler createAssembler(FrameMap frameMap) {
+    protected Assembler createAssembler(FrameMap frameMap) {
         return new PTXMacroAssembler(getTarget(), frameMap.registerConfig);
     }
 
@@ -384,13 +384,13 @@
         // facilitate seemless PTX code generation subsequently.
         assert codeCacheOwner != null : lirGen.getGraph() + " is not associated with a method";
         final String name = codeCacheOwner.getName();
-        Buffer codeBuffer = crb.asm.codeBuffer;
+        Assembler asm = crb.asm;
 
         // Emit initial boiler-plate directives.
-        codeBuffer.emitString(".version 3.0");
-        codeBuffer.emitString(".target sm_30");
-        codeBuffer.emitString0(".entry " + name + " (");
-        codeBuffer.emitString("");
+        asm.emitString(".version 3.0");
+        asm.emitString(".target sm_30");
+        asm.emitString0(".entry " + name + " (");
+        asm.emitString("");
 
         // Get the start block
         Block startBlock = lirGen.lir.cfg.getStartBlock();
@@ -413,8 +413,8 @@
         }
 
         // Start emiting body of the PTX kernel.
-        codeBuffer.emitString0(") {");
-        codeBuffer.emitString("");
+        asm.emitString0(") {");
+        asm.emitString("");
     }
 
     // Emit .reg space declarations
@@ -422,7 +422,6 @@
 
         assert codeCacheOwner != null : lirGen.getGraph() + " is not associated with a method";
 
-        Buffer codeBuffer = crb.asm.codeBuffer;
         RegisterAnalysis registerAnalysis = new RegisterAnalysis();
 
         for (Block b : lirGen.lir.codeEmittingOrder()) {
@@ -437,19 +436,21 @@
             }
         }
 
-        registerAnalysis.emitDeclarations(codeBuffer);
+        Assembler asm = crb.asm;
+        registerAnalysis.emitDeclarations(asm);
 
         // emit predicate register declaration
         int maxPredRegNum = ((PTXLIRGenerator) lirGen).getNextPredRegNumber();
         if (maxPredRegNum > 0) {
-            codeBuffer.emitString(".reg .pred %p<" + maxPredRegNum + ">;");
+            asm.emitString(".reg .pred %p<" + maxPredRegNum + ">;");
         }
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, LIRGenerator lirGen, ResolvedJavaMethod codeCacheOwner) {
         assert codeCacheOwner != null : lirGen.getGraph() + " is not associated with a method";
-        Buffer codeBuffer = crb.asm.codeBuffer;
+        Assembler asm = crb.asm;
+
         // Emit the prologue
         emitKernelEntry(crb, lirGen, codeCacheOwner);
 
@@ -460,8 +461,7 @@
             e.printStackTrace();
             // TODO : Better error handling needs to be done once
             // all types of parameters are handled.
-            codeBuffer.setPosition(0);
-            codeBuffer.close(false);
+            asm.close(false);
             return;
         }
         // Emit code for the LIR
@@ -471,14 +471,13 @@
             e.printStackTrace();
             // TODO : Better error handling needs to be done once
             // all types of parameters are handled.
-            codeBuffer.setPosition(0);
-            codeBuffer.close(false);
+            asm.close(false);
             return;
         }
 
         // Emit the epilogue
-        codeBuffer.emitString0("}");
-        codeBuffer.emitString("");
+        asm.emitString0("}");
+        asm.emitString("");
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java	Fri Feb 28 16:19:10 2014 +0100
@@ -40,7 +40,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.ptx.*;
 import com.oracle.graal.nodes.*;
@@ -238,7 +237,7 @@
             int javaParameterOffset = javaParameterOffsetsInKernelParametersBuffer[javaParametersIndex];
             LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, javaParameter.kind(), javaParameterOffset, getGraph());
             append(new WriteNode(buf, javaParameter, location, BarrierType.NONE, false, false));
-            updateDimArg(method, providers, sig, sigIndex++, args, javaParameter);
+            updateDimArg(method, sig, sigIndex++, args, javaParameter);
         }
         if (returnKind != Kind.Void) {
             LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, bufSize - wordSize, getGraph());
@@ -325,7 +324,7 @@
      * Updates the {@code dimX}, {@code dimY} or {@code dimZ} argument passed to the kernel if
      * {@code javaParameter} is annotated with {@link ParallelOver}.
      */
-    private void updateDimArg(ResolvedJavaMethod method, HotSpotProviders providers, Signature sig, int sigIndex, Map<LaunchArg, ValueNode> launchArgs, ParameterNode javaParameter) {
+    private void updateDimArg(ResolvedJavaMethod method, Signature sig, int sigIndex, Map<LaunchArg, ValueNode> launchArgs, ParameterNode javaParameter) {
         if (sigIndex >= 0) {
             ParallelOver parallelOver = getParameterAnnotation(ParallelOver.class, sigIndex, method);
             if (parallelOver != null && sig.getParameterType(sigIndex, method.getDeclaringClass()).equals(providers.getMetaAccess().lookupJavaType(int[].class))) {
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri Feb 28 16:19:10 2014 +0100
@@ -147,7 +147,7 @@
     }
 
     @Override
-    protected AbstractAssembler createAssembler(FrameMap frameMap) {
+    protected Assembler createAssembler(FrameMap frameMap) {
         return new SPARCMacroAssembler(getTarget(), frameMap.registerConfig);
     }
 
@@ -158,7 +158,7 @@
         assert gen.deoptimizationRescueSlot == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
 
         Stub stub = gen.getStub();
-        AbstractAssembler masm = createAssembler(frameMap);
+        Assembler masm = createAssembler(frameMap);
         // On SPARC we always use stack frames.
         HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null);
         CompilationResultBuilder crb = factory.createBuilder(getProviders().getCodeCache(), getProviders().getForeignCalls(), frameMap, masm, frameContext, compilationResult);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Fri Feb 28 16:19:10 2014 +0100
@@ -59,7 +59,7 @@
     }
 
     public static void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm, HotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) {
-        final int pos = masm.codeBuffer.position();
+        final int pos = masm.position();
         new Setx(config.safepointPollingAddress, scratch).emit(masm);
         crb.recordMark(atReturn ? MARK_POLL_RETURN_FAR : MARK_POLL_FAR);
         if (state != null) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri Feb 28 16:19:10 2014 +0100
@@ -30,6 +30,7 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 import static com.oracle.graal.phases.common.InliningUtil.*;
 
+import java.io.*;
 import java.lang.reflect.*;
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
@@ -52,9 +53,14 @@
 
 public class CompilationTask implements Runnable, Comparable {
 
+    // Keep static finals in a group with withinEnqueue as the last one. CompilationTask can be
+    // called from within it's own clinit so it needs to be careful about accessing state. Once
+    // withinEnqueue is non-null we assume that CompilationTask is fully initialized.
+    private static final AtomicLong uniqueTaskIds = new AtomicLong();
+
     private static final DebugMetric BAILOUTS = Debug.metric("Bailouts");
 
-    public static final ThreadLocal<Boolean> withinEnqueue = new ThreadLocal<Boolean>() {
+    private static final ThreadLocal<Boolean> withinEnqueue = new ThreadLocal<Boolean>() {
 
         @Override
         protected Boolean initialValue() {
@@ -62,6 +68,22 @@
         }
     };
 
+    public static final boolean isWithinEnqueue() {
+        // It's possible this can be called before the <clinit> has completed so check for null
+        return withinEnqueue == null || withinEnqueue.get();
+    }
+
+    public static class BeginEnqueue implements Closeable {
+        public BeginEnqueue() {
+            assert !withinEnqueue.get();
+            withinEnqueue.set(Boolean.TRUE);
+        }
+
+        public void close() {
+            withinEnqueue.set(Boolean.FALSE);
+        }
+    }
+
     private enum CompilationStatus {
         Queued, Running, Finished
     }
@@ -74,8 +96,6 @@
 
     private StructuredGraph graph;
 
-    private static final AtomicLong uniqueTaskIds = new AtomicLong();
-
     /**
      * A long representing the sequence number of this task. Used for sorting the compile queue.
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri Feb 28 16:19:10 2014 +0100
@@ -248,14 +248,10 @@
             // Compile until the queue is empty.
             int z = 0;
             while (true) {
-                try {
-                    assert !CompilationTask.withinEnqueue.get();
-                    CompilationTask.withinEnqueue.set(Boolean.TRUE);
+                try (CompilationTask.BeginEnqueue beginEnqueue = new CompilationTask.BeginEnqueue()) {
                     if (compileQueue.getCompletedTaskCount() >= Math.max(3, compileQueue.getTaskCount())) {
                         break;
                     }
-                } finally {
-                    CompilationTask.withinEnqueue.set(Boolean.FALSE);
                 }
 
                 Thread.sleep(100);
@@ -325,9 +321,7 @@
     }
 
     public void shutdownCompiler() throws Exception {
-        try {
-            assert !CompilationTask.withinEnqueue.get();
-            CompilationTask.withinEnqueue.set(Boolean.TRUE);
+        try (CompilationTask.BeginEnqueue beginEnqueue = new CompilationTask.BeginEnqueue()) {
             // We have to use a privileged action here because shutting down the compiler might be
             // called from user code which very likely contains unprivileged frames.
             AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@@ -336,8 +330,6 @@
                     return null;
                 }
             });
-        } finally {
-            CompilationTask.withinEnqueue.set(Boolean.FALSE);
         }
 
         printDebugValues(ResetDebugValuesAfterBootstrap.getValue() ? "application" : null, false);
@@ -537,7 +529,7 @@
             return;
         }
 
-        if (CompilationTask.withinEnqueue.get()) {
+        if (CompilationTask.isWithinEnqueue()) {
             // This is required to avoid deadlocking a compiler thread. The issue is that a
             // java.util.concurrent.BlockingQueue is used to implement the compilation worker
             // queues. If a compiler thread triggers a compilation, then it may be blocked trying
@@ -547,8 +539,7 @@
 
         // Don't allow blocking compiles from CompilerThreads
         boolean block = blocking && !(Thread.currentThread() instanceof CompilerThread);
-        CompilationTask.withinEnqueue.set(Boolean.TRUE);
-        try {
+        try (CompilationTask.BeginEnqueue beginEnqueue = new CompilationTask.BeginEnqueue()) {
             if (method.tryToQueueForCompilation()) {
                 assert method.isQueuedForCompilation();
 
@@ -565,8 +556,6 @@
                     // The compile queue was already shut down.
                 }
             }
-        } finally {
-            CompilationTask.withinEnqueue.set(Boolean.FALSE);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Fri Feb 28 16:19:10 2014 +0100
@@ -336,7 +336,7 @@
             ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false));
             ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph);
             ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false));
-            IntegerAddNode add = graph.unique(new IntegerAddNode(Kind.Long, read, counter.getIncrement()));
+            IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement()));
             WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false));
 
             graph.addBeforeFixed(counter, thread);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Fri Feb 28 16:19:10 2014 +0100
@@ -27,7 +27,7 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.meta.HotSpotHostForeignCallsProvider.*;
+import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
 import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
@@ -97,325 +97,40 @@
 
     @Override
     public void lower(Node n, LoweringTool tool) {
-        HotSpotVMConfig config = runtime.getConfig();
         StructuredGraph graph = (StructuredGraph) n.graph();
 
-        Kind wordKind = runtime.getTarget().wordKind;
         if (n instanceof ArrayLengthNode) {
-            ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
-            ValueNode array = arrayLengthNode.array();
-            ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt(),
-                            BarrierType.NONE, false));
-            arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool));
-            graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
+            lowerArrayLengthNode((ArrayLengthNode) n, tool);
         } else if (n instanceof Invoke) {
-            Invoke invoke = (Invoke) n;
-            if (invoke.callTarget() instanceof MethodCallTargetNode) {
-
-                MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-                NodeInputList<ValueNode> parameters = callTarget.arguments();
-                ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
-                GuardingNode receiverNullCheck = null;
-                if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !ObjectStamp.isObjectNonNull(receiver)) {
-                    receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
-                    invoke.setGuard(receiverNullCheck);
-                }
-                JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
-
-                LoweredCallTargetNode loweredCallTarget = null;
-                if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
-
-                    HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
-                    if (!hsMethod.getDeclaringClass().isInterface()) {
-                        if (hsMethod.isInVirtualMethodTable()) {
-                            int vtableEntryOffset = hsMethod.vtableEntryOffset();
-                            assert vtableEntryOffset > 0;
-                            FloatingReadNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
-
-                            ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
-                            // We use LocationNode.ANY_LOCATION for the reads that access the
-                            // compiled code entry as HotSpot does not guarantee they are final
-                            // values.
-                            ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph),
-                                            StampFactory.forKind(wordKind), BarrierType.NONE, false));
-
-                            loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
-                                            CallingConvention.Type.JavaCall));
-
-                            graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
-                            graph.addAfterFixed(metaspaceMethod, compiledEntry);
-                        }
-                    }
-                }
-
-                if (loweredCallTarget == null) {
-                    loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
-                                    callTarget.invokeKind()));
-                }
-                callTarget.replaceAndDelete(loweredCallTarget);
-            }
+            lowerInvoke((Invoke) n, tool, graph);
         } else if (n instanceof LoadFieldNode) {
-            LoadFieldNode loadField = (LoadFieldNode) n;
-            HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
-            ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : loadField.object();
-            assert loadField.kind() != Kind.Illegal;
-            BarrierType barrierType = getFieldLoadBarrierType(field);
-            ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object)));
-            graph.replaceFixedWithFixed(loadField, memoryRead);
-            memoryRead.setGuard(createNullCheck(object, memoryRead, tool));
-
-            if (loadField.isVolatile()) {
-                MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
-                graph.addBeforeFixed(memoryRead, preMembar);
-                MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
-                graph.addAfterFixed(memoryRead, postMembar);
-            }
+            lowerLoadFieldNode((LoadFieldNode) n, tool);
         } else if (n instanceof StoreFieldNode) {
-            StoreFieldNode storeField = (StoreFieldNode) n;
-            HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
-            ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : storeField.object();
-            BarrierType barrierType = getFieldStoreBarrierType(storeField);
-            WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object));
-            memoryWrite.setStateAfter(storeField.stateAfter());
-            graph.replaceFixedWithFixed(storeField, memoryWrite);
-            memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool));
-            FixedWithNextNode last = memoryWrite;
-            FixedWithNextNode first = memoryWrite;
-
-            if (storeField.isVolatile()) {
-                MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
-                graph.addBeforeFixed(first, preMembar);
-                MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
-                graph.addAfterFixed(last, postMembar);
-            }
+            lowerStoreFieldNode((StoreFieldNode) n, tool);
         } else if (n instanceof CompareAndSwapNode) {
-            // Separate out GC barrier semantics
-            CompareAndSwapNode cas = (CompareAndSwapNode) n;
-            LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1);
-            LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, cas.expected(), cas.newValue(), getCompareAndSwapBarrier(cas),
-                            cas.expected().kind() == Kind.Object));
-            atomicNode.setStateAfter(cas.stateAfter());
-            graph.replaceFixedWithFixed(cas, atomicNode);
+            lowerCompareAndSwapNode((CompareAndSwapNode) n);
         } else if (n instanceof LoadIndexedNode) {
-            LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
-            Kind elementKind = loadIndexed.elementKind();
-            LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
-            ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object));
-            memoryRead.setGuard(createBoundsCheck(loadIndexed, tool));
-            graph.replaceFixedWithFixed(loadIndexed, memoryRead);
+            lowerLoadIndexedNode((LoadIndexedNode) n, tool);
         } else if (n instanceof StoreIndexedNode) {
-            StoreIndexedNode storeIndexed = (StoreIndexedNode) n;
-            GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
-            Kind elementKind = storeIndexed.elementKind();
-            LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false);
-            ValueNode value = storeIndexed.value();
-            ValueNode array = storeIndexed.array();
-
-            CheckCastNode checkcastNode = null;
-            CheckCastDynamicNode checkcastDynamicNode = null;
-            if (elementKind == Kind.Object && !ObjectStamp.isObjectAlwaysNull(value)) {
-                // Store check!
-                ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array);
-                if (arrayType != null && ObjectStamp.isExactType(array)) {
-                    ResolvedJavaType elementType = arrayType.getComponentType();
-                    if (!MetaUtil.isJavaLangObject(elementType)) {
-                        checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true));
-                        graph.addBeforeFixed(storeIndexed, checkcastNode);
-                        value = checkcastNode;
-                    }
-                } else {
-                    FloatingReadNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck);
-                    LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
-                    /*
-                     * 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.
-                     */
-                    FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed)));
-                    checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
-                    graph.addBeforeFixed(storeIndexed, checkcastDynamicNode);
-                    value = checkcastDynamicNode;
-                }
-            }
-            BarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
-            WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType, elementKind == Kind.Object));
-            memoryWrite.setGuard(boundsCheck);
-            memoryWrite.setStateAfter(storeIndexed.stateAfter());
-            graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
-
-            // Lower the associated checkcast node.
-            if (checkcastNode != null) {
-                checkcastNode.lower(tool);
-            } else if (checkcastDynamicNode != null) {
-                checkcastDynamicSnippets.lower(checkcastDynamicNode, tool);
-            }
+            lowerStoreIndexedNode((StoreIndexedNode) n, tool);
         } else if (n instanceof UnsafeLoadNode) {
-            UnsafeLoadNode load = (UnsafeLoadNode) n;
-            if (load.getGuardingCondition() != null) {
-                boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
-                ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition()));
-                LocationNode location = createLocation(load);
-                ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), valueAnchorNode, BarrierType.NONE, compressible));
-                load.replaceAtUsages(memoryRead);
-                graph.replaceFixedWithFixed(load, valueAnchorNode);
-                graph.addAfterFixed(valueAnchorNode, memoryRead);
-            } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
-                assert load.kind() != Kind.Illegal;
-                boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
-                if (addReadBarrier(load)) {
-                    unsafeLoadSnippets.lower(load, tool);
-                } else {
-                    LocationNode location = createLocation(load);
-                    ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), BarrierType.NONE, compressible));
-                    // An unsafe read must not float outside its block otherwise
-                    // it may float above an explicit null check on its object.
-                    memoryRead.setGuard(AbstractBeginNode.prevBegin(load));
-                    graph.replaceFixedWithFixed(load, memoryRead);
-                }
-            }
+            lowerUnsafeLoadNode((UnsafeLoadNode) n, tool);
         } else if (n instanceof UnsafeStoreNode) {
-            UnsafeStoreNode store = (UnsafeStoreNode) n;
-            LocationNode location = createLocation(store);
-            ValueNode object = store.object();
-            BarrierType barrierType = getUnsafeStoreBarrierType(store);
-            WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object));
-            write.setStateAfter(store.stateAfter());
-            graph.replaceFixedWithFixed(store, write);
+            lowerUnsafeStoreNode((UnsafeStoreNode) n);
         } else if (n instanceof LoadHubNode) {
-            if (graph.getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) {
-                LoadHubNode loadHub = (LoadHubNode) n;
-                assert loadHub.kind() == wordKind;
-                ValueNode object = loadHub.object();
-                GuardingNode guard = loadHub.getGuard();
-                FloatingReadNode hub = createReadHub(graph, wordKind, object, guard);
-                graph.replaceFloating(loadHub, hub);
-            }
+            lowerLoadHubNode((LoadHubNode) n);
         } else if (n instanceof LoadMethodNode) {
-            LoadMethodNode loadMethodNode = (LoadMethodNode) n;
-            ResolvedJavaMethod method = loadMethodNode.getMethod();
-            ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method);
-            graph.replaceFixed(loadMethodNode, metaspaceMethod);
+            lowerLoadMethodNode((LoadMethodNode) n);
         } else if (n instanceof StoreHubNode) {
-            StoreHubNode storeHub = (StoreHubNode) n;
-            WriteNode hub = createWriteHub(graph, wordKind, storeHub.getObject(), storeHub.getValue());
-            graph.replaceFixed(storeHub, hub);
+            lowerStoreHubNode((StoreHubNode) n, graph);
         } else if (n instanceof CommitAllocationNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                CommitAllocationNode commit = (CommitAllocationNode) n;
-                ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
-                BitSet omittedValues = new BitSet();
-                int valuePos = 0;
-                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                    VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
-                    int entryCount = virtual.entryCount();
-                    FixedWithNextNode newObject;
-                    if (virtual instanceof VirtualInstanceNode) {
-                        newObject = graph.add(new NewInstanceNode(virtual.type(), true));
-                    } else {
-                        newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true));
-                    }
-                    graph.addBeforeFixed(commit, newObject);
-                    allocations[objIndex] = newObject;
-                    for (int i = 0; i < entryCount; i++) {
-                        ValueNode value = commit.getValues().get(valuePos);
-                        if (value instanceof VirtualObjectNode) {
-                            value = allocations[commit.getVirtualObjects().indexOf(value)];
-                        }
-                        if (value == null) {
-                            omittedValues.set(valuePos);
-                        } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
-                            // Constant.illegal is always the defaultForKind, so it is skipped
-                            Kind valueKind = value.kind();
-                            Kind entryKind = virtual.entryKind(i);
-
-                            // Truffle requires some leniency in terms of what can be put where:
-                            Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind;
-                            assert valueKind.getStackKind() == entryKind.getStackKind() ||
-                                            (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode));
-                            ConstantLocationNode location;
-                            BarrierType barrierType;
-                            if (virtual instanceof VirtualInstanceNode) {
-                                ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
-                                location = ConstantLocationNode.create(INIT_LOCATION, accessKind, ((HotSpotResolvedJavaField) field).offset(), graph);
-                                barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
-                            } else {
-                                location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(entryKind) + i * getScalingFactor(entryKind), graph);
-                                barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE;
-                            }
-                            WriteNode write = new WriteNode(newObject, value, location, barrierType, entryKind == Kind.Object);
-                            graph.addAfterFixed(newObject, graph.add(write));
-                        }
-                        valuePos++;
-
-                    }
-                }
-                valuePos = 0;
-
-                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                    VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
-                    int entryCount = virtual.entryCount();
-                    ValueNode newObject = allocations[objIndex];
-                    for (int i = 0; i < entryCount; i++) {
-                        if (omittedValues.get(valuePos)) {
-                            ValueNode value = commit.getValues().get(valuePos);
-                            assert value instanceof VirtualObjectNode;
-                            ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
-                            if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
-                                assert virtual.entryKind(i) == Kind.Object && allocValue.kind() == Kind.Object;
-                                WriteNode write;
-                                if (virtual instanceof VirtualInstanceNode) {
-                                    VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
-                                    write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true), BarrierType.IMPRECISE, true);
-                                } else {
-                                    write = new WriteNode(newObject, allocValue, createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE, true);
-                                }
-                                graph.addBeforeFixed(commit, graph.add(write));
-                            }
-                        }
-                        valuePos++;
-                    }
-                }
-
-                finishAllocatedObjects(tool, commit, allocations);
-                graph.removeFixed(commit);
-            }
+            lowerCommitAllocationNode((CommitAllocationNode) n, tool);
         } else if (n instanceof OSRStartNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                OSRStartNode osrStart = (OSRStartNode) n;
-                StartNode newStart = graph.add(new StartNode());
-                ParameterNode buffer = graph.unique(new ParameterNode(0, StampFactory.forKind(wordKind)));
-                ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
-                migrationEnd.setStateAfter(osrStart.stateAfter());
-
-                newStart.setNext(migrationEnd);
-                FixedNode next = osrStart.next();
-                osrStart.setNext(null);
-                migrationEnd.setNext(next);
-                graph.setStart(newStart);
-
-                // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
-                int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
-                for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
-                    int size = FrameStateBuilder.stackSlots(osrLocal.kind());
-                    int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
-                    IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1);
-                    ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false));
-                    osrLocal.replaceAndDelete(load);
-                    graph.addBeforeFixed(migrationEnd, load);
-                }
-                osrStart.replaceAtUsages(newStart);
-                osrStart.safeDelete();
-            }
+            lowerOSRStartNode((OSRStartNode) n);
         } else if (n instanceof DynamicCounterNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                BenchmarkCounters.lower((DynamicCounterNode) n, registers, runtime.getConfig(), wordKind);
-            }
+            lowerDynamicCounterNode((DynamicCounterNode) n);
         } else if (n instanceof DeferredForeignCallNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
-                DeferredForeignCallNode deferred = (DeferredForeignCallNode) n;
-                ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, deferred.getDescriptor(), deferred.getArguments()));
-                graph.replaceFixedWithFixed(deferred, foreignCallNode);
-            }
+            lowerDeferredForeignCallNode((DeferredForeignCallNode) n);
         } else if (n instanceof CheckCastDynamicNode) {
             checkcastDynamicSnippets.lower((CheckCastDynamicNode) n, tool);
         } else if (n instanceof InstanceOfNode) {
@@ -480,8 +195,355 @@
         } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode) {
             /* No lowering, we generate LIR directly for these nodes. */
         } else {
-            assert false : "Node implementing Lowerable not handled: " + n;
-            throw GraalInternalError.shouldNotReachHere();
+            throw GraalInternalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
+        }
+    }
+
+    private void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) {
+        StructuredGraph graph = arrayLengthNode.graph();
+        ValueNode array = arrayLengthNode.array();
+        ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, graph),
+                        StampFactory.positiveInt(), BarrierType.NONE, false));
+        arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool));
+        graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
+    }
+
+    private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) {
+        if (invoke.callTarget() instanceof MethodCallTargetNode) {
+            MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+            NodeInputList<ValueNode> parameters = callTarget.arguments();
+            ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
+            GuardingNode receiverNullCheck = null;
+            if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !ObjectStamp.isObjectNonNull(receiver)) {
+                receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
+                invoke.setGuard(receiverNullCheck);
+            }
+            JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
+
+            LoweredCallTargetNode loweredCallTarget = null;
+            if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
+
+                HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
+                if (!hsMethod.getDeclaringClass().isInterface()) {
+                    if (hsMethod.isInVirtualMethodTable()) {
+                        int vtableEntryOffset = hsMethod.vtableEntryOffset();
+                        assert vtableEntryOffset > 0;
+                        Kind wordKind = runtime.getTarget().wordKind;
+                        FloatingReadNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
+
+                        ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
+                        // We use LocationNode.ANY_LOCATION for the reads that access the
+                        // compiled code entry as HotSpot does not guarantee they are final
+                        // values.
+                        ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph),
+                                        StampFactory.forKind(wordKind), BarrierType.NONE, false));
+
+                        loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
+                                        CallingConvention.Type.JavaCall));
+
+                        graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
+                        graph.addAfterFixed(metaspaceMethod, compiledEntry);
+                    }
+                }
+            }
+
+            if (loweredCallTarget == null) {
+                loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
+                                callTarget.invokeKind()));
+            }
+            callTarget.replaceAndDelete(loweredCallTarget);
+        }
+    }
+
+    private void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
+        StructuredGraph graph = loadField.graph();
+        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
+        ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : loadField.object();
+        assert loadField.kind() != Kind.Illegal;
+        BarrierType barrierType = getFieldLoadBarrierType(field);
+        ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object)));
+        graph.replaceFixedWithFixed(loadField, memoryRead);
+        memoryRead.setGuard(createNullCheck(object, memoryRead, tool));
+
+        if (loadField.isVolatile()) {
+            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
+            graph.addBeforeFixed(memoryRead, preMembar);
+            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
+            graph.addAfterFixed(memoryRead, postMembar);
+        }
+    }
+
+    private void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
+        StructuredGraph graph = storeField.graph();
+        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
+        ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : storeField.object();
+        BarrierType barrierType = getFieldStoreBarrierType(storeField);
+        WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object));
+        memoryWrite.setStateAfter(storeField.stateAfter());
+        graph.replaceFixedWithFixed(storeField, memoryWrite);
+        memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool));
+        FixedWithNextNode last = memoryWrite;
+        FixedWithNextNode first = memoryWrite;
+
+        if (storeField.isVolatile()) {
+            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+            graph.addBeforeFixed(first, preMembar);
+            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
+            graph.addAfterFixed(last, postMembar);
+        }
+    }
+
+    private static void lowerCompareAndSwapNode(CompareAndSwapNode cas) {
+        // Separate out GC barrier semantics
+        StructuredGraph graph = cas.graph();
+        LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1);
+        LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, cas.expected(), cas.newValue(), getCompareAndSwapBarrier(cas),
+                        cas.expected().kind() == Kind.Object));
+        atomicNode.setStateAfter(cas.stateAfter());
+        graph.replaceFixedWithFixed(cas, atomicNode);
+    }
+
+    private void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) {
+        StructuredGraph graph = loadIndexed.graph();
+        Kind elementKind = loadIndexed.elementKind();
+        LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
+        ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object));
+        memoryRead.setGuard(createBoundsCheck(loadIndexed, tool));
+        graph.replaceFixedWithFixed(loadIndexed, memoryRead);
+    }
+
+    private void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
+        StructuredGraph graph = storeIndexed.graph();
+        GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
+        Kind elementKind = storeIndexed.elementKind();
+        LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false);
+        ValueNode value = storeIndexed.value();
+        ValueNode array = storeIndexed.array();
+
+        CheckCastNode checkcastNode = null;
+        CheckCastDynamicNode checkcastDynamicNode = null;
+        if (elementKind == Kind.Object && !ObjectStamp.isObjectAlwaysNull(value)) {
+            // Store check!
+            ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array);
+            if (arrayType != null && ObjectStamp.isExactType(array)) {
+                ResolvedJavaType elementType = arrayType.getComponentType();
+                if (!MetaUtil.isJavaLangObject(elementType)) {
+                    checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true));
+                    graph.addBeforeFixed(storeIndexed, checkcastNode);
+                    value = checkcastNode;
+                }
+            } else {
+                Kind wordKind = runtime.getTarget().wordKind;
+                FloatingReadNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck);
+                LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, runtime.getConfig().arrayClassElementOffset, graph);
+                /*
+                 * 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.
+                 */
+                FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed)));
+                checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
+                graph.addBeforeFixed(storeIndexed, checkcastDynamicNode);
+                value = checkcastDynamicNode;
+            }
+        }
+        BarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
+        WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType, elementKind == Kind.Object));
+        memoryWrite.setGuard(boundsCheck);
+        memoryWrite.setStateAfter(storeIndexed.stateAfter());
+        graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
+
+        // Lower the associated checkcast node.
+        if (checkcastNode != null) {
+            checkcastNode.lower(tool);
+        } else if (checkcastDynamicNode != null) {
+            checkcastDynamicSnippets.lower(checkcastDynamicNode, tool);
+        }
+    }
+
+    private void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) {
+        StructuredGraph graph = load.graph();
+        if (load.getGuardingCondition() != null) {
+            boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
+            ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition()));
+            LocationNode location = createLocation(load);
+            ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), valueAnchorNode, BarrierType.NONE, compressible));
+            load.replaceAtUsages(memoryRead);
+            graph.replaceFixedWithFixed(load, valueAnchorNode);
+            graph.addAfterFixed(valueAnchorNode, memoryRead);
+        } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
+            assert load.kind() != Kind.Illegal;
+            boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
+            if (addReadBarrier(load)) {
+                unsafeLoadSnippets.lower(load, tool);
+            } else {
+                LocationNode location = createLocation(load);
+                ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), BarrierType.NONE, compressible));
+                // An unsafe read must not float outside its block otherwise
+                // it may float above an explicit null check on its object.
+                memoryRead.setGuard(AbstractBeginNode.prevBegin(load));
+                graph.replaceFixedWithFixed(load, memoryRead);
+            }
+        }
+    }
+
+    private static void lowerUnsafeStoreNode(UnsafeStoreNode store) {
+        StructuredGraph graph = store.graph();
+        LocationNode location = createLocation(store);
+        ValueNode object = store.object();
+        BarrierType barrierType = getUnsafeStoreBarrierType(store);
+        WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object));
+        write.setStateAfter(store.stateAfter());
+        graph.replaceFixedWithFixed(store, write);
+    }
+
+    private void lowerLoadHubNode(LoadHubNode loadHub) {
+        StructuredGraph graph = loadHub.graph();
+        if (graph.getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) {
+            Kind wordKind = runtime.getTarget().wordKind;
+            assert loadHub.kind() == wordKind;
+            ValueNode object = loadHub.object();
+            GuardingNode guard = loadHub.getGuard();
+            FloatingReadNode hub = createReadHub(graph, wordKind, object, guard);
+            graph.replaceFloating(loadHub, hub);
+        }
+    }
+
+    private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
+        StructuredGraph graph = loadMethodNode.graph();
+        ResolvedJavaMethod method = loadMethodNode.getMethod();
+        ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method);
+        graph.replaceFixed(loadMethodNode, metaspaceMethod);
+    }
+
+    private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) {
+        WriteNode hub = createWriteHub(graph, runtime.getTarget().wordKind, storeHub.getObject(), storeHub.getValue());
+        graph.replaceFixed(storeHub, hub);
+    }
+
+    private void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
+        StructuredGraph graph = commit.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
+            BitSet omittedValues = new BitSet();
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+                FixedWithNextNode newObject;
+                if (virtual instanceof VirtualInstanceNode) {
+                    newObject = graph.add(new NewInstanceNode(virtual.type(), true));
+                } else {
+                    newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true));
+                }
+                graph.addBeforeFixed(commit, newObject);
+                allocations[objIndex] = newObject;
+                for (int i = 0; i < entryCount; i++) {
+                    ValueNode value = commit.getValues().get(valuePos);
+                    if (value instanceof VirtualObjectNode) {
+                        value = allocations[commit.getVirtualObjects().indexOf(value)];
+                    }
+                    if (value == null) {
+                        omittedValues.set(valuePos);
+                    } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
+                        // Constant.illegal is always the defaultForKind, so it is skipped
+                        Kind valueKind = value.kind();
+                        Kind entryKind = virtual.entryKind(i);
+
+                        // Truffle requires some leniency in terms of what can be put where:
+                        Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind;
+                        assert valueKind.getStackKind() == entryKind.getStackKind() ||
+                                        (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode));
+                        ConstantLocationNode location;
+                        BarrierType barrierType;
+                        if (virtual instanceof VirtualInstanceNode) {
+                            ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
+                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, ((HotSpotResolvedJavaField) field).offset(), graph);
+                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
+                        } else {
+                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(entryKind) + i * getScalingFactor(entryKind), graph);
+                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE;
+                        }
+                        WriteNode write = new WriteNode(newObject, value, location, barrierType, entryKind == Kind.Object);
+                        graph.addAfterFixed(newObject, graph.add(write));
+                    }
+                    valuePos++;
+
+                }
+            }
+            valuePos = 0;
+
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+                ValueNode newObject = allocations[objIndex];
+                for (int i = 0; i < entryCount; i++) {
+                    if (omittedValues.get(valuePos)) {
+                        ValueNode value = commit.getValues().get(valuePos);
+                        assert value instanceof VirtualObjectNode;
+                        ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
+                        if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
+                            assert virtual.entryKind(i) == Kind.Object && allocValue.kind() == Kind.Object;
+                            WriteNode write;
+                            if (virtual instanceof VirtualInstanceNode) {
+                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
+                                write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true), BarrierType.IMPRECISE, true);
+                            } else {
+                                write = new WriteNode(newObject, allocValue, createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE, true);
+                            }
+                            graph.addBeforeFixed(commit, graph.add(write));
+                        }
+                    }
+                    valuePos++;
+                }
+            }
+
+            finishAllocatedObjects(tool, commit, allocations);
+            graph.removeFixed(commit);
+        }
+    }
+
+    private void lowerOSRStartNode(OSRStartNode osrStart) {
+        StructuredGraph graph = osrStart.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            StartNode newStart = graph.add(new StartNode());
+            ParameterNode buffer = graph.unique(new ParameterNode(0, StampFactory.forKind(runtime.getTarget().wordKind)));
+            ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
+            migrationEnd.setStateAfter(osrStart.stateAfter());
+
+            newStart.setNext(migrationEnd);
+            FixedNode next = osrStart.next();
+            osrStart.setNext(null);
+            migrationEnd.setNext(next);
+            graph.setStart(newStart);
+
+            // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
+            int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
+            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
+                int size = FrameStateBuilder.stackSlots(osrLocal.kind());
+                int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
+                IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1);
+                ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false));
+                osrLocal.replaceAndDelete(load);
+                graph.addBeforeFixed(migrationEnd, load);
+            }
+            osrStart.replaceAtUsages(newStart);
+            osrStart.safeDelete();
+        }
+    }
+
+    private void lowerDynamicCounterNode(DynamicCounterNode n) {
+        StructuredGraph graph = n.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+            BenchmarkCounters.lower(n, registers, runtime.getConfig(), runtime.getTarget().wordKind);
+        }
+    }
+
+    private void lowerDeferredForeignCallNode(DeferredForeignCallNode deferred) {
+        StructuredGraph graph = deferred.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
+            ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, deferred.getDescriptor(), deferred.getArguments()));
+            graph.replaceFixedWithFixed(deferred, foreignCallNode);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -22,31 +22,18 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
+import java.lang.reflect.*;
+import java.util.*;
 
-import com.oracle.graal.api.meta.Constant;
-import com.oracle.graal.api.meta.JavaType;
-import com.oracle.graal.api.meta.ResolvedJavaField;
-import com.oracle.graal.api.meta.ResolvedJavaMethod;
-import com.oracle.graal.api.meta.ResolvedJavaType;
-import com.oracle.graal.graph.GraalInternalError;
-import com.oracle.graal.graph.NodeInputList;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.meta.HotSpotResolvedJavaMethod;
-import com.oracle.graal.hotspot.meta.HotSpotResolvedObjectType;
-import com.oracle.graal.hotspot.meta.HotSpotSignature;
-import com.oracle.graal.nodes.CallTargetNode;
-import com.oracle.graal.nodes.Invoke;
-import com.oracle.graal.nodes.InvokeNode;
-import com.oracle.graal.nodes.PiNode;
-import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.java.MethodCallTargetNode;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.java.SelfReplacingMethodCallTargetNode;
 import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.type.GenericStamp.*;
-import com.oracle.graal.replacements.nodes.MacroNode;
+import com.oracle.graal.replacements.nodes.*;
 
 /**
  * Common base class for method handle invoke nodes.
@@ -282,7 +269,7 @@
         // invoker's stamp would be wrong because it's a less concrete type
         // (usually java.lang.Object).
         InvokeNode invoke;
-        if (stamp() instanceof GenericStamp && ((GenericStamp) stamp()).type() == GenericStampType.Void) {
+        if (stamp() == StampFactory.forVoid()) {
             invoke = new InvokeNode(callTarget, getBci(), stamp());
         } else {
             invoke = new InvokeNode(callTarget, getBci());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Fri Feb 28 16:19:10 2014 +0100
@@ -35,6 +35,7 @@
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/GraphKit.java	Wed Feb 26 13:09:16 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,165 +0,0 @@
-/*
- * Copyright (c) 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.hotspot.stubs;
-
-import java.lang.reflect.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.*;
-import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.util.*;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.ReplacementsImpl.*;
-import com.oracle.graal.word.phases.*;
-
-/**
- * A utility for manually creating a graph. This will be expanded as necessary to support all
- * subsystems that employ manual graph creation (as opposed to {@linkplain GraphBuilderPhase
- * bytecode parsing} based graph creation).
- */
-public class GraphKit {
-
-    private final Providers providers;
-    private final StructuredGraph graph;
-    private FixedWithNextNode lastFixedNode;
-
-    public GraphKit(StructuredGraph graph, Providers providers) {
-        this.providers = providers;
-        this.graph = graph;
-        this.lastFixedNode = graph.start();
-    }
-
-    public StructuredGraph getGraph() {
-        return graph;
-    }
-
-    /**
-     * Ensures a floating node is added to or already present in the graph via {@link Graph#unique}.
-     * 
-     * @return a node similar to {@code node} if one exists, otherwise {@code node}
-     */
-    protected <T extends FloatingNode> T unique(T node) {
-        return graph.unique(node);
-    }
-
-    /**
-     * Appends a fixed node to the graph.
-     */
-    protected <T extends FixedNode> T append(T node) {
-        T result = graph.add(node);
-        assert lastFixedNode != null;
-        assert result.predecessor() == null;
-        graph.addAfterFixed(lastFixedNode, result);
-        if (result instanceof FixedWithNextNode) {
-            lastFixedNode = (FixedWithNextNode) result;
-        } else {
-            lastFixedNode = null;
-        }
-        return result;
-    }
-
-    /**
-     * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
-     * arguments.
-     * 
-     * @param declaringClass the class declaring the invoked method
-     * @param name the name of the invoked method
-     * @param args the arguments to the invocation
-     */
-    public InvokeNode createInvoke(Class<?> declaringClass, String name, ValueNode... args) {
-        ResolvedJavaMethod method = null;
-        for (Method m : declaringClass.getDeclaredMethods()) {
-            if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) {
-                assert method == null : "found more than one method in " + declaringClass + " named " + name;
-                method = providers.getMetaAccess().lookupJavaMethod(m);
-            }
-        }
-        assert method != null : "did not find method in " + declaringClass + " named " + name;
-        Signature signature = method.getSignature();
-        JavaType returnType = signature.getReturnType(null);
-        assert checkArgs(method, args);
-        MethodCallTargetNode callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, method, args, returnType));
-        InvokeNode invoke = append(new InvokeNode(callTarget, FrameState.UNKNOWN_BCI));
-        return invoke;
-    }
-
-    /**
-     * Determines if a given set of arguments is compatible with the signature of a given method.
-     * 
-     * @return true if {@code args} are compatible with the signature if {@code method}
-     * @throws AssertionError if {@code args} are not compatible with the signature if
-     *             {@code method}
-     */
-    public boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) {
-        Signature signature = method.getSignature();
-        if (signature.getParameterCount(false) != args.length) {
-            throw new AssertionError(graph + ": wrong number of arguments to " + method);
-        }
-        for (int i = 0; i != args.length; i++) {
-            Kind expected = signature.getParameterKind(i).getStackKind();
-            Kind actual = args[i].stamp().getStackKind();
-            if (expected != actual) {
-                throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of calls to " + method + " [" + actual + " != " + expected + "]");
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Rewrite all word types in the graph.
-     */
-    public void rewriteWordTypes() {
-        new WordTypeRewriterPhase(providers.getMetaAccess(), providers.getCodeCache().getTarget().wordKind).apply(graph);
-    }
-
-    /**
-     * {@linkplain #inline(InvokeNode) Inlines} all invocations currently in the graph.
-     */
-    public void inlineInvokes() {
-        for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) {
-            inline(invoke);
-        }
-
-        // Clean up all code that is now dead after inlining.
-        new DeadCodeEliminationPhase().apply(graph);
-        assert graph.getNodes().filter(InvokeNode.class).isEmpty();
-    }
-
-    /**
-     * Inlines a given invocation to a method. The graph of the inlined method is
-     * {@linkplain ReplacementsImpl#makeGraph processed} in the same manner as for snippets and
-     * method substitutions.
-     */
-    public void inline(InvokeNode invoke) {
-        ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
-        ReplacementsImpl repl = new ReplacementsImpl(providers, new Assumptions(false), providers.getCodeCache().getTarget());
-        StructuredGraph calleeGraph = repl.makeGraph(method, null, method, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
-        InliningUtil.inline(invoke, calleeGraph, false);
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Feb 28 16:19:10 2014 +0100
@@ -598,35 +598,35 @@
             switch (opcode) {
                 case IADD:
                 case LADD:
-                    v = new IntegerAddNode(result, x, y);
+                    v = new IntegerAddNode(StampFactory.forKind(result), x, y);
                     break;
                 case FADD:
                 case DADD:
-                    v = new FloatAddNode(result, x, y, isStrictFP);
+                    v = new FloatAddNode(StampFactory.forKind(result), x, y, isStrictFP);
                     break;
                 case ISUB:
                 case LSUB:
-                    v = new IntegerSubNode(result, x, y);
+                    v = new IntegerSubNode(StampFactory.forKind(result), x, y);
                     break;
                 case FSUB:
                 case DSUB:
-                    v = new FloatSubNode(result, x, y, isStrictFP);
+                    v = new FloatSubNode(StampFactory.forKind(result), x, y, isStrictFP);
                     break;
                 case IMUL:
                 case LMUL:
-                    v = new IntegerMulNode(result, x, y);
+                    v = new IntegerMulNode(StampFactory.forKind(result), x, y);
                     break;
                 case FMUL:
                 case DMUL:
-                    v = new FloatMulNode(result, x, y, isStrictFP);
+                    v = new FloatMulNode(StampFactory.forKind(result), x, y, isStrictFP);
                     break;
                 case FDIV:
                 case DDIV:
-                    v = new FloatDivNode(result, x, y, isStrictFP);
+                    v = new FloatDivNode(StampFactory.forKind(result), x, y, isStrictFP);
                     break;
                 case FREM:
                 case DREM:
-                    v = new FloatRemNode(result, x, y, isStrictFP);
+                    v = new FloatRemNode(StampFactory.forKind(result), x, y, isStrictFP);
                     break;
                 default:
                     throw new GraalInternalError("should not reach");
@@ -641,11 +641,11 @@
             switch (opcode) {
                 case IDIV:
                 case LDIV:
-                    v = new IntegerDivNode(result, x, y);
+                    v = new IntegerDivNode(StampFactory.forKind(result), x, y);
                     break;
                 case IREM:
                 case LREM:
-                    v = new IntegerRemNode(result, x, y);
+                    v = new IntegerRemNode(StampFactory.forKind(result), x, y);
                     break;
                 default:
                     throw new GraalInternalError("should not reach");
@@ -664,15 +664,15 @@
             switch (opcode) {
                 case ISHL:
                 case LSHL:
-                    v = new LeftShiftNode(kind, x, s);
+                    v = new LeftShiftNode(StampFactory.forKind(kind), x, s);
                     break;
                 case ISHR:
                 case LSHR:
-                    v = new RightShiftNode(kind, x, s);
+                    v = new RightShiftNode(StampFactory.forKind(kind), x, s);
                     break;
                 case IUSHR:
                 case LUSHR:
-                    v = new UnsignedRightShiftNode(kind, x, s);
+                    v = new UnsignedRightShiftNode(StampFactory.forKind(kind), x, s);
                     break;
                 default:
                     throw new GraalInternalError("should not reach");
@@ -683,19 +683,20 @@
         private void genLogicOp(Kind kind, int opcode) {
             ValueNode y = frameState.pop(kind);
             ValueNode x = frameState.pop(kind);
+            Stamp stamp = StampFactory.forKind(kind);
             BitLogicNode v;
             switch (opcode) {
                 case IAND:
                 case LAND:
-                    v = new AndNode(kind, x, y);
+                    v = new AndNode(stamp, x, y);
                     break;
                 case IOR:
                 case LOR:
-                    v = new OrNode(kind, x, y);
+                    v = new OrNode(stamp, x, y);
                     break;
                 case IXOR:
                 case LXOR:
-                    v = new XorNode(kind, x, y);
+                    v = new XorNode(stamp, x, y);
                     break;
                 default:
                     throw new GraalInternalError("should not reach");
@@ -740,7 +741,7 @@
             int delta = stream().readIncrement();
             ValueNode x = frameState.loadLocal(index);
             ValueNode y = appendConstant(Constant.forInt(delta));
-            frameState.storeLocal(index, append(new IntegerAddNode(Kind.Int, x, y)));
+            frameState.storeLocal(index, append(new IntegerAddNode(StampFactory.forKind(Kind.Int), x, y)));
         }
 
         private void genGoto() {
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Fri Feb 28 16:19:10 2014 +0100
@@ -554,7 +554,7 @@
                 case IDIV:
                 case IREM:
                     masm.cdql();
-                    exceptionOffset = masm.codeBuffer.position();
+                    exceptionOffset = masm.position();
                     masm.idivl(asRegister(src));
                     break;
 
@@ -562,7 +562,7 @@
                 case LDIV:
                 case LREM:
                     masm.cdqq();
-                    exceptionOffset = masm.codeBuffer.position();
+                    exceptionOffset = masm.position();
                     masm.idivq(asRegister(src));
                     break;
 
@@ -570,7 +570,7 @@
                 case IUREM:
                     // Must zero the high 64-bit word (in RDX) of the dividend
                     masm.xorq(AMD64.rdx, AMD64.rdx);
-                    exceptionOffset = masm.codeBuffer.position();
+                    exceptionOffset = masm.position();
                     masm.divl(asRegister(src));
                     break;
 
@@ -578,7 +578,7 @@
                 case LUREM:
                     // Must zero the high 64-bit word (in RDX) of the dividend
                     masm.xorq(AMD64.rdx, AMD64.rdx);
-                    exceptionOffset = masm.codeBuffer.position();
+                    exceptionOffset = masm.position();
                     masm.divq(asRegister(src));
                     break;
                 default:
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Fri Feb 28 16:19:10 2014 +0100
@@ -155,7 +155,7 @@
         if (align) {
             emitAlignmentForDirectCall(crb, masm);
         }
-        int before = masm.codeBuffer.position();
+        int before = masm.position();
         if (scratch != null) {
             // offset might not fit a 32-bit immediate, generate an
             // indirect call with a 64-bit immediate
@@ -164,7 +164,7 @@
         } else {
             masm.call();
         }
-        int after = masm.codeBuffer.position();
+        int after = masm.position();
         crb.recordDirectCall(before, after, callTarget, info);
         crb.recordExceptionHandlers(after, info);
         masm.ensureUniquePC();
@@ -172,7 +172,7 @@
 
     protected static void emitAlignmentForDirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
         // make sure that the displacement word of the call ends up word aligned
-        int offset = masm.codeBuffer.position();
+        int offset = masm.position();
         offset += crb.target.arch.getMachineCodeCallDisplacementOffset();
         int modulus = crb.target.wordSize;
         if (offset % modulus != 0) {
@@ -181,25 +181,25 @@
     }
 
     public static void directJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target) {
-        int before = masm.codeBuffer.position();
+        int before = masm.position();
         masm.jmp(0, true);
-        int after = masm.codeBuffer.position();
+        int after = masm.position();
         crb.recordDirectCall(before, after, target, null);
         masm.ensureUniquePC();
     }
 
     public static void directConditionalJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target, ConditionFlag cond) {
-        int before = masm.codeBuffer.position();
+        int before = masm.position();
         masm.jcc(cond, 0, true);
-        int after = masm.codeBuffer.position();
+        int after = masm.position();
         crb.recordDirectCall(before, after, target, null);
         masm.ensureUniquePC();
     }
 
     public static void indirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
-        int before = masm.codeBuffer.position();
+        int before = masm.position();
         masm.call(dst);
-        int after = masm.codeBuffer.position();
+        int after = masm.position();
         crb.recordIndirectCall(before, after, callTarget, info);
         crb.recordExceptionHandlers(after, info);
         masm.ensureUniquePC();
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Fri Feb 28 16:19:10 2014 +0100
@@ -198,7 +198,6 @@
                 masm.movl(idxScratchReg, indexReg);
             }
 
-            Buffer buf = masm.codeBuffer;
             // Compare index against jump table bounds
             int highKey = lowKey + targets.length - 1;
             if (lowKey != 0) {
@@ -215,9 +214,8 @@
             }
 
             // Set scratch to address of jump table
-            int leaPos = buf.position();
             masm.leaq(scratchReg, new AMD64Address(AMD64.rip, 0));
-            int afterLea = buf.position();
+            final int afterLea = masm.position();
 
             // Load jump table entry into scratch and jump to it
             masm.movslq(idxScratchReg, new AMD64Address(scratchReg, idxScratchReg, Scale.Times4, 0));
@@ -225,29 +223,29 @@
             masm.jmp(scratchReg);
 
             // Inserting padding so that jump table address is 4-byte aligned
-            if ((buf.position() & 0x3) != 0) {
-                masm.nop(4 - (buf.position() & 0x3));
+            if ((masm.position() & 0x3) != 0) {
+                masm.nop(4 - (masm.position() & 0x3));
             }
 
             // Patch LEA instruction above now that we know the position of the jump table
-            int jumpTablePos = buf.position();
-            buf.setPosition(leaPos);
-            masm.leaq(scratchReg, new AMD64Address(AMD64.rip, jumpTablePos - afterLea));
-            buf.setPosition(jumpTablePos);
+            // TODO this is ugly and should be done differently
+            final int jumpTablePos = masm.position();
+            final int leaDisplacementPosition = afterLea - 4;
+            masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition);
 
             // Emit jump table entries
             for (LabelRef target : targets) {
                 Label label = target.label();
-                int offsetToJumpTableBase = buf.position() - jumpTablePos;
+                int offsetToJumpTableBase = masm.position() - jumpTablePos;
                 if (label.isBound()) {
                     int imm32 = label.position() - jumpTablePos;
-                    buf.emitInt(imm32);
+                    masm.emitInt(imm32);
                 } else {
-                    label.addPatchAt(buf.position());
+                    label.addPatchAt(masm.position());
 
-                    buf.emitByte(0); // pseudo-opcode for jump table entry
-                    buf.emitShort(offsetToJumpTableBase);
-                    buf.emitByte(0); // padding to make jump table entry 4 bytes wide
+                    masm.emitByte(0); // pseudo-opcode for jump table entry
+                    masm.emitShort(offsetToJumpTableBase);
+                    masm.emitByte(0); // padding to make jump table entry 4 bytes wide
                 }
             }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Fri Feb 28 16:19:10 2014 +0100
@@ -122,7 +122,7 @@
         @Override
         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
             if (state != null) {
-                crb.recordImplicitException(masm.codeBuffer.position(), state);
+                crb.recordImplicitException(masm.position(), state);
             }
             emitMemAccess(crb, masm);
         }
@@ -329,7 +329,7 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            crb.recordImplicitException(masm.codeBuffer.position(), state);
+            crb.recordImplicitException(masm.position(), state);
             masm.nullCheck(asRegister(input));
         }
 
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Fri Feb 28 16:19:10 2014 +0100
@@ -146,7 +146,7 @@
         @Override
         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
             if (state != null) {
-                // crb.recordImplicitException(masm.codeBuffer.position(), state);
+                // crb.recordImplicitException(masm.position(), state);
                 throw new InternalError("NYI");
             }
             emitMemAccess(masm);
@@ -305,7 +305,7 @@
             encodePointer(masm, scratch, base, shift, alignment, testForNull);
             if (state != null) {
                 throw new InternalError("NYI");
-                // crb.recordImplicitException(masm.codeBuffer.position(), state);
+                // crb.recordImplicitException(masm.position(), state);
             }
             masm.emitStore(scratch, address.toAddress(), "u32");
         }
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java	Fri Feb 28 16:19:10 2014 +0100
@@ -266,8 +266,6 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) {
-            Buffer buf = masm.codeBuffer;
-
             // Compare index against jump table bounds
 
             int highKey = lowKey + targets.length - 1;
@@ -285,7 +283,7 @@
             }
 
             // address of jump table
-            int tablePos = buf.position();
+            int tablePos = masm.position();
 
             JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4);
             String name = "jumptable" + jt.position;
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Fri Feb 28 16:19:10 2014 +0100
@@ -252,7 +252,7 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) {
-            crb.recordImplicitException(masm.codeBuffer.position(), state);
+            crb.recordImplicitException(masm.position(), state);
             masm.nullCheck(asRegister(input));
         }
 
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java	Fri Feb 28 16:19:10 2014 +0100
@@ -147,7 +147,7 @@
         if (align) {
             // We don't need alignment on SPARC.
         }
-        int before = masm.codeBuffer.position();
+        int before = masm.position();
         if (scratch != null) {
             // offset might not fit a 30-bit displacement, generate an
             // indirect call with a 64-bit immediate
@@ -156,7 +156,7 @@
         } else {
             new Call(0).emit(masm);
         }
-        int after = masm.codeBuffer.position();
+        int after = masm.position();
         crb.recordDirectCall(before, after, callTarget, info);
         crb.recordExceptionHandlers(after, info);
         new Nop().emit(masm);  // delay slot
@@ -164,19 +164,19 @@
     }
 
     public static void indirectJmp(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget target) {
-        int before = masm.codeBuffer.position();
+        int before = masm.position();
         new Sethix(0L, dst, true).emit(masm);
         new Jmp(new SPARCAddress(dst, 0)).emit(masm);
-        int after = masm.codeBuffer.position();
+        int after = masm.position();
         crb.recordIndirectCall(before, after, target, null);
         new Nop().emit(masm);  // delay slot
         masm.ensureUniquePC();
     }
 
     public static void indirectCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
-        int before = masm.codeBuffer.position();
+        int before = masm.position();
         new Jmpl(dst, 0, o7).emit(masm);
-        int after = masm.codeBuffer.position();
+        int after = masm.position();
         crb.recordIndirectCall(before, after, callTarget, info);
         crb.recordExceptionHandlers(after, info);
         new Nop().emit(masm);  // delay slot
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Fri Feb 28 16:19:10 2014 +0100
@@ -234,7 +234,6 @@
             Register value = asIntReg(index);
             Register scratchReg = asLongReg(scratch);
 
-            Buffer buf = masm.codeBuffer;
             // Compare index against jump table bounds
             int highKey = lowKey + targets.length - 1;
             if (lowKey != 0) {
@@ -258,7 +257,7 @@
             new Nop().emit(masm);  // delay slot
 
             // address of jump table
-            int tablePos = buf.position();
+            int tablePos = masm.position();
 
             JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4);
             crb.compilationResult.addAnnotation(jt);
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Fri Feb 28 16:19:10 2014 +0100
@@ -120,7 +120,7 @@
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
             if (state != null) {
-                crb.recordImplicitException(masm.codeBuffer.position(), state);
+                crb.recordImplicitException(masm.position(), state);
             }
             emitMemAccess(masm);
         }
@@ -225,7 +225,7 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            crb.recordImplicitException(masm.codeBuffer.position(), state);
+            crb.recordImplicitException(masm.position(), state);
             new Ldx(new SPARCAddress(asRegister(input), 0), r0).emit(masm);
         }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InfopointOp.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InfopointOp.java	Fri Feb 28 16:19:10 2014 +0100
@@ -42,6 +42,6 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb) {
-        crb.recordInfopoint(crb.asm.codeBuffer.position(), state, reason);
+        crb.recordInfopoint(crb.asm.position(), state, reason);
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java	Fri Feb 28 16:19:10 2014 +0100
@@ -89,11 +89,11 @@
     public abstract static class BaseSwitchClosure implements SwitchClosure {
 
         private final CompilationResultBuilder crb;
-        private final AbstractAssembler masm;
+        private final Assembler masm;
         private final LabelRef[] keyTargets;
         private final LabelRef defaultTarget;
 
-        public BaseSwitchClosure(CompilationResultBuilder crb, AbstractAssembler masm, LabelRef[] keyTargets, LabelRef defaultTarget) {
+        public BaseSwitchClosure(CompilationResultBuilder crb, Assembler masm, LabelRef[] keyTargets, LabelRef defaultTarget) {
             this.crb = crb;
             this.masm = masm;
             this.keyTargets = keyTargets;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Fri Feb 28 16:19:10 2014 +0100
@@ -54,7 +54,7 @@
         }
     }
 
-    public final AbstractAssembler asm;
+    public final Assembler asm;
     public final CompilationResult compilationResult;
     public final TargetDescription target;
     public final CodeCacheProvider codeCache;
@@ -78,8 +78,7 @@
 
     private List<ExceptionInfo> exceptionInfoList;
 
-    public CompilationResultBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext,
-                    CompilationResult compilationResult) {
+    public CompilationResultBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext, CompilationResult compilationResult) {
         this.target = codeCache.getTarget();
         this.codeCache = codeCache;
         this.foreignCalls = foreignCalls;
@@ -97,15 +96,15 @@
     private static final CompilationResult.Mark[] NO_REFS = {};
 
     public CompilationResult.Mark recordMark(Object id) {
-        return compilationResult.recordMark(asm.codeBuffer.position(), id, NO_REFS);
+        return compilationResult.recordMark(asm.position(), id, NO_REFS);
     }
 
     public CompilationResult.Mark recordMark(Object id, CompilationResult.Mark... references) {
-        return compilationResult.recordMark(asm.codeBuffer.position(), id, references);
+        return compilationResult.recordMark(asm.position(), id, references);
     }
 
     public void blockComment(String s) {
-        compilationResult.addAnnotation(new CompilationResult.CodeComment(asm.codeBuffer.position(), s));
+        compilationResult.addAnnotation(new CompilationResult.CodeComment(asm.position(), s));
     }
 
     /**
@@ -114,7 +113,7 @@
      * the compilation result.
      */
     public void finish() {
-        compilationResult.setTargetCode(asm.codeBuffer.close(false), asm.codeBuffer.position());
+        compilationResult.setTargetCode(asm.close(false), asm.position());
 
         // Record exception handlers if they exist
         if (exceptionInfoList != null) {
@@ -159,7 +158,7 @@
 
     public void recordInlineDataInCode(Constant data) {
         assert data != null;
-        int pos = asm.codeBuffer.position();
+        int pos = asm.position();
         Debug.log("Inline data in code: pos = %d, data = %s", pos, data);
         compilationResult.recordInlineData(pos, data);
     }
@@ -171,7 +170,7 @@
 
     public AbstractAddress recordDataReferenceInCode(Data data) {
         assert data != null;
-        int pos = asm.codeBuffer.position();
+        int pos = asm.position();
         Debug.log("Data reference in code: pos = %d, data = %s", pos, data);
         compilationResult.recordDataReference(pos, data);
         return asm.getPlaceholder();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilderFactory.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilderFactory.java	Fri Feb 28 16:19:10 2014 +0100
@@ -34,7 +34,7 @@
     /**
      * Creates a new {@link CompilationResultBuilder}.
      */
-    CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext,
+    CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext,
                     CompilationResult compilationResult);
 
     /**
@@ -42,7 +42,7 @@
      */
     CompilationResultBuilderFactory Default = new CompilationResultBuilderFactory() {
 
-        public CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext,
+        public CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext,
                         CompilationResult compilationResult) {
             return new CompilationResultBuilder(codeCache, foreignCalls, frameMap, asm, frameContext, compilationResult);
         }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Fri Feb 28 16:19:10 2014 +0100
@@ -29,6 +29,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
 
 public class CountedLoopInfo {
 
@@ -52,18 +53,18 @@
 
     public ValueNode maxTripCountNode(boolean assumePositive) {
         StructuredGraph graph = iv.valueNode().graph();
-        Kind kind = iv.valueNode().kind();
+        Stamp stamp = iv.valueNode().stamp();
         IntegerArithmeticNode range = IntegerArithmeticNode.sub(graph, end, iv.initNode());
         if (oneOff) {
             if (iv.direction() == Direction.Up) {
-                range = IntegerArithmeticNode.add(graph, range, ConstantNode.forIntegerKind(kind, 1, graph));
+                range = IntegerArithmeticNode.add(graph, range, ConstantNode.forIntegerStamp(stamp, 1, graph));
             } else {
-                range = IntegerArithmeticNode.sub(graph, range, ConstantNode.forIntegerKind(kind, 1, graph));
+                range = IntegerArithmeticNode.sub(graph, range, ConstantNode.forIntegerStamp(stamp, 1, graph));
             }
         }
-        IntegerDivNode div = graph.add(new IntegerDivNode(kind, range, iv.strideNode()));
+        IntegerDivNode div = graph.add(new IntegerDivNode(iv.valueNode().stamp().unrestricted(), range, iv.strideNode()));
         graph.addBeforeFixed(loop.entryPoint(), div);
-        ConstantNode zero = ConstantNode.forIntegerKind(kind, 0, graph);
+        ConstantNode zero = ConstantNode.forIntegerStamp(stamp, 0, graph);
         if (assumePositive) {
             return div;
         }
@@ -137,19 +138,19 @@
         if (overflowGuard != null) {
             return overflowGuard;
         }
-        Kind kind = iv.valueNode().kind();
+        IntegerStamp stamp = (IntegerStamp) iv.valueNode().stamp();
         StructuredGraph graph = iv.valueNode().graph();
         CompareNode cond; // we use a negated guard with a < condition to achieve a >=
-        ConstantNode one = ConstantNode.forIntegerKind(kind, 1, graph);
+        ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph);
         if (iv.direction() == Direction.Up) {
-            IntegerArithmeticNode v1 = sub(graph, ConstantNode.forIntegerKind(kind, kind.getMaxValue(), graph), sub(graph, iv.strideNode(), one));
+            IntegerArithmeticNode v1 = sub(graph, ConstantNode.forIntegerStamp(stamp, IntegerStamp.defaultMaxValue(stamp.getBits(), stamp.isUnsigned()), graph), sub(graph, iv.strideNode(), one));
             if (oneOff) {
                 v1 = sub(graph, v1, one);
             }
             cond = graph.unique(new IntegerLessThanNode(v1, end));
         } else {
             assert iv.direction() == Direction.Down;
-            IntegerArithmeticNode v1 = add(graph, ConstantNode.forIntegerKind(kind, kind.getMinValue(), graph), sub(graph, one, iv.strideNode()));
+            IntegerArithmeticNode v1 = add(graph, ConstantNode.forIntegerStamp(stamp, IntegerStamp.defaultMinValue(stamp.getBits(), stamp.isUnsigned()), graph), sub(graph, one, iv.strideNode()));
             if (oneOff) {
                 v1 = add(graph, v1, one);
             }
@@ -161,7 +162,7 @@
         return overflowGuard;
     }
 
-    public Kind getKind() {
-        return iv.valueNode().kind();
+    public IntegerStamp getStamp() {
+        return (IntegerStamp) iv.valueNode().stamp();
     }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Fri Feb 28 16:19:10 2014 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.loop.phases;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
@@ -38,7 +37,7 @@
         if (context.getOptimisticOptimizations().useLoopLimitChecks()) {
             loops.detectedCountedLoops();
             for (LoopEx loop : loops.countedLoops()) {
-                if (loop.lirLoop().children.isEmpty() && loop.counted().getKind() == Kind.Int) {
+                if (loop.lirLoop().children.isEmpty() && loop.counted().getStamp().getBits() <= 32) {
                     boolean hasSafepoint = false;
                     for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
                         hasSafepoint |= loopEnd.canSafepoint();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -151,6 +151,16 @@
         }
     }
 
+    public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph) {
+        if (stamp instanceof PrimitiveStamp) {
+            return forPrimitive(stamp, constant, graph);
+        } else {
+            ConstantNode ret = forConstant(constant, metaAccess, graph);
+            assert ret.stamp().isCompatible(stamp);
+            return ret;
+        }
+    }
+
     /**
      * Returns a node for a Java primitive.
      */
@@ -319,6 +329,13 @@
         }
     }
 
+    /**
+     * Returns a node for a constant double that's compatible to a given stamp.
+     */
+    public static ConstantNode forFloatingStamp(Stamp stamp, double value, StructuredGraph graph) {
+        return forFloatingKind(stamp.getStackKind(), value, graph);
+    }
+
     public static ConstantNode defaultForKind(Kind kind, StructuredGraph graph) {
         switch (kind) {
             case Boolean:
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -30,10 +30,10 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "&")
-public final class AndNode extends BitLogicNode implements Canonicalizable {
+public final class AndNode extends BitLogicNode implements Canonicalizable, NarrowableArithmeticNode {
 
-    public AndNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    public AndNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
@@ -44,7 +44,7 @@
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        return Constant.forIntegerKind(kind(), inputs[0].asLong() & inputs[1].asLong(), null);
+        return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() & inputs[1].asLong());
     }
 
     @Override
@@ -53,28 +53,18 @@
             return x();
         }
         if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new AndNode(kind(), y(), x()));
+            return graph().unique(new AndNode(stamp(), y(), x()));
         }
         if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+            return ConstantNode.forPrimitive(stamp(), evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
-            if (kind() == Kind.Int) {
-                int c = y().asConstant().asInt();
-                if (c == -1) {
-                    return x();
-                }
-                if (c == 0) {
-                    return ConstantNode.forInt(0, graph());
-                }
-            } else {
-                assert kind() == Kind.Long;
-                long c = y().asConstant().asLong();
-                if (c == -1) {
-                    return x();
-                }
-                if (c == 0) {
-                    return ConstantNode.forLong(0, graph());
-                }
+            long rawY = y().asConstant().asLong();
+            long mask = IntegerStamp.defaultMask(PrimitiveStamp.getBits(stamp()));
+            if ((rawY & mask) == mask) {
+                return x();
+            }
+            if ((rawY & mask) == 0) {
+                return ConstantNode.forIntegerStamp(stamp(), 0, graph());
             }
             return BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
@@ -47,12 +46,12 @@
     /**
      * Creates a new BinaryNode instance.
      * 
-     * @param kind the result type of this instruction
+     * @param stamp the result type of this instruction
      * @param x the first input instruction
      * @param y the second input instruction
      */
-    public BinaryNode(Kind kind, ValueNode x, ValueNode y) {
-        super(StampFactory.forKind(kind));
+    public BinaryNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp);
         this.x = x;
         this.y = y;
     }
@@ -84,53 +83,38 @@
     }
 
     public static BinaryNode add(StructuredGraph graph, ValueNode x, ValueNode y) {
-        assert x.kind() == y.kind();
-        switch (x.kind()) {
-            case Byte:
-            case Char:
-            case Short:
-            case Int:
-            case Long:
-                return IntegerArithmeticNode.add(graph, x, y);
-            case Float:
-            case Double:
-                return graph.unique(new FloatAddNode(x.kind(), x, y, false));
-            default:
-                throw GraalInternalError.shouldNotReachHere();
+        assert x.stamp().isCompatible(y.stamp());
+        Stamp stamp = x.stamp();
+        if (stamp instanceof IntegerStamp) {
+            return IntegerArithmeticNode.add(graph, x, y);
+        } else if (stamp instanceof FloatStamp) {
+            return graph.unique(new FloatAddNode(stamp, x, y, false));
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
         }
     }
 
     public static BinaryNode sub(StructuredGraph graph, ValueNode x, ValueNode y) {
-        assert x.kind() == y.kind();
-        switch (x.kind()) {
-            case Byte:
-            case Char:
-            case Short:
-            case Int:
-            case Long:
-                return IntegerArithmeticNode.sub(graph, x, y);
-            case Float:
-            case Double:
-                return graph.unique(new FloatSubNode(x.kind(), x, y, false));
-            default:
-                throw GraalInternalError.shouldNotReachHere();
+        assert x.stamp().isCompatible(y.stamp());
+        Stamp stamp = x.stamp();
+        if (stamp instanceof IntegerStamp) {
+            return IntegerArithmeticNode.sub(graph, x, y);
+        } else if (stamp instanceof FloatStamp) {
+            return graph.unique(new FloatSubNode(stamp, x, y, false));
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
         }
     }
 
     public static BinaryNode mul(StructuredGraph graph, ValueNode x, ValueNode y) {
-        assert x.kind() == y.kind();
-        switch (x.kind()) {
-            case Byte:
-            case Char:
-            case Short:
-            case Int:
-            case Long:
-                return IntegerArithmeticNode.mul(graph, x, y);
-            case Float:
-            case Double:
-                return graph.unique(new FloatMulNode(x.kind(), x, y, false));
-            default:
-                throw GraalInternalError.shouldNotReachHere();
+        assert x.stamp().isCompatible(y.stamp());
+        Stamp stamp = x.stamp();
+        if (stamp instanceof IntegerStamp) {
+            return IntegerArithmeticNode.mul(graph, x, y);
+        } else if (stamp instanceof FloatStamp) {
+            return graph.unique(new FloatMulNode(stamp, x, y, false));
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -22,14 +22,14 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code LogicNode} class definition.
  */
-public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable {
+public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     /**
      * Constructs a new logic operation node.
@@ -37,44 +37,23 @@
      * @param x the first input into this node
      * @param y the second input into this node
      */
-    public BitLogicNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
-        assert kind == Kind.Int || kind == Kind.Long;
+    public BitLogicNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
+        assert stamp instanceof IntegerStamp;
     }
 
     public static BitLogicNode and(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind();
-        switch (v1.kind()) {
-            case Int:
-                return graph.unique(new AndNode(Kind.Int, v1, v2));
-            case Long:
-                return graph.unique(new AndNode(Kind.Long, v1, v2));
-            default:
-                throw ValueNodeUtil.shouldNotReachHere();
-        }
+        assert v1.stamp().isCompatible(v2.stamp());
+        return graph.unique(new AndNode(StampTool.and(v1.stamp(), v2.stamp()), v1, v2));
     }
 
     public static BitLogicNode or(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind();
-        switch (v1.kind()) {
-            case Int:
-                return graph.unique(new OrNode(Kind.Int, v1, v2));
-            case Long:
-                return graph.unique(new OrNode(Kind.Long, v1, v2));
-            default:
-                throw ValueNodeUtil.shouldNotReachHere();
-        }
+        assert v1.stamp().isCompatible(v2.stamp());
+        return graph.unique(new OrNode(StampTool.or(v1.stamp(), v2.stamp()), v1, v2));
     }
 
     public static BitLogicNode xor(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind();
-        switch (v1.kind()) {
-            case Int:
-                return graph.unique(new XorNode(Kind.Int, v1, v2));
-            case Long:
-                return graph.unique(new XorNode(Kind.Long, v1, v2));
-            default:
-                throw ValueNodeUtil.shouldNotReachHere();
-        }
+        assert v1.stamp().isCompatible(v2.stamp());
+        return graph.unique(new XorNode(StampTool.xor(v1.stamp(), v2.stamp()), v1, v2));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -49,8 +49,8 @@
     }
 
     public ConditionalNode(LogicNode condition, ValueNode trueValue, ValueNode falseValue) {
-        super(trueValue.kind(), trueValue, falseValue);
-        assert trueValue.kind() == falseValue.kind();
+        super(trueValue.stamp().meet(falseValue.stamp()), trueValue, falseValue);
+        assert trueValue.stamp().isCompatible(falseValue.stamp());
         this.condition = condition;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -39,8 +38,8 @@
         return y;
     }
 
-    public FixedBinaryNode(Kind kind, ValueNode x, ValueNode y) {
-        super(StampFactory.forKind(kind));
+    public FixedBinaryNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp);
         this.x = x;
         this.y = y;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -27,20 +27,22 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "+")
 public final class FloatAddNode extends FloatArithmeticNode implements Canonicalizable {
 
-    public FloatAddNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-        super(kind, x, y, isStrictFP);
+    public FloatAddNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
+        super(stamp, x, y, isStrictFP);
     }
 
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        if (kind() == Kind.Float) {
+        assert inputs[0].getKind() == inputs[1].getKind();
+        if (inputs[0].getKind() == Kind.Float) {
             return Constant.forFloat(inputs[0].asFloat() + inputs[1].asFloat());
         } else {
-            assert kind() == Kind.Double;
+            assert inputs[0].getKind() == Kind.Double;
             return Constant.forDouble(inputs[0].asDouble() + inputs[1].asDouble());
         }
     }
@@ -48,22 +50,14 @@
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new FloatAddNode(kind(), y(), x(), isStrictFP()));
+            return graph().unique(new FloatAddNode(stamp(), y(), x(), isStrictFP()));
         }
         if (x().isConstant()) {
             return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
-            if (kind() == Kind.Float) {
-                float c = y().asConstant().asFloat();
-                if (c == 0.0f) {
-                    return x();
-                }
-            } else {
-                assert kind() == Kind.Double;
-                double c = y().asConstant().asDouble();
-                if (c == 0.0) {
-                    return x();
-                }
+            Constant c = y().asConstant();
+            if ((c.getKind() == Kind.Float && c.asFloat() == 0.0f) || (c.getKind() == Kind.Double && c.asDouble() == 0.0)) {
+                return x();
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -22,17 +22,17 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
 
     private final boolean isStrictFP;
 
-    public FloatArithmeticNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-        super(kind, x, y);
-        assert kind.isNumericFloat();
+    public FloatArithmeticNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
+        super(stamp, x, y);
+        assert stamp instanceof FloatStamp;
         this.isStrictFP = isStrictFP;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -27,20 +27,22 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "/")
 public final class FloatDivNode extends FloatArithmeticNode implements Canonicalizable {
 
-    public FloatDivNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-        super(kind, x, y, isStrictFP);
+    public FloatDivNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
+        super(stamp, x, y, isStrictFP);
     }
 
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        if (kind() == Kind.Float) {
+        assert inputs[0].getKind() == inputs[1].getKind();
+        if (inputs[0].getKind() == Kind.Float) {
             return Constant.forFloat(inputs[0].asFloat() / inputs[1].asFloat());
         } else {
-            assert kind() == Kind.Double;
+            assert inputs[0].getKind() == Kind.Double;
             return Constant.forDouble(inputs[0].asDouble() / inputs[1].asDouble());
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "==")
 public final class FloatEqualsNode extends CompareNode {
@@ -37,8 +37,8 @@
      */
     public FloatEqualsNode(ValueNode x, ValueNode y) {
         super(x, y);
-        assert x.kind() == Kind.Double || x.kind() == Kind.Float;
-        assert y.kind() == Kind.Double || y.kind() == Kind.Float;
+        assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp;
+        assert x.stamp().isCompatible(y.stamp());
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "<")
 public final class FloatLessThanNode extends CompareNode {
@@ -42,8 +42,8 @@
      */
     public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) {
         super(x, y);
-        assert x.kind() == Kind.Double || x.kind() == Kind.Float;
-        assert y.kind() == Kind.Double || y.kind() == Kind.Float;
+        assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp;
+        assert x.stamp().isCompatible(y.stamp());
         this.unorderedIsTrue = unorderedIsTrue;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -27,20 +27,22 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "*")
 public final class FloatMulNode extends FloatArithmeticNode implements Canonicalizable {
 
-    public FloatMulNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-        super(kind, x, y, isStrictFP);
+    public FloatMulNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
+        super(stamp, x, y, isStrictFP);
     }
 
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        if (kind() == Kind.Float) {
+        assert inputs[0].getKind() == inputs[1].getKind();
+        if (inputs[0].getKind() == Kind.Float) {
             return Constant.forFloat(inputs[0].asFloat() * inputs[1].asFloat());
         } else {
-            assert kind() == Kind.Double;
+            assert inputs[0].getKind() == Kind.Double;
             return Constant.forDouble(inputs[0].asDouble() * inputs[1].asDouble());
         }
     }
@@ -48,7 +50,7 @@
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new FloatMulNode(kind(), y(), x(), isStrictFP()));
+            return graph().unique(new FloatMulNode(stamp(), y(), x(), isStrictFP()));
         }
         if (x().isConstant()) {
             return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -27,20 +27,22 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "%")
 public final class FloatRemNode extends FloatArithmeticNode implements Canonicalizable {
 
-    public FloatRemNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-        super(kind, x, y, isStrictFP);
+    public FloatRemNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
+        super(stamp, x, y, isStrictFP);
     }
 
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        if (kind() == Kind.Float) {
+        assert inputs[0].getKind() == inputs[1].getKind();
+        if (inputs[0].getKind() == Kind.Float) {
             return Constant.forFloat(inputs[0].asFloat() % inputs[1].asFloat());
         } else {
-            assert kind() == Kind.Double;
+            assert inputs[0].getKind() == Kind.Double;
             return Constant.forDouble(inputs[0].asDouble() % inputs[1].asDouble());
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -27,20 +27,22 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "-")
 public final class FloatSubNode extends FloatArithmeticNode implements Canonicalizable {
 
-    public FloatSubNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-        super(kind, x, y, isStrictFP);
+    public FloatSubNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
+        super(stamp, x, y, isStrictFP);
     }
 
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        if (kind() == Kind.Float) {
+        assert inputs[0].getKind() == inputs[1].getKind();
+        if (inputs[0].getKind() == Kind.Float) {
             return Constant.forFloat(inputs[0].asFloat() - inputs[1].asFloat());
         } else {
-            assert kind() == Kind.Double;
+            assert inputs[0].getKind() == Kind.Double;
             return Constant.forDouble(inputs[0].asDouble() - inputs[1].asDouble());
         }
     }
@@ -48,24 +50,25 @@
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x() == y()) {
-            return ConstantNode.forFloatingKind(kind(), 0.0f, graph());
+            return ConstantNode.forFloatingStamp(stamp(), 0.0f, graph());
         }
         if (x().isConstant() && y().isConstant()) {
             return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
-            if (kind() == Kind.Float) {
-                float c = y().asConstant().asFloat();
-                if (c == 0.0f) {
+            Constant c = y().asConstant();
+            if (c.getKind() == Kind.Float) {
+                float f = c.asFloat();
+                if (f == 0.0f) {
                     return x();
                 }
-                return graph().unique(new FloatAddNode(kind(), x(), ConstantNode.forFloat(-c, graph()), isStrictFP()));
+                return graph().unique(new FloatAddNode(stamp(), x(), ConstantNode.forFloat(-f, graph()), isStrictFP()));
             } else {
-                assert kind() == Kind.Double;
-                double c = y().asConstant().asDouble();
-                if (c == 0.0) {
+                assert c.getKind() == Kind.Double;
+                double d = c.asDouble();
+                if (d == 0.0) {
                     return x();
                 }
-                return graph().unique(new FloatAddNode(kind(), x(), ConstantNode.forDouble(-c, graph()), isStrictFP()));
+                return graph().unique(new FloatAddNode(stamp(), x(), ConstantNode.forDouble(-d, graph()), isStrictFP()));
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -30,10 +30,10 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "+")
-public class IntegerAddNode extends IntegerArithmeticNode implements Canonicalizable {
+public class IntegerAddNode extends IntegerArithmeticNode implements Canonicalizable, NarrowableArithmeticNode {
 
-    public IntegerAddNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    public IntegerAddNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
@@ -44,13 +44,13 @@
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        return Constant.forIntegerKind(kind(), inputs[0].asLong() + inputs[1].asLong(), null);
+        return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() + inputs[1].asLong());
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new IntegerAddNode(kind(), y(), x()));
+            return graph().unique(new IntegerAddNode(stamp(), y(), x()));
         }
         if (x() instanceof IntegerSubNode) {
             IntegerSubNode sub = (IntegerSubNode) x();
@@ -79,12 +79,7 @@
                 return reassociated;
             }
             if (c < 0) {
-                if (kind() == Kind.Int) {
-                    return IntegerArithmeticNode.sub(graph(), x(), ConstantNode.forInt((int) -c, graph()));
-                } else {
-                    assert kind() == Kind.Long;
-                    return IntegerArithmeticNode.sub(graph(), x(), ConstantNode.forLong(-c, graph()));
-                }
+                return IntegerArithmeticNode.sub(graph(), x(), ConstantNode.forIntegerStamp(stamp(), -c, graph()));
             }
         }
         if (x() instanceof NegateNode) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -22,29 +22,27 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
 
-    public IntegerArithmeticNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
-        assert kind.isNumericInteger();
+    public IntegerArithmeticNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
+        assert stamp instanceof IntegerStamp;
     }
 
     public static IntegerAddNode add(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind();
-        return graph.unique(new IntegerAddNode(v1.kind(), v1, v2));
+        return graph.unique(new IntegerAddNode(StampTool.add(v1.stamp(), v2.stamp()), v1, v2));
     }
 
     public static IntegerMulNode mul(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind();
-        return graph.unique(new IntegerMulNode(v1.kind(), v1, v2));
+        assert v1.stamp().isCompatible(v2.stamp());
+        return graph.unique(new IntegerMulNode(v1.stamp().unrestricted(), v1, v2));
     }
 
     public static IntegerSubNode sub(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind();
-        return graph.unique(new IntegerSubNode(v1.kind(), v1, v2));
+        return graph.unique(new IntegerSubNode(StampTool.sub(v1.stamp(), v2.stamp()), v1, v2));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -23,8 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -32,7 +30,7 @@
 /**
  * An {@code IntegerConvert} converts an integer to an integer of different width.
  */
-public abstract class IntegerConvertNode extends ConvertNode implements Canonicalizable, ArithmeticLIRLowerable {
+public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable {
 
     private final int resultBits;
 
@@ -61,8 +59,7 @@
         }
     }
 
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
+    protected ValueNode canonicalConvert() {
         if (getInput().stamp() instanceof IntegerStamp) {
             int inputBits = ((IntegerStamp) getInput().stamp()).getBits();
             if (inputBits == resultBits) {
@@ -73,7 +70,7 @@
             }
         }
 
-        return this;
+        return null;
     }
 
     public static ValueNode convert(ValueNode input, Stamp stamp) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
@@ -33,8 +32,8 @@
 @NodeInfo(shortName = "/")
 public class IntegerDivNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
 
-    public IntegerDivNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    public IntegerDivNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
@@ -45,16 +44,11 @@
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && y().isConstant()) {
-            long yConst = y().asConstant().asLong();
-            if (yConst == 0) {
+            long y = y().asConstant().asLong();
+            if (y == 0) {
                 return this; // this will trap, can not canonicalize
             }
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() / (int) yConst, graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() / yConst, graph());
-            }
+            return ConstantNode.forIntegerStamp(stamp(), x().asConstant().asLong() / y, graph());
         } else if (y().isConstant()) {
             long c = y().asConstant().asLong();
             if (c == 1) {
@@ -65,23 +59,18 @@
             }
             long abs = Math.abs(c);
             if (CodeUtil.isPowerOf2(abs) && x().stamp() instanceof IntegerStamp) {
+                Stamp unrestricted = stamp().unrestricted();
                 ValueNode dividend = x();
                 IntegerStamp stampX = (IntegerStamp) x().stamp();
                 int log2 = CodeUtil.log2(abs);
                 // no rounding if dividend is positive or if its low bits are always 0
                 if (stampX.canBeNegative() || (stampX.upMask() & (abs - 1)) != 0) {
-                    int bits;
-                    if (kind().getStackKind() == Kind.Int) {
-                        bits = 32;
-                    } else {
-                        assert kind() == Kind.Long;
-                        bits = 64;
-                    }
-                    RightShiftNode sign = graph().unique(new RightShiftNode(kind(), x(), ConstantNode.forInt(bits - 1, graph())));
-                    UnsignedRightShiftNode round = graph().unique(new UnsignedRightShiftNode(kind(), sign, ConstantNode.forInt(bits - log2, graph())));
+                    int bits = PrimitiveStamp.getBits(stamp());
+                    RightShiftNode sign = graph().unique(new RightShiftNode(unrestricted, x(), ConstantNode.forInt(bits - 1, graph())));
+                    UnsignedRightShiftNode round = graph().unique(new UnsignedRightShiftNode(unrestricted, sign, ConstantNode.forInt(bits - log2, graph())));
                     dividend = IntegerArithmeticNode.add(graph(), dividend, round);
                 }
-                RightShiftNode shift = graph().unique(new RightShiftNode(kind(), dividend, ConstantNode.forInt(log2, graph())));
+                RightShiftNode shift = graph().unique(new RightShiftNode(unrestricted, dividend, ConstantNode.forInt(log2, graph())));
                 if (c < 0) {
                     return graph().unique(new NegateNode(shift));
                 }
@@ -94,8 +83,9 @@
             IntegerSubNode integerSubNode = (IntegerSubNode) x();
             if (integerSubNode.y() instanceof IntegerRemNode) {
                 IntegerRemNode integerRemNode = (IntegerRemNode) integerSubNode.y();
-                if (integerSubNode.kind() == this.kind() && integerRemNode.kind() == this.kind() && integerSubNode.x() == integerRemNode.x() && this.y() == integerRemNode.y()) {
-                    return graph().add(new IntegerDivNode(kind(), integerSubNode.x(), this.y()));
+                if (integerSubNode.stamp().isCompatible(this.stamp()) && integerRemNode.stamp().isCompatible(this.stamp()) && integerSubNode.x() == integerRemNode.x() &&
+                                this.y() == integerRemNode.y()) {
+                    return graph().add(new IntegerDivNode(stamp(), integerSubNode.x(), this.y()));
                 }
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -28,24 +28,25 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "*")
-public class IntegerMulNode extends IntegerArithmeticNode implements Canonicalizable {
+public class IntegerMulNode extends IntegerArithmeticNode implements Canonicalizable, NarrowableArithmeticNode {
 
-    public IntegerMulNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    public IntegerMulNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        return Constant.forIntegerKind(kind(), inputs[0].asLong() * inputs[1].asLong(), null);
+        return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() * inputs[1].asLong());
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new IntegerMulNode(kind(), y(), x()));
+            return graph().unique(new IntegerMulNode(stamp(), y(), x()));
         }
         if (x().isConstant()) {
             return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
@@ -55,11 +56,11 @@
                 return x();
             }
             if (c == 0) {
-                return ConstantNode.defaultForKind(kind(), graph());
+                return ConstantNode.forIntegerStamp(stamp(), 0, graph());
             }
             long abs = Math.abs(c);
             if (abs > 0 && CodeUtil.isPowerOf2(abs)) {
-                LeftShiftNode shift = graph().unique(new LeftShiftNode(kind(), x(), ConstantNode.forInt(CodeUtil.log2(abs), graph())));
+                LeftShiftNode shift = graph().unique(new LeftShiftNode(stamp().unrestricted(), x(), ConstantNode.forInt(CodeUtil.log2(abs), graph())));
                 if (c < 0) {
                     return graph().unique(new NegateNode(shift));
                 } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
@@ -33,29 +32,24 @@
 @NodeInfo(shortName = "%")
 public class IntegerRemNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
 
-    public IntegerRemNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    public IntegerRemNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && y().isConstant()) {
-            long yConst = y().asConstant().asLong();
-            if (yConst == 0) {
+            long y = y().asConstant().asLong();
+            if (y == 0) {
                 return this; // this will trap, can not canonicalize
             }
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() % (int) yConst, graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() % yConst, graph());
-            }
+            return ConstantNode.forIntegerStamp(stamp(), x().asConstant().asLong() % y, graph());
         } else if (y().isConstant()) {
             long c = y().asConstant().asLong();
             if (c == 1 || c == -1) {
-                return ConstantNode.forIntegerKind(kind(), 0, graph());
+                return ConstantNode.forIntegerStamp(stamp(), 0, graph());
             } else if (c > 0 && CodeUtil.isPowerOf2(c) && x().stamp() instanceof IntegerStamp && ((IntegerStamp) x().stamp()).isPositive()) {
-                return graph().unique(new AndNode(kind(), x(), ConstantNode.forIntegerKind(kind(), c - 1, graph())));
+                return graph().unique(new AndNode(stamp(), x(), ConstantNode.forIntegerStamp(stamp(), c - 1, graph())));
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -30,10 +30,10 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "-")
-public class IntegerSubNode extends IntegerArithmeticNode implements Canonicalizable {
+public class IntegerSubNode extends IntegerArithmeticNode implements Canonicalizable, NarrowableArithmeticNode {
 
-    public IntegerSubNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    public IntegerSubNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
@@ -44,13 +44,13 @@
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        return Constant.forIntegerKind(kind(), inputs[0].asLong() - inputs[1].asLong(), null);
+        return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() - inputs[1].asLong());
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x() == y()) {
-            return ConstantNode.forIntegerKind(kind(), 0, graph());
+            return ConstantNode.forIntegerStamp(stamp(), 0, graph());
         }
         if (x() instanceof IntegerAddNode) {
             IntegerAddNode x = (IntegerAddNode) x();
@@ -98,12 +98,7 @@
                 return reassociated;
             }
             if (c < 0) {
-                if (kind() == Kind.Int) {
-                    return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forInt((int) -c, graph()));
-                } else {
-                    assert kind() == Kind.Long;
-                    return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forLong(-c, graph()));
-                }
+                return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forIntegerStamp(stamp(), -c, graph()));
             }
         } else if (x().isConstant()) {
             long c = x().asConstant().asLong();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -53,7 +53,7 @@
      * @param y the instruction that produces the second input to this instruction
      */
     public IntegerTestNode(ValueNode x, ValueNode y) {
-        assert (x == null && y == null) || x.kind() == y.kind();
+        assert (x == null && y == null) || x.stamp().isCompatible(y.stamp());
         this.x = x;
         this.y = y;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -32,8 +32,8 @@
 @NodeInfo(shortName = "<<")
 public final class LeftShiftNode extends ShiftNode implements Canonicalizable {
 
-    public LeftShiftNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    public LeftShiftNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
@@ -79,19 +79,19 @@
                         if (total != (total & mask)) {
                             return ConstantNode.forIntegerKind(kind(), 0, graph());
                         }
-                        return graph().unique(new LeftShiftNode(kind(), other.x(), ConstantNode.forInt(total, graph())));
+                        return graph().unique(new LeftShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph())));
                     } else if ((other instanceof RightShiftNode || other instanceof UnsignedRightShiftNode) && otherAmount == amount) {
                         if (kind() == Kind.Long) {
-                            return graph().unique(new AndNode(kind(), other.x(), ConstantNode.forLong(-1L << amount, graph())));
+                            return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forLong(-1L << amount, graph())));
                         } else {
                             assert kind() == Kind.Int;
-                            return graph().unique(new AndNode(kind(), other.x(), ConstantNode.forInt(-1 << amount, graph())));
+                            return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forInt(-1 << amount, graph())));
                         }
                     }
                 }
             }
             if (originalAmout != amount) {
-                return graph().unique(new LeftShiftNode(kind(), x(), ConstantNode.forInt(amount, graph())));
+                return graph().unique(new LeftShiftNode(stamp(), x(), ConstantNode.forInt(amount, graph())));
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -32,7 +32,7 @@
 /**
  * The {@code NarrowNode} converts an integer to a narrower integer.
  */
-public class NarrowNode extends IntegerConvertNode {
+public class NarrowNode extends IntegerConvertNode implements Simplifiable {
 
     public NarrowNode(ValueNode input, int resultBits) {
         super(StampTool.narrowingConversion(input.stamp(), resultBits), input, resultBits);
@@ -64,28 +64,70 @@
         return false;
     }
 
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
+    private ValueNode tryCanonicalize() {
+        ValueNode ret = canonicalConvert();
+        if (ret != null) {
+            return ret;
+        }
+
         if (getInput() instanceof NarrowNode) {
+            // zzzzzzzz yyyyxxxx -(narrow)-> yyyyxxxx -(narrow)-> xxxx
+            // ==> zzzzzzzz yyyyxxxx -(narrow)-> xxxx
             NarrowNode other = (NarrowNode) getInput();
             return graph().unique(new NarrowNode(other.getInput(), getResultBits()));
         } else if (getInput() instanceof IntegerConvertNode) {
             // SignExtendNode or ZeroExtendNode
             IntegerConvertNode other = (IntegerConvertNode) getInput();
             if (getResultBits() == other.getInputBits()) {
+                // xxxx -(extend)-> yyyy xxxx -(narrow)-> xxxx
+                // ==> no-op
                 return other.getInput();
             } else if (getResultBits() < other.getInputBits()) {
+                // yyyyxxxx -(extend)-> zzzzzzzz yyyyxxxx -(narrow)-> xxxx
+                // ==> yyyyxxxx -(narrow)-> xxxx
                 return graph().unique(new NarrowNode(other.getInput(), getResultBits()));
             } else {
                 if (other instanceof SignExtendNode) {
+                    // sxxx -(sign-extend)-> ssssssss sssssxxx -(narrow)-> sssssxxx
+                    // ==> sxxx -(sign-extend)-> sssssxxx
                     return graph().unique(new SignExtendNode(other.getInput(), getResultBits()));
                 } else if (other instanceof ZeroExtendNode) {
+                    // xxxx -(zero-extend)-> 00000000 00000xxx -(narrow)-> 0000xxxx
+                    // ==> xxxx -(zero-extend)-> 0000xxxx
                     return graph().unique(new ZeroExtendNode(other.getInput(), getResultBits()));
                 }
             }
         }
 
-        return super.canonical(tool);
+        return null;
+    }
+
+    private boolean tryNarrow(SimplifierTool tool, Stamp stamp, ValueNode node) {
+        boolean canNarrow = node instanceof NarrowableArithmeticNode && node.usages().count() == 1;
+
+        if (canNarrow) {
+            for (Node inputNode : node.inputs().snapshot()) {
+                ValueNode input = (ValueNode) inputNode;
+                if (!tryNarrow(tool, stamp, input)) {
+                    ValueNode narrow = graph().unique(new NarrowNode(input, getResultBits()));
+                    node.replaceFirstInput(input, narrow);
+                    tool.addToWorkList(narrow);
+                }
+            }
+            node.setStamp(stamp);
+        }
+
+        return canNarrow;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        ValueNode ret = tryCanonicalize();
+        if (ret != null) {
+            graph().replaceFloating(this, ret);
+        } else if (tryNarrow(tool, stamp().unrestricted(), getInput())) {
+            graph().replaceFloating(this, getInput());
+        }
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowableArithmeticNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 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.calc;
+
+/**
+ * Marker interface for nodes where it is valid to apply a {@link NarrowNode} to its inputs and do a
+ * narrow operation instead of doing the wide operation and applying the {@link NarrowNode} to the
+ * result.
+ */
+public interface NarrowableArithmeticNode {
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -32,7 +32,7 @@
 /**
  * The {@code NegateNode} node negates its operand.
  */
-public final class NegateNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
+public final class NegateNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     @Input private ValueNode x;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 /**
  * Returns -1, 0, or 1 if either x < y, x == y, or x > y. If the comparison is undecided (one of the
@@ -43,7 +44,7 @@
      *            less, false when greater.
      */
     public NormalizeCompareNode(ValueNode x, ValueNode y, boolean isUnorderedLess) {
-        super(Kind.Int, x, y);
+        super(StampFactory.forKind(Kind.Int), x, y);
         this.isUnorderedLess = isUnorderedLess;
     }
 
@@ -51,7 +52,7 @@
     public void lower(LoweringTool tool) {
         LogicNode equalComp;
         LogicNode lessComp;
-        if (x().kind() == Kind.Double || x().kind() == Kind.Float) {
+        if (x().stamp() instanceof FloatStamp) {
             equalComp = graph().unique(new FloatEqualsNode(x(), y()));
             lessComp = graph().unique(new FloatLessThanNode(x(), y(), isUnorderedLess));
         } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -32,7 +32,7 @@
 /**
  * Binary negation of long or integer values.
  */
-public final class NotNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
+public final class NotNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     @Input private ValueNode x;
 
@@ -48,7 +48,7 @@
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 1;
-        return Constant.forIntegerKind(kind(), ~inputs[0].asLong(), null);
+        return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), ~inputs[0].asLong());
     }
 
     /**
@@ -58,7 +58,6 @@
      */
     public NotNode(ValueNode x) {
         super(StampTool.not(x.stamp()));
-        assert x.kind() == Kind.Int || x.kind() == Kind.Long;
         this.x = x;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -32,8 +32,8 @@
 @NodeInfo(shortName = "|")
 public final class OrNode extends BitLogicNode implements Canonicalizable {
 
-    public OrNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    public OrNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
@@ -44,7 +44,7 @@
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        return Constant.forIntegerKind(kind(), inputs[0].asLong() | inputs[1].asLong(), null);
+        return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() | inputs[1].asLong());
     }
 
     @Override
@@ -53,28 +53,18 @@
             return x();
         }
         if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new OrNode(kind(), y(), x()));
+            return graph().unique(new OrNode(stamp(), y(), x()));
         }
         if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+            return ConstantNode.forPrimitive(stamp(), evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
-            if (kind() == Kind.Int) {
-                int c = y().asConstant().asInt();
-                if (c == -1) {
-                    return ConstantNode.forInt(-1, graph());
-                }
-                if (c == 0) {
-                    return x();
-                }
-            } else {
-                assert kind() == Kind.Long;
-                long c = y().asConstant().asLong();
-                if (c == -1) {
-                    return ConstantNode.forLong(-1, graph());
-                }
-                if (c == 0) {
-                    return x();
-                }
+            long rawY = y().asConstant().asLong();
+            long mask = IntegerStamp.defaultMask(PrimitiveStamp.getBits(stamp()));
+            if ((rawY & mask) == mask) {
+                return ConstantNode.forIntegerStamp(stamp(), mask, graph());
+            }
+            if ((rawY & mask) == 0) {
+                return x();
             }
             return BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -32,8 +32,8 @@
 @NodeInfo(shortName = ">>")
 public final class RightShiftNode extends ShiftNode implements Canonicalizable {
 
-    public RightShiftNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    public RightShiftNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
@@ -50,7 +50,7 @@
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().stamp() instanceof IntegerStamp && ((IntegerStamp) x().stamp()).isPositive()) {
-            return graph().unique(new UnsignedRightShiftNode(kind(), x(), y()));
+            return graph().unique(new UnsignedRightShiftNode(stamp(), x(), y()));
         }
         if (x().isConstant() && y().isConstant()) {
             return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
@@ -90,14 +90,14 @@
                              * full shift for this kind
                              */
                             assert total >= mask;
-                            return graph().unique(new RightShiftNode(kind(), other.x(), ConstantNode.forInt(mask, graph())));
+                            return graph().unique(new RightShiftNode(stamp(), other.x(), ConstantNode.forInt(mask, graph())));
                         }
-                        return graph().unique(new RightShiftNode(kind(), other.x(), ConstantNode.forInt(total, graph())));
+                        return graph().unique(new RightShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph())));
                     }
                 }
             }
             if (originalAmout != amount) {
-                return graph().unique(new RightShiftNode(kind(), x(), ConstantNode.forInt(amount, graph())));
+                return graph().unique(new RightShiftNode(stamp(), x(), ConstantNode.forInt(amount, graph())));
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code ShiftOp} class represents shift operations.
@@ -37,7 +37,7 @@
      * @param x the first input value
      * @param s the second input value
      */
-    public ShiftNode(Kind kind, ValueNode x, ValueNode s) {
-        super(kind, x, s);
+    public ShiftNode(Stamp stamp, ValueNode x, ValueNode s) {
+        super(stamp, x, s);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -32,7 +32,7 @@
 /**
  * The {@code SignExtendNode} converts an integer to a wider integer using sign extension.
  */
-public class SignExtendNode extends IntegerConvertNode {
+public class SignExtendNode extends IntegerConvertNode implements Canonicalizable {
 
     public SignExtendNode(ValueNode input, int resultBits) {
         super(StampTool.signExtend(input.stamp(), resultBits), input, resultBits);
@@ -67,12 +67,21 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
+        ValueNode ret = canonicalConvert();
+        if (ret != null) {
+            return ret;
+        }
+
         if (getInput() instanceof SignExtendNode) {
+            // sxxx -(sign-extend)-> ssss sxxx -(sign-extend)-> ssssssss sssssxxx
+            // ==> sxxx -(sign-extend)-> ssssssss sssssxxx
             SignExtendNode other = (SignExtendNode) getInput();
             return graph().unique(new SignExtendNode(other.getInput(), getResultBits()));
         } else if (getInput() instanceof ZeroExtendNode) {
             ZeroExtendNode other = (ZeroExtendNode) getInput();
             if (other.getResultBits() > other.getInputBits()) {
+                // sxxx -(zero-extend)-> 0000 sxxx -(sign-extend)-> 00000000 0000sxxx
+                // ==> sxxx -(zero-extend)-> 00000000 0000sxxx
                 return graph().unique(new ZeroExtendNode(other.getInput(), getResultBits()));
             }
         }
@@ -80,11 +89,13 @@
         if (getInput().stamp() instanceof IntegerStamp) {
             IntegerStamp inputStamp = (IntegerStamp) getInput().stamp();
             if ((inputStamp.upMask() & (1L << (getInputBits() - 1))) == 0L) {
+                // 0xxx -(sign-extend)-> 0000 0xxx
+                // ==> 0xxx -(zero-extend)-> 0000 0xxx
                 return graph().unique(new ZeroExtendNode(getInput(), getResultBits()));
             }
         }
 
-        return super.canonical(tool);
+        return this;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -33,8 +33,16 @@
 @NodeInfo(shortName = "|/|")
 public class UnsignedDivNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
 
-    public UnsignedDivNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    /**
+     * Used by {@code NodeIntrinsic} in {@code UnsignedMathSubstitutions}.
+     */
+    @SuppressWarnings("unused")
+    private UnsignedDivNode(Kind kind, ValueNode x, ValueNode y) {
+        this(StampFactory.forKind(kind), x, y);
+    }
+
+    public UnsignedDivNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
@@ -44,19 +52,14 @@
             if (yConst == 0) {
                 return this; // this will trap, cannot canonicalize
             }
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(UnsignedMath.divide(x().asConstant().asInt(), (int) yConst), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(UnsignedMath.divide(x().asConstant().asLong(), yConst), graph());
-            }
+            return ConstantNode.forIntegerStamp(stamp(), UnsignedMath.divide(x().asConstant().asLong(), yConst), graph());
         } else if (y().isConstant()) {
             long c = y().asConstant().asLong();
             if (c == 1) {
                 return x();
             }
             if (CodeUtil.isPowerOf2(c)) {
-                return graph().unique(new UnsignedRightShiftNode(kind(), x(), ConstantNode.forInt(CodeUtil.log2(c), graph())));
+                return graph().unique(new UnsignedRightShiftNode(stamp(), x(), ConstantNode.forInt(CodeUtil.log2(c), graph())));
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -33,8 +33,16 @@
 @NodeInfo(shortName = "|%|")
 public class UnsignedRemNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
 
-    public UnsignedRemNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    /**
+     * Used by {@code NodeIntrinsic} in {@code UnsignedMathSubstitutions}.
+     */
+    @SuppressWarnings("unused")
+    private UnsignedRemNode(Kind kind, ValueNode x, ValueNode y) {
+        this(StampFactory.forKind(kind), x, y);
+    }
+
+    public UnsignedRemNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
@@ -44,18 +52,13 @@
             if (yConst == 0) {
                 return this; // this will trap, cannot canonicalize
             }
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(UnsignedMath.remainder(x().asConstant().asInt(), (int) yConst), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(UnsignedMath.remainder(x().asConstant().asLong(), yConst), graph());
-            }
+            return ConstantNode.forIntegerStamp(stamp(), UnsignedMath.remainder(x().asConstant().asLong(), yConst), graph());
         } else if (y().isConstant()) {
             long c = y().asConstant().asLong();
             if (c == 1) {
-                return ConstantNode.forIntegerKind(kind(), 0, graph());
+                return ConstantNode.forIntegerStamp(stamp(), 0, graph());
             } else if (CodeUtil.isPowerOf2(c)) {
-                return graph().unique(new AndNode(kind(), x(), ConstantNode.forIntegerKind(kind(), c - 1, graph())));
+                return graph().unique(new AndNode(stamp(), x(), ConstantNode.forIntegerStamp(stamp(), c - 1, graph())));
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -32,8 +32,8 @@
 @NodeInfo(shortName = ">>>")
 public final class UnsignedRightShiftNode extends ShiftNode implements Canonicalizable {
 
-    public UnsignedRightShiftNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    public UnsignedRightShiftNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
@@ -79,19 +79,19 @@
                         if (total != (total & mask)) {
                             return ConstantNode.forIntegerKind(kind(), 0, graph());
                         }
-                        return graph().unique(new UnsignedRightShiftNode(kind(), other.x(), ConstantNode.forInt(total, graph())));
+                        return graph().unique(new UnsignedRightShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph())));
                     } else if (other instanceof LeftShiftNode && otherAmount == amount) {
                         if (kind() == Kind.Long) {
-                            return graph().unique(new AndNode(kind(), other.x(), ConstantNode.forLong(-1L >>> amount, graph())));
+                            return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forLong(-1L >>> amount, graph())));
                         } else {
                             assert kind() == Kind.Int;
-                            return graph().unique(new AndNode(kind(), other.x(), ConstantNode.forInt(-1 >>> amount, graph())));
+                            return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forInt(-1 >>> amount, graph())));
                         }
                     }
                 }
             }
             if (originalAmout != amount) {
-                return graph().unique(new UnsignedRightShiftNode(kind(), x(), ConstantNode.forInt(amount, graph())));
+                return graph().unique(new UnsignedRightShiftNode(stamp(), x(), ConstantNode.forInt(amount, graph())));
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -32,8 +32,8 @@
 @NodeInfo(shortName = "^")
 public final class XorNode extends BitLogicNode implements Canonicalizable {
 
-    public XorNode(Kind kind, ValueNode x, ValueNode y) {
-        super(kind, x, y);
+    public XorNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
     }
 
     @Override
@@ -44,35 +44,26 @@
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        return Constant.forIntegerKind(kind(), inputs[0].asLong() ^ inputs[1].asLong(), null);
+        return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() ^ inputs[1].asLong());
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x() == y()) {
-            return ConstantNode.forIntegerKind(kind(), 0, graph());
+            return ConstantNode.forIntegerStamp(stamp(), 0, graph());
         }
         if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new XorNode(kind(), y(), x()));
+            return graph().unique(new XorNode(stamp(), y(), x()));
         }
         if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+            return ConstantNode.forPrimitive(stamp(), evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
-            if (kind() == Kind.Int) {
-                int c = y().asConstant().asInt();
-                if (c == 0) {
-                    return x();
-                } else if (c == -1) {
-                    return graph().unique(new NotNode(x()));
-                }
-            } else {
-                assert kind() == Kind.Long;
-                long c = y().asConstant().asLong();
-                if (c == 0) {
-                    return x();
-                } else if (c == -1) {
-                    return graph().unique(new NotNode(x()));
-                }
+            long rawY = y().asConstant().asLong();
+            long mask = IntegerStamp.defaultMask(PrimitiveStamp.getBits(stamp()));
+            if ((rawY & mask) == 0) {
+                return x();
+            } else if ((rawY & mask) == mask) {
+                return graph().unique(new NotNode(x()));
             }
             return BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -32,7 +32,7 @@
 /**
  * The {@code ZeroExtendNode} converts an integer to a wider integer using zero extension.
  */
-public class ZeroExtendNode extends IntegerConvertNode {
+public class ZeroExtendNode extends IntegerConvertNode implements Canonicalizable {
 
     public ZeroExtendNode(ValueNode input, int resultBits) {
         super(StampTool.zeroExtend(input.stamp(), resultBits), input, resultBits);
@@ -63,12 +63,19 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
+        ValueNode ret = canonicalConvert();
+        if (ret != null) {
+            return ret;
+        }
+
         if (getInput() instanceof ZeroExtendNode) {
+            // xxxx -(zero-extend)-> 0000 xxxx -(zero-extend)-> 00000000 0000xxxx
+            // ==> xxxx -(zero-extend)-> 00000000 0000xxxx
             ZeroExtendNode other = (ZeroExtendNode) getInput();
             return graph().unique(new ZeroExtendNode(other.getInput(), getResultBits()));
         }
 
-        return super.canonical(tool);
+        return this;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -76,7 +76,7 @@
         if (ObjectStamp.isObjectAlwaysNull(object())) {
             return object();
         }
-        if (hub.isConstant() && hub.kind() == Kind.Object && hub.asConstant().asObject() instanceof Class) {
+        if (hub.isConstant() && hub.asConstant().getKind() == Kind.Object && hub.asConstant().asObject() instanceof Class) {
             Class clazz = (Class) hub.asConstant().asObject();
             ResolvedJavaType t = tool.getMetaAccess().lookupJavaType(clazz);
             return graph().add(new CheckCastNode(t, object(), null, forStoreCheck));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -64,7 +64,7 @@
 
     public CompareAndSwapNode(ValueNode object, int displacement, ValueNode offset, ValueNode expected, ValueNode newValue) {
         super(StampFactory.forKind(Kind.Boolean.getStackKind()));
-        assert expected.kind() == newValue.kind();
+        assert expected.stamp().isCompatible(newValue.stamp());
         this.object = object;
         this.offset = offset;
         this.expected = expected;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java	Fri Feb 28 16:19:10 2014 +0100
@@ -29,7 +29,7 @@
 public final class GenericStamp extends Stamp {
 
     public enum GenericStampType {
-        Dependency, Extension, Condition, Void
+        Dependency, Extension, Condition
     }
 
     private final GenericStampType type;
@@ -49,11 +49,7 @@
 
     @Override
     public Kind getStackKind() {
-        if (type == GenericStampType.Void) {
-            return Kind.Void;
-        } else {
-            return Kind.Illegal;
-        }
+        return Kind.Illegal;
     }
 
     @Override
@@ -63,8 +59,7 @@
 
     @Override
     public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
-        assert type == GenericStampType.Void;
-        return metaAccess.lookupJavaType(Void.TYPE);
+        throw GraalInternalError.shouldNotReachHere(type + " stamp has not Java type");
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Fri Feb 28 16:19:10 2014 +0100
@@ -38,7 +38,6 @@
     private static final Stamp dependencyStamp = new GenericStamp(GenericStampType.Dependency);
     private static final Stamp extensionStamp = new GenericStamp(GenericStampType.Extension);
     private static final Stamp conditionStamp = new GenericStamp(GenericStampType.Condition);
-    private static final Stamp voidStamp = new GenericStamp(GenericStampType.Void);
     private static final Stamp nodeIntrinsicStamp = new ObjectStamp(null, false, false, false);
     private static final Stamp positiveInt = forInteger(Kind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
 
@@ -73,7 +72,7 @@
         setFloatCache(Kind.Double);
 
         setCache(Kind.Object, objectStamp);
-        setCache(Kind.Void, voidStamp);
+        setCache(Kind.Void, VoidStamp.getInstance());
         for (Kind k : Kind.values()) {
             illegalStampCache[k.ordinal()] = new IllegalStamp(k);
         }
@@ -87,8 +86,12 @@
         return stampCache[kind.ordinal()];
     }
 
+    /**
+     * Return the stamp for the {@code void} type. This will return a singleton instance than can be
+     * compared using {@code ==}.
+     */
     public static Stamp forVoid() {
-        return voidStamp;
+        return VoidStamp.getInstance();
     }
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Fri Feb 28 16:19:10 2014 +0100
@@ -369,16 +369,6 @@
         }
     }
 
-    public static Stamp intToLong(IntegerStamp intStamp) {
-        long downMask = intStamp.downMask();
-        long upMask = intStamp.upMask();
-        if (!intStamp.isUnsigned()) {
-            downMask = SignExtendNode.signExtend(downMask, intStamp.getBits());
-            upMask = SignExtendNode.signExtend(upMask, intStamp.getBits());
-        }
-        return new IntegerStamp(64, intStamp.isUnsigned(), intStamp.lowerBound(), intStamp.upperBound(), downMask, upMask);
-    }
-
     public static Stamp narrowingConversion(Stamp input, int resultBits) {
         if (input instanceof IntegerStamp) {
             IntegerStamp inputStamp = (IntegerStamp) input;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/VoidStamp.java	Fri Feb 28 16:19:10 2014 +0100
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 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.type;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Singleton stamp representing the value of type {@code void}.
+ */
+public final class VoidStamp extends Stamp {
+
+    private VoidStamp() {
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return this;
+    }
+
+    @Override
+    public Kind getStackKind() {
+        return Kind.Void;
+    }
+
+    @Override
+    public PlatformKind getPlatformKind(LIRTypeTool tool) {
+        throw GraalInternalError.shouldNotReachHere("void stamp has no value");
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        return metaAccess.lookupJavaType(Void.TYPE);
+    }
+
+    @Override
+    public String toString() {
+        return "void";
+    }
+
+    @Override
+    public boolean alwaysDistinct(Stamp other) {
+        return this != other;
+    }
+
+    @Override
+    public Stamp meet(Stamp other) {
+        if (other instanceof IllegalStamp) {
+            return other.join(this);
+        }
+        if (this == other) {
+            return this;
+        }
+        return StampFactory.illegal(Kind.Illegal);
+    }
+
+    @Override
+    public Stamp join(Stamp other) {
+        if (other instanceof IllegalStamp) {
+            return other.join(this);
+        }
+        if (this == other) {
+            return this;
+        }
+        return StampFactory.illegal(Kind.Illegal);
+    }
+
+    @Override
+    public boolean isCompatible(Stamp stamp) {
+        return this == stamp;
+    }
+
+    private static VoidStamp instance = new VoidStamp();
+
+    static VoidStamp getInstance() {
+        return instance;
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri Feb 28 16:19:10 2014 +0100
@@ -185,7 +185,7 @@
                             boolean improvedStamp = tryInferStamp(valueNode);
                             Constant constant = valueNode.stamp().asConstant();
                             if (constant != null && !(node instanceof ConstantNode)) {
-                                performReplacement(valueNode, ConstantNode.forConstant(constant, context.getMetaAccess(), valueNode.graph()));
+                                performReplacement(valueNode, ConstantNode.forConstant(valueNode.stamp(), constant, context.getMetaAccess(), valueNode.graph()));
                             } else if (improvedStamp) {
                                 // the improved stamp may enable additional canonicalization
                                 tryCanonicalize(valueNode, nodeClass);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsignedMathTest.java	Fri Feb 28 16:19:10 2014 +0100
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 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.replacements.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.test.*;
+
+/**
+ * Tests the substitutions for the {@link UnsignedMath} class.
+ */
+public class UnsignedMathTest extends GraalCompilerTest {
+
+    public static boolean aboveThanInt(int a, int b) {
+        return UnsignedMath.aboveThan(a, b);
+    }
+
+    public static boolean aboveOrEqualInt(int a, int b) {
+        return UnsignedMath.aboveOrEqual(a, b);
+    }
+
+    public static boolean belowThanInt(int a, int b) {
+        return UnsignedMath.belowThan(a, b);
+    }
+
+    public static boolean belowOrEqualInt(int a, int b) {
+        return UnsignedMath.belowOrEqual(a, b);
+    }
+
+    public static int divideInt(int a, int b) {
+        return UnsignedMath.divide(a, b);
+    }
+
+    public static int remainderInt(int a, int b) {
+        return UnsignedMath.remainder(a, b);
+    }
+
+    public static boolean aboveThanLong(long a, long b) {
+        return UnsignedMath.aboveThan(a, b);
+    }
+
+    public static boolean aboveOrEqualLong(long a, long b) {
+        return UnsignedMath.aboveOrEqual(a, b);
+    }
+
+    public static boolean belowThanLong(long a, long b) {
+        return UnsignedMath.belowThan(a, b);
+    }
+
+    public static boolean belowOrEqualLong(long a, long b) {
+        return UnsignedMath.belowOrEqual(a, b);
+    }
+
+    public static long divideLong(long a, long b) {
+        return UnsignedMath.divide(a, b);
+    }
+
+    public static long remainderLong(long a, long b) {
+        return UnsignedMath.remainder(a, b);
+    }
+
+    private void testInt(int a, int b) {
+        test("aboveThanInt", a, b);
+        test("aboveOrEqualInt", a, b);
+        test("belowThanInt", a, b);
+        test("belowOrEqualInt", a, b);
+        test("divideInt", a, b);
+        test("remainderInt", a, b);
+    }
+
+    private void testLong(long a, long b) {
+        test("aboveThanLong", a, b);
+        test("aboveOrEqualLong", a, b);
+        test("belowThanLong", a, b);
+        test("belowOrEqualLong", a, b);
+        test("divideLong", a, b);
+        test("remainderLong", a, b);
+    }
+
+    @Test
+    public void testInt() {
+        testInt(5, 7);
+        testInt(-3, -7);
+        testInt(-3, 7);
+        testInt(42, -5);
+    }
+
+    @Test
+    public void testLong() {
+        testLong(5, 7);
+        testLong(-3, -7);
+        testLong(-3, 7);
+        testLong(42, -5);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Fri Feb 28 16:19:10 2014 +0100
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 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.replacements;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.util.*;
+import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
+import com.oracle.graal.word.phases.*;
+
+/**
+ * A utility for manually creating a graph. This will be expanded as necessary to support all
+ * subsystems that employ manual graph creation (as opposed to {@linkplain GraphBuilderPhase
+ * bytecode parsing} based graph creation).
+ */
+public class GraphKit {
+
+    protected final Providers providers;
+    protected final StructuredGraph graph;
+    protected FixedWithNextNode lastFixedNode;
+
+    private final List<Structure> structures;
+
+    abstract static class Structure {
+    }
+
+    public GraphKit(StructuredGraph graph, Providers providers) {
+        this.providers = providers;
+        this.graph = graph;
+        this.lastFixedNode = graph.start();
+
+        structures = new ArrayList<>();
+        /* Add a dummy element, so that the access of the last element never leads to an exception. */
+        structures.add(new Structure() {
+        });
+    }
+
+    public StructuredGraph getGraph() {
+        return graph;
+    }
+
+    /**
+     * Ensures a floating node is added to or already present in the graph via {@link Graph#unique}.
+     * 
+     * @return a node similar to {@code node} if one exists, otherwise {@code node}
+     */
+    public <T extends FloatingNode> T unique(T node) {
+        return graph.unique(node);
+    }
+
+    /**
+     * Appends a fixed node to the graph.
+     */
+    public <T extends FixedNode> T append(T node) {
+        T result = graph.add(node);
+        assert lastFixedNode != null;
+        assert result.predecessor() == null;
+        graph.addAfterFixed(lastFixedNode, result);
+        if (result instanceof FixedWithNextNode) {
+            lastFixedNode = (FixedWithNextNode) result;
+        } else {
+            lastFixedNode = null;
+        }
+        return result;
+    }
+
+    public InvokeNode createInvoke(Class<?> declaringClass, String name, ValueNode... args) {
+        return createInvoke(declaringClass, name, InvokeKind.Static, null, FrameState.UNKNOWN_BCI, args);
+    }
+
+    /**
+     * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
+     * arguments. The method is looked up via reflection based on the declaring class and name.
+     * 
+     * @param declaringClass the class declaring the invoked method
+     * @param name the name of the invoked method
+     * @param args the arguments to the invocation
+     */
+    public InvokeNode createInvoke(Class<?> declaringClass, String name, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+        boolean isStatic = invokeKind == InvokeKind.Static;
+        ResolvedJavaMethod method = null;
+        for (Method m : declaringClass.getDeclaredMethods()) {
+            if (Modifier.isStatic(m.getModifiers()) == isStatic && m.getName().equals(name)) {
+                assert method == null : "found more than one method in " + declaringClass + " named " + name;
+                method = providers.getMetaAccess().lookupJavaMethod(m);
+            }
+        }
+        assert method != null : "did not find method in " + declaringClass + " named " + name;
+        return createInvoke(method, invokeKind, frameStateBuilder, bci, args);
+    }
+
+    /**
+     * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
+     * arguments.
+     */
+    public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+        assert Modifier.isStatic(method.getModifiers()) == (invokeKind == InvokeKind.Static);
+        Signature signature = method.getSignature();
+        JavaType returnType = signature.getReturnType(null);
+        assert checkArgs(method, args);
+        MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnType, bci));
+        InvokeNode invoke = append(new InvokeNode(callTarget, bci));
+
+        if (frameStateBuilder != null) {
+            if (invoke.kind() != Kind.Void) {
+                frameStateBuilder.push(invoke.kind(), invoke);
+            }
+            invoke.setStateAfter(frameStateBuilder.create(0));
+            if (invoke.kind() != Kind.Void) {
+                frameStateBuilder.pop(invoke.kind());
+            }
+        }
+        return invoke;
+    }
+
+    protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, JavaType returnType, @SuppressWarnings("unused") int bci) {
+        return new MethodCallTargetNode(invokeKind, targetMethod, args, returnType);
+    }
+
+    /**
+     * Determines if a given set of arguments is compatible with the signature of a given method.
+     * 
+     * @return true if {@code args} are compatible with the signature if {@code method}
+     * @throws AssertionError if {@code args} are not compatible with the signature if
+     *             {@code method}
+     */
+    public boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) {
+        Signature signature = method.getSignature();
+        boolean isStatic = Modifier.isStatic(method.getModifiers());
+        if (signature.getParameterCount(!isStatic) != args.length) {
+            throw new AssertionError(graph + ": wrong number of arguments to " + method);
+        }
+        int paramNum = 0;
+        for (int i = 0; i != args.length; i++) {
+            Kind expected;
+            if (i == 0 && !isStatic) {
+                expected = Kind.Object;
+            } else {
+                expected = signature.getParameterKind(paramNum++).getStackKind();
+            }
+            Kind actual = args[i].stamp().getStackKind();
+            if (expected != actual) {
+                throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of call to " + method + " [" + actual + " != " + expected + "]");
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Rewrite all word types in the graph.
+     */
+    public void rewriteWordTypes() {
+        new WordTypeRewriterPhase(providers.getMetaAccess(), providers.getCodeCache().getTarget().wordKind).apply(graph);
+    }
+
+    /**
+     * {@linkplain #inline(InvokeNode) Inlines} all invocations currently in the graph.
+     */
+    public void inlineInvokes() {
+        for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) {
+            inline(invoke);
+        }
+
+        // Clean up all code that is now dead after inlining.
+        new DeadCodeEliminationPhase().apply(graph);
+        assert graph.getNodes().filter(InvokeNode.class).isEmpty();
+    }
+
+    /**
+     * Inlines a given invocation to a method. The graph of the inlined method is
+     * {@linkplain ReplacementsImpl#makeGraph processed} in the same manner as for snippets and
+     * method substitutions.
+     */
+    public void inline(InvokeNode invoke) {
+        ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
+        ReplacementsImpl repl = new ReplacementsImpl(providers, new Assumptions(false), providers.getCodeCache().getTarget());
+        StructuredGraph calleeGraph = repl.makeGraph(method, null, method, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        InliningUtil.inline(invoke, calleeGraph, false);
+    }
+
+    protected void pushStructure(Structure structure) {
+        structures.add(structure);
+    }
+
+    protected <T extends Structure> T getTopStructure(Class<T> expectedClass) {
+        return expectedClass.cast(structures.get(structures.size() - 1));
+    }
+
+    protected void popStructure() {
+        structures.remove(structures.size() - 1);
+    }
+
+    protected enum IfState {
+        CONDITION, THEN_PART, ELSE_PART, FINISHED
+    }
+
+    static class IfStructure extends Structure {
+        protected IfState state;
+        protected FixedNode thenPart;
+        protected FixedNode elsePart;
+    }
+
+    /**
+     * Starts an if-block. This call can be followed by a call to {@link #thenPart} to start
+     * emitting the code executed when the condition hold; and a call to {@link #elsePart} to start
+     * emititng the code when the condition does not hold. It must be followed by a call to
+     * {@link #endIf} to close the if-block.
+     * 
+     * @param condition The condition for the if-block
+     * @param trueProbability The estimated probability the the condition is true
+     */
+    public void startIf(LogicNode condition, double trueProbability) {
+        BeginNode thenSuccessor = graph.add(new BeginNode());
+        BeginNode elseSuccessor = graph.add(new BeginNode());
+        append(new IfNode(condition, thenSuccessor, elseSuccessor, trueProbability));
+        lastFixedNode = null;
+
+        IfStructure s = new IfStructure();
+        s.state = IfState.CONDITION;
+        s.thenPart = thenSuccessor;
+        s.elsePart = elseSuccessor;
+        pushStructure(s);
+    }
+
+    private IfStructure saveLastNode() {
+        IfStructure s = getTopStructure(IfStructure.class);
+        switch (s.state) {
+            case CONDITION:
+                assert lastFixedNode == null;
+                break;
+            case THEN_PART:
+                s.thenPart = lastFixedNode;
+                break;
+            case ELSE_PART:
+                s.elsePart = lastFixedNode;
+                break;
+            case FINISHED:
+                assert false;
+                break;
+        }
+        lastFixedNode = null;
+        return s;
+    }
+
+    public void thenPart() {
+        IfStructure s = saveLastNode();
+        lastFixedNode = (FixedWithNextNode) s.thenPart;
+        s.state = IfState.THEN_PART;
+    }
+
+    public void elsePart() {
+        IfStructure s = saveLastNode();
+        lastFixedNode = (FixedWithNextNode) s.elsePart;
+        s.state = IfState.ELSE_PART;
+    }
+
+    public void endIf() {
+        IfStructure s = saveLastNode();
+
+        FixedWithNextNode thenPart = s.thenPart instanceof FixedWithNextNode ? (FixedWithNextNode) s.thenPart : null;
+        FixedWithNextNode elsePart = s.elsePart instanceof FixedWithNextNode ? (FixedWithNextNode) s.elsePart : null;
+
+        if (thenPart != null && elsePart != null) {
+            /* Both parts are alive, we need a real merge. */
+            EndNode thenEnd = graph.add(new EndNode());
+            graph.addAfterFixed(thenPart, thenEnd);
+            EndNode elseEnd = graph.add(new EndNode());
+            graph.addAfterFixed(elsePart, elseEnd);
+
+            MergeNode merge = graph.add(new MergeNode());
+            merge.addForwardEnd(thenEnd);
+            merge.addForwardEnd(elseEnd);
+
+            lastFixedNode = merge;
+
+        } else if (thenPart != null) {
+            /* elsePart ended with a control sink, so we can continue with thenPart. */
+            lastFixedNode = thenPart;
+
+        } else if (elsePart != null) {
+            /* thenPart ended with a control sink, so we can continue with elsePart. */
+            lastFixedNode = elsePart;
+
+        } else {
+            /* Both parts ended with a control sink, so no nodes can be added after the if. */
+            assert lastFixedNode == null;
+        }
+        s.state = IfState.FINISHED;
+        popStructure();
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -37,18 +37,18 @@
     @Input private ValueNode value;
 
     public BitCountNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount()));
+        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()));
         this.value = value;
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (value.isConstant()) {
-            long v = value.asConstant().asLong();
-            if (value.kind().getStackKind() == Kind.Int) {
-                return ConstantNode.forInt(Integer.bitCount((int) v), graph());
-            } else if (value.kind() == Kind.Long) {
-                return ConstantNode.forInt(Long.bitCount(v), graph());
+            Constant c = value.asConstant();
+            if (c.getKind() == Kind.Int) {
+                return ConstantNode.forInt(Integer.bitCount(c.asInt()), graph());
+            } else if (c.getKind() == Kind.Long) {
+                return ConstantNode.forInt(Long.bitCount(c.asLong()), graph());
             }
         }
         return this;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -37,18 +37,18 @@
     @Input private ValueNode value;
 
     public BitScanForwardNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount()));
+        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()));
         this.value = value;
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (value.isConstant()) {
-            long v = value.asConstant().asLong();
-            if (value.kind().getStackKind() == Kind.Int) {
-                return ConstantNode.forInt(Integer.numberOfTrailingZeros((int) v), graph());
-            } else if (value.kind() == Kind.Long) {
-                return ConstantNode.forInt(Long.numberOfTrailingZeros(v), graph());
+            Constant c = value.asConstant();
+            if (c.getKind() == Kind.Int) {
+                return ConstantNode.forInt(Integer.numberOfTrailingZeros(c.asInt()), graph());
+            } else if (c.getKind() == Kind.Long) {
+                return ConstantNode.forInt(Long.numberOfTrailingZeros(c.asLong()), graph());
             }
         }
         return this;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -37,18 +37,18 @@
     @Input private ValueNode value;
 
     public BitScanReverseNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount()));
+        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()));
         this.value = value;
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (value.isConstant()) {
-            long v = value.asConstant().asLong();
-            if (value.kind().getStackKind() == Kind.Int) {
-                return ConstantNode.forInt(31 - Integer.numberOfLeadingZeros((int) v), graph());
-            } else if (value.kind() == Kind.Long) {
-                return ConstantNode.forInt(63 - Long.numberOfLeadingZeros(v), graph());
+            Constant c = value.asConstant();
+            if (c.getKind() == Kind.Int) {
+                return ConstantNode.forInt(31 - Integer.numberOfLeadingZeros(c.asInt()), graph());
+            } else if (c.getKind() == Kind.Long) {
+                return ConstantNode.forInt(63 - Long.numberOfLeadingZeros(c.asLong()), graph());
             }
         }
         return this;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -48,8 +48,8 @@
     }
 
     public MathIntrinsicNode(ValueNode x, Operation op) {
-        super(StampFactory.forKind(x.kind()));
-        assert x.kind() == Kind.Double;
+        super(StampFactory.forKind(Kind.Double));
+        assert x.stamp() instanceof FloatStamp && PrimitiveStamp.getBits(x.stamp()) == 64;
         this.x = x;
         this.operation = op;
     }
--- a/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64OptimizedCallTargetInstrumentationFactory.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64OptimizedCallTargetInstrumentationFactory.java	Fri Feb 28 16:19:10 2014 +0100
@@ -41,7 +41,7 @@
 @ServiceProvider(OptimizedCallTargetInstrumentationFactory.class)
 public class AMD64OptimizedCallTargetInstrumentationFactory implements OptimizedCallTargetInstrumentationFactory {
 
-    public CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext,
+    public CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext,
                     CompilationResult compilationResult) {
         return new OptimizedCallTargetInstrumentation(codeCache, foreignCalls, frameMap, asm, frameContext, compilationResult) {
             @Override
@@ -51,14 +51,14 @@
                 Register thisRegister = codeCache.getRegisterConfig().getCallingConventionRegisters(Type.JavaCall, Kind.Object)[0];
                 Register spillRegister = AMD64.r10; // TODO(mg): fix me
                 AMD64Address nMethodAddress = new AMD64Address(thisRegister, getFieldOffset("installedCode", OptimizedCallTarget.class));
-                int verifiedEntryPoint = asm.codeBuffer.position();
+                int verifiedEntryPoint = asm.position();
                 if (config.useCompressedOops) {
                     asm.movl(spillRegister, nMethodAddress);
-                    asm.nop(AMD64HotSpotBackend.PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE - (asm.codeBuffer.position() - verifiedEntryPoint));
+                    asm.nop(AMD64HotSpotBackend.PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE - (asm.position() - verifiedEntryPoint));
                     AMD64HotSpotMove.decodePointer(asm, spillRegister, registers.getHeapBaseRegister(), config.getOopEncoding());
                 } else {
                     asm.movq(spillRegister, nMethodAddress);
-                    asm.nop(AMD64HotSpotBackend.PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE - (asm.codeBuffer.position() - verifiedEntryPoint));
+                    asm.nop(AMD64HotSpotBackend.PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE - (asm.position() - verifiedEntryPoint));
                 }
                 Label doProlog = new Label();
 
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java	Fri Feb 28 16:19:10 2014 +0100
@@ -43,7 +43,7 @@
  */
 public abstract class OptimizedCallTargetInstrumentation extends CompilationResultBuilder {
 
-    public OptimizedCallTargetInstrumentation(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext,
+    public OptimizedCallTargetInstrumentation(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext,
                     CompilationResult compilationResult) {
         super(codeCache, foreignCalls, frameMap, asm, frameContext, compilationResult);
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -38,8 +38,8 @@
 public class IntegerAddExactNode extends IntegerAddNode implements Canonicalizable, IntegerExactArithmeticNode {
 
     public IntegerAddExactNode(ValueNode x, ValueNode y) {
-        super(x.kind(), x, y);
-        assert x.kind() == y.kind() && (x.kind() == Kind.Int || x.kind() == Kind.Long);
+        super(x.stamp().unrestricted(), x, y);
+        assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
     }
 
     @Override
@@ -54,12 +54,15 @@
             return graph().unique(new IntegerAddExactNode(y(), x()));
         }
         if (x().isConstant()) {
+            Constant xConst = x().asConstant();
+            Constant yConst = y().asConstant();
+            assert xConst.getKind() == yConst.getKind();
             try {
-                if (kind() == Kind.Int) {
-                    return ConstantNode.forInt(ExactMath.addExact(x().asConstant().asInt(), y().asConstant().asInt()), graph());
+                if (xConst.getKind() == Kind.Int) {
+                    return ConstantNode.forInt(ExactMath.addExact(xConst.asInt(), yConst.asInt()), graph());
                 } else {
-                    assert kind() == Kind.Long;
-                    return ConstantNode.forLong(ExactMath.addExact(x().asConstant().asLong(), y().asConstant().asLong()), graph());
+                    assert xConst.getKind() == Kind.Long;
+                    return ConstantNode.forLong(ExactMath.addExact(xConst.asLong(), yConst.asLong()), graph());
                 }
             } catch (ArithmeticException ex) {
                 // The operation will result in an overflow exception, so do not canonicalize.
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -28,6 +28,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.truffle.api.*;
 
 /**
@@ -37,8 +38,8 @@
 public class IntegerMulExactNode extends IntegerMulNode implements Canonicalizable, IntegerExactArithmeticNode {
 
     public IntegerMulExactNode(ValueNode x, ValueNode y) {
-        super(x.kind(), x, y);
-        assert x.kind() == y.kind() && (x.kind() == Kind.Int || x.kind() == Kind.Long);
+        super(x.stamp().unrestricted(), x, y);
+        assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
     }
 
     @Override
@@ -47,12 +48,15 @@
             return graph().unique(new IntegerMulExactNode(y(), x()));
         }
         if (x().isConstant()) {
+            Constant xConst = x().asConstant();
+            Constant yConst = y().asConstant();
+            assert xConst.getKind() == yConst.getKind();
             try {
-                if (kind() == Kind.Int) {
-                    return ConstantNode.forInt(ExactMath.multiplyExact(x().asConstant().asInt(), y().asConstant().asInt()), graph());
+                if (xConst.getKind() == Kind.Int) {
+                    return ConstantNode.forInt(ExactMath.multiplyExact(xConst.asInt(), yConst.asInt()), graph());
                 } else {
-                    assert kind() == Kind.Long;
-                    return ConstantNode.forLong(ExactMath.multiplyExact(x().asConstant().asLong(), y().asConstant().asLong()), graph());
+                    assert xConst.getKind() == Kind.Long;
+                    return ConstantNode.forLong(ExactMath.multiplyExact(xConst.asLong(), yConst.asLong()), graph());
                 }
             } catch (ArithmeticException ex) {
                 // The operation will result in an overflow exception, so do not canonicalize.
@@ -63,7 +67,7 @@
                 return x();
             }
             if (c == 0) {
-                return ConstantNode.defaultForKind(kind(), graph());
+                return ConstantNode.forIntegerStamp(stamp(), 0, graph());
             }
         }
         return this;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Fri Feb 28 16:19:10 2014 +0100
@@ -38,8 +38,8 @@
 public class IntegerSubExactNode extends IntegerSubNode implements Canonicalizable, IntegerExactArithmeticNode {
 
     public IntegerSubExactNode(ValueNode x, ValueNode y) {
-        super(x.kind(), x, y);
-        assert x.kind() == y.kind() && (x.kind() == Kind.Int || x.kind() == Kind.Long);
+        super(StampTool.sub(x.stamp(), y.stamp()), x, y);
+        assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
     }
 
     @Override
@@ -51,15 +51,18 @@
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x() == y()) {
-            return ConstantNode.forIntegerKind(kind(), 0, graph());
+            return ConstantNode.forIntegerStamp(stamp(), 0, graph());
         }
         if (x().isConstant() && y().isConstant()) {
+            Constant xConst = x().asConstant();
+            Constant yConst = y().asConstant();
+            assert xConst.getKind() == yConst.getKind();
             try {
-                if (kind() == Kind.Int) {
-                    return ConstantNode.forInt(ExactMath.subtractExact(x().asConstant().asInt(), y().asConstant().asInt()), graph());
+                if (xConst.getKind() == Kind.Int) {
+                    return ConstantNode.forInt(ExactMath.subtractExact(xConst.asInt(), yConst.asInt()), graph());
                 } else {
-                    assert kind() == Kind.Long;
-                    return ConstantNode.forLong(ExactMath.subtractExact(x().asConstant().asLong(), y().asConstant().asLong()), graph());
+                    assert xConst.getKind() == Kind.Long;
+                    return ConstantNode.forLong(ExactMath.subtractExact(xConst.asLong(), yConst.asLong()), graph());
                 }
             } catch (ArithmeticException ex) {
                 // The operation will result in an overflow exception, so do not canonicalize.
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Wed Feb 26 13:09:16 2014 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Fri Feb 28 16:19:10 2014 +0100
@@ -202,7 +202,7 @@
 
             case NOT:
                 assert arguments.size() == 1;
-                replace(invoke, graph.unique(new XorNode(wordKind, arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph))));
+                replace(invoke, graph.unique(new XorNode(StampFactory.forKind(wordKind), arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph))));
                 break;
 
             case READ: {
@@ -320,8 +320,8 @@
      */
     private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, Kind kind, ValueNode left, ValueNode right) {
         try {
-            Constructor<? extends ValueNode> constructor = nodeClass.getConstructor(Kind.class, ValueNode.class, ValueNode.class);
-            return constructor.newInstance(kind, left, right);
+            Constructor<? extends ValueNode> constructor = nodeClass.getConstructor(Stamp.class, ValueNode.class, ValueNode.class);
+            return constructor.newInstance(StampFactory.forKind(kind), left, right);
         } catch (Throwable ex) {
             throw new GraalInternalError(ex).addContext(nodeClass.getName());
         }
--- a/mx/mx_graal.py	Wed Feb 26 13:09:16 2014 +0100
+++ b/mx/mx_graal.py	Fri Feb 28 16:19:10 2014 +0100
@@ -1325,6 +1325,7 @@
         mx.run_java(
            ['-jar', os.path.join(absoluteMicro, "target", "microbenchmarks.jar"),
             "-f", "1",
+            "-v", "EXTRA" if mx._opts.verbose else "NORMAL",
             "-i", "10", "-wi", "10",
             "--jvm", exe,
             "--jvmArgs", " ".join(["-" + vm] + forkedVmArgs)] + regex,
--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Wed Feb 26 13:09:16 2014 +0100
+++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Fri Feb 28 16:19:10 2014 +0100
@@ -1006,6 +1006,15 @@
   __ delayed()->nop();
 }
 
+void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
+                                    int total_args_passed,
+                                    int comp_args_on_stack,
+                                    const BasicType *sig_bt,
+                                    const VMRegPair *regs) {
+  AdapterGenerator agen(masm);
+  agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs);
+}
+
 // ---------------------------------------------------------------
 AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
                                                             int total_args_passed,
@@ -1016,9 +1025,7 @@
                                                             AdapterFingerPrint* fingerprint) {
   address i2c_entry = __ pc();
 
-  AdapterGenerator agen(masm);
-
-  agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs);
+  gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
 
 
   // -------------------------------------------------------------------------
@@ -1063,7 +1070,7 @@
   }
 
   address c2i_entry = __ pc();
-
+  AdapterGenerator agen(masm);
   agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, L_skip_fixup);
 
   __ flush();
--- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Wed Feb 26 13:09:16 2014 +0100
+++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Fri Feb 28 16:19:10 2014 +0100
@@ -711,7 +711,7 @@
   __ bind(L_fail);
 }
 
-static void gen_i2c_adapter(MacroAssembler *masm,
+void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
                             int total_args_passed,
                             int comp_args_on_stack,
                             const BasicType *sig_bt,
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Wed Feb 26 13:09:16 2014 +0100
+++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Fri Feb 28 16:19:10 2014 +0100
@@ -642,7 +642,7 @@
   __ bind(L_fail);
 }
 
-static void gen_i2c_adapter(MacroAssembler *masm,
+void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
                             int total_args_passed,
                             int comp_args_on_stack,
                             const BasicType *sig_bt,
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Wed Feb 26 13:09:16 2014 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Fri Feb 28 16:19:10 2014 +0100
@@ -808,7 +808,6 @@
 
 void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, oop site) {
   oop id_obj = CompilationResult_Mark::id(site);
-  arrayOop references = (arrayOop) CompilationResult_Mark::references(site);
 
   if (id_obj != NULL) {
     assert(java_lang_boxing_object::is_instance(id_obj, T_INT), "Integer id expected");
--- a/src/share/vm/graal/graalJavaAccess.hpp	Wed Feb 26 13:09:16 2014 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Fri Feb 28 16:19:10 2014 +0100
@@ -169,7 +169,6 @@
   end_class                                                                                                                                                    \
   start_class(CompilationResult_Mark)                                                                                                                          \
     oop_field(CompilationResult_Mark, id, "Ljava/lang/Object;")                                                                                                \
-    oop_field(CompilationResult_Mark, references, "[Lcom/oracle/graal/api/code/CompilationResult$Mark;")                                                       \
   end_class                                                                                                                                                    \
   start_class(DebugInfo)                                                                                                                                       \
     oop_field(DebugInfo, bytecodePosition, "Lcom/oracle/graal/api/code/BytecodePosition;")                                                                     \
--- a/src/share/vm/runtime/sharedRuntime.hpp	Wed Feb 26 13:09:16 2014 +0100
+++ b/src/share/vm/runtime/sharedRuntime.hpp	Fri Feb 28 16:19:10 2014 +0100
@@ -402,6 +402,12 @@
                                                       const VMRegPair *regs,
                                                       AdapterFingerPrint* fingerprint);
 
+  static void gen_i2c_adapter(MacroAssembler *_masm,
+                              int total_args_passed,
+                              int comp_args_on_stack,
+                              const BasicType *sig_bt,
+                              const VMRegPair *regs);
+
   // OSR support
 
   // OSR_migration_begin will extract the jvm state from an interpreter