changeset 16327:5f01f7c48d40

Merge with 5cdcb94a7cf7d9782107cc582f3e4b50000d5d1f
author Stefan Anzinger <stefan.anzinger@gmail.com>
date Mon, 30 Jun 2014 12:02:19 +0200
parents 51f392557124 (current diff) 5cdcb94a7cf7 (diff)
children 34ac3ddfd5ac
files graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/UnsafeAccess.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/PlatformKindTool.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampFactory.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampProvider.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConstant.java graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMField.java graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMFlag.java graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMType.java graal/com.oracle.graal.java/src/com/oracle/graal/java/VerifyOptionsPhase.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMap.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/util/HashSetNodeChangeListener.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/util/HashSetNodeEventListener.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningResult.java graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/TextMapTest.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/NullSourceSection.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceFactory.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceLineLocation.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/TextMap.java mx/mx_graal.py mx/projects src/share/vm/graal/graalCompilerToVM.cpp test/whitelist_baseline.txt
diffstat 655 files changed, 13425 insertions(+), 7468 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Mon Jun 30 08:50:26 2014 +0200
+++ b/.hgignore	Mon Jun 30 12:02:19 2014 +0200
@@ -88,3 +88,6 @@
 agent/make/filelist
 agent/make/sa17.tar.gz
 export.json
+.recommenders
+syntax: regexp
+test\.[0-9]+\.er
--- a/CHANGELOG.md	Mon Jun 30 08:50:26 2014 +0200
+++ b/CHANGELOG.md	Mon Jun 30 12:02:19 2014 +0200
@@ -9,6 +9,7 @@
 
 ### Truffle
 * `truffle.jar`: strip out build-time only dependency into a seperated JAR file (`truffle-dsl-processor.jar`)
+* New flag -G:+TraceTruffleCompilationAST to print the AST before compilation.
 * ...
 
 ## Version 0.3
--- a/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Mon Jun 30 12:02:19 2014 +0200
@@ -38,7 +38,6 @@
 public class AMD64 extends Architecture {
 
     public static final RegisterCategory CPU = new RegisterCategory("CPU");
-    public static final RegisterCategory XMM = new RegisterCategory("XMM");
 
     // @formatter:off
 
@@ -66,6 +65,10 @@
         r8, r9, r10, r11, r12, r13, r14, r15
     };
 
+    private static final int XMM_REFERENCE_MAP_SHIFT = 2;
+
+    public static final RegisterCategory XMM = new RegisterCategory("XMM", cpuRegisters.length, XMM_REFERENCE_MAP_SHIFT);
+
     // XMM registers
     public static final Register xmm0 = new Register(16, 0, "xmm0", XMM);
     public static final Register xmm1 = new Register(17, 1, "xmm1", XMM);
@@ -135,7 +138,7 @@
     private final EnumSet<CPUFeature> features;
 
     public AMD64(EnumSet<CPUFeature> features) {
-        super("AMD64", 8, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, r15.encoding + 1, 8);
+        super("AMD64", 8, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, cpuRegisters.length + xmmRegisters.length << XMM_REFERENCE_MAP_SHIFT, 8);
         this.features = features;
         assert features.contains(CPUFeature.SSE2) : "minimum config for x64";
     }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java	Mon Jun 30 12:02:19 2014 +0200
@@ -34,11 +34,11 @@
 public abstract class Architecture {
 
     /**
-     * The number of bits required in a bit map covering all the registers that may store
-     * references. The bit position of a register in the map is the register's
-     * {@linkplain Register#number number}.
+     * The number of entries required in a {@link ReferenceMap} covering all the registers that may
+     * store references. The index of a register in the reference map is given by
+     * {@link Register#getReferenceMapIndex()}.
      */
-    private final int registerReferenceMapBitCount;
+    private final int registerReferenceMapSize;
 
     /**
      * Represents the natural size of words (typically registers and pointers) of this architecture,
@@ -85,7 +85,7 @@
     private final int returnAddressSize;
 
     protected Architecture(String name, int wordSize, ByteOrder byteOrder, boolean unalignedMemoryAccess, Register[] registers, int implicitMemoryBarriers, int nativeCallDisplacementOffset,
-                    int registerReferenceMapBitCount, int returnAddressSize) {
+                    int registerReferenceMapSize, int returnAddressSize) {
         this.name = name;
         this.registers = registers;
         this.wordSize = wordSize;
@@ -93,13 +93,13 @@
         this.unalignedMemoryAccess = unalignedMemoryAccess;
         this.implicitMemoryBarriers = implicitMemoryBarriers;
         this.machineCodeCallDisplacementOffset = nativeCallDisplacementOffset;
-        this.registerReferenceMapBitCount = registerReferenceMapBitCount;
+        this.registerReferenceMapSize = registerReferenceMapSize;
         this.returnAddressSize = returnAddressSize;
     }
 
     /**
      * Converts this architecture to a string.
-     * 
+     *
      * @return the string representation of this architecture
      */
     @Override
@@ -107,8 +107,8 @@
         return getName().toLowerCase();
     }
 
-    public int getRegisterReferenceMapBitCount() {
-        return registerReferenceMapBitCount;
+    public int getRegisterReferenceMapSize() {
+        return registerReferenceMapSize;
     }
 
     /**
@@ -163,7 +163,7 @@
     /**
      * Determines the barriers in a given barrier mask that are explicitly required on this
      * architecture.
-     * 
+     *
      * @param barriers a mask of the barrier constants
      * @return the value of {@code barriers} minus the barriers unnecessary on this architecture
      */
@@ -173,9 +173,9 @@
 
     /**
      * Gets the size in bytes of the specified kind for this target.
-     * 
+     *
      * @param kind the kind for which to get the size
-     * 
+     *
      * @return the size in bytes of {@code kind}
      */
     public int getSizeInBytes(PlatformKind kind) {
@@ -205,7 +205,7 @@
 
     /**
      * Determine whether a kind can be stored in a register of a given category.
-     * 
+     *
      * @param category the category of the register
      * @param kind the kind that should be stored in the register
      */
@@ -213,7 +213,7 @@
 
     /**
      * Return the largest kind that can be stored in a register of a given category.
-     * 
+     *
      * @param category the category of the register
      * @return the largest kind that can be stored in a register {@code category}
      */
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Mon Jun 30 12:02:19 2014 +0200
@@ -27,9 +27,9 @@
 
 public interface ReferenceMap {
 
-    void setRegister(int idx, PlatformKind kind);
+    void setRegister(int idx, LIRKind kind);
 
-    void setStackSlot(int offset, PlatformKind kind);
+    void setStackSlot(int offset, LIRKind kind);
 
     boolean hasRegisterRefMap();
 
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -79,10 +79,23 @@
      */
     public static class RegisterCategory {
 
-        private String name;
+        private final String name;
+
+        private final int referenceMapOffset;
+        private final int referenceMapShift;
 
         public RegisterCategory(String name) {
+            this(name, 0, 0);
+        }
+
+        public RegisterCategory(String name, int referenceMapOffset) {
+            this(name, referenceMapOffset, 0);
+        }
+
+        public RegisterCategory(String name, int referenceMapOffset, int referenceMapShift) {
             this.name = name;
+            this.referenceMapOffset = referenceMapOffset;
+            this.referenceMapShift = referenceMapShift;
         }
 
         @Override
@@ -107,7 +120,7 @@
 
     /**
      * Creates a {@link Register} instance.
-     * 
+     *
      * @param number unique identifier for the register
      * @param encoding the target machine encoding for the register
      * @param name the mnemonic name for the register
@@ -125,27 +138,34 @@
     }
 
     /**
+     * Get the start index of this register in the {@link ReferenceMap}.
+     */
+    public int getReferenceMapIndex() {
+        return (encoding << registerCategory.referenceMapShift) + registerCategory.referenceMapOffset;
+    }
+
+    /**
      * Gets this register as a {@linkplain RegisterValue value} with a specified kind.
-     * 
+     *
      * @param kind the specified kind
      * @return the {@link RegisterValue}
      */
-    public RegisterValue asValue(PlatformKind kind) {
+    public RegisterValue asValue(LIRKind kind) {
         return new RegisterValue(kind, this);
     }
 
     /**
      * Gets this register as a {@linkplain RegisterValue value} with no particular kind.
-     * 
+     *
      * @return a {@link RegisterValue} with {@link Kind#Illegal} kind.
      */
     public RegisterValue asValue() {
-        return asValue(Kind.Illegal);
+        return asValue(LIRKind.Illegal);
     }
 
     /**
      * Determines if this is a valid register.
-     * 
+     *
      * @return {@code true} iff this register is valid
      */
     public boolean isValid() {
@@ -154,7 +174,7 @@
 
     /**
      * Gets the maximum register {@linkplain #number number} in a given set of registers.
-     * 
+     *
      * @param registers the set of registers to process
      * @return the maximum register number for any register in {@code registers}
      */
@@ -170,7 +190,7 @@
 
     /**
      * Gets the maximum register {@linkplain #encoding encoding} in a given set of registers.
-     * 
+     *
      * @param registers the set of registers to process
      * @return the maximum register encoding for any register in {@code registers}
      */
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,8 +27,8 @@
 /**
  * Denotes a register that stores a value of a fixed kind. There is exactly one (canonical) instance
  * of {@link RegisterValue} for each ({@link Register}, {@link Kind}) pair. Use
- * {@link Register#asValue(PlatformKind)} to retrieve the canonical {@link RegisterValue} instance
- * for a given (register,kind) pair.
+ * {@link Register#asValue(LIRKind)} to retrieve the canonical {@link RegisterValue} instance for a
+ * given (register,kind) pair.
  */
 public final class RegisterValue extends AllocatableValue {
 
@@ -39,7 +39,7 @@
     /**
      * Should only be called from {@link Register#Register} to ensure canonicalization.
      */
-    protected RegisterValue(PlatformKind kind, Register register) {
+    protected RegisterValue(LIRKind kind, Register register) {
         super(kind);
         this.reg = register;
     }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -38,22 +38,22 @@
     /**
      * Gets a {@link StackSlot} instance representing a stack slot at a given index holding a value
      * of a given kind.
-     * 
+     *
      * @param kind The kind of the value stored in the stack slot.
      * @param offset The offset of the stack slot (in bytes)
      * @param addFrameSize Specifies if the offset is relative to the stack pointer, or the
      *            beginning of the frame (stack pointer + total frame size).
      */
-    public static StackSlot get(PlatformKind kind, int offset, boolean addFrameSize) {
+    public static StackSlot get(LIRKind kind, int offset, boolean addFrameSize) {
         assert addFrameSize || offset >= 0;
         return new StackSlot(kind, offset, addFrameSize);
     }
 
     /**
-     * Private constructor to enforce use of {@link #get(PlatformKind, int, boolean)} so that a
-     * cache can be used.
+     * Private constructor to enforce use of {@link #get(LIRKind, int, boolean)} so that a cache can
+     * be used.
      */
-    private StackSlot(PlatformKind kind, int offset, boolean addFrameSize) {
+    private StackSlot(LIRKind kind, int offset, boolean addFrameSize) {
         super(kind);
         this.offset = offset;
         this.addFrameSize = addFrameSize;
@@ -61,7 +61,7 @@
 
     /**
      * Gets the offset of this stack slot, relative to the stack pointer.
-     * 
+     *
      * @return The offset of this slot (in bytes).
      */
     public int getOffset(int totalFrameSize) {
@@ -100,7 +100,7 @@
     public StackSlot asOutArg() {
         assert offset >= 0;
         if (addFrameSize) {
-            return get(getPlatformKind(), offset, false);
+            return get(getLIRKind(), offset, false);
         }
         return this;
     }
@@ -111,7 +111,7 @@
     public StackSlot asInArg() {
         assert offset >= 0;
         if (!addFrameSize) {
-            return get(getPlatformKind(), offset, true);
+            return get(getLIRKind(), offset, true);
         }
         return this;
     }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -56,7 +56,7 @@
      * The stack alignment requirement of the platform. For example, from Appendix D of <a
      * href="http://www.intel.com/Assets/PDF/manual/248966.pdf">Intel 64 and IA-32 Architectures
      * Optimization Reference Manual</a>:
-     * 
+     *
      * <pre>
      *     "It is important to ensure that the stack frame is aligned to a
      *      16-byte boundary upon function entry to keep local __m128 data,
@@ -86,5 +86,23 @@
         return arch.getSizeInBytes(kind);
     }
 
+    public LIRKind getLIRKind(Kind javaKind) {
+        switch (javaKind) {
+            case Boolean:
+            case Byte:
+            case Short:
+            case Char:
+            case Int:
+            case Long:
+            case Float:
+            case Double:
+                return LIRKind.value(javaKind);
+            case Object:
+                return LIRKind.reference(javaKind);
+            default:
+                return LIRKind.Illegal;
+        }
+    }
+
     public abstract ReferenceMap createReferenceMap(boolean hasRegisters, int stackSlotCount);
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -47,7 +47,7 @@
      * returned by {@link ResolvedJavaType#getInstanceFields(boolean) getInstanceFields(true)}. If
      * {@code type} is an array then the length of the values array determines the reallocated array
      * length.
-     * 
+     *
      * @param type the type of the object whose allocation was removed during compilation. This can
      *            be either an instance of an array type.
      * @param values an array containing all the values to be stored into the object when it is
@@ -61,7 +61,7 @@
     }
 
     private VirtualObject(ResolvedJavaType type, Value[] values, int id) {
-        super(Kind.Object);
+        super(LIRKind.reference(Kind.Object));
         this.type = type;
         this.values = values;
         this.id = id;
@@ -164,7 +164,7 @@
 
     /**
      * Overwrites the current set of values with a new one.
-     * 
+     *
      * @param values an array containing all the values to be stored into the object when it is
      *            recreated.
      */
@@ -175,7 +175,7 @@
 
     @Override
     public int hashCode() {
-        return getPlatformKind().hashCode() + type.hashCode();
+        return getLIRKind().hashCode() + type.hashCode();
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/ConstantTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * 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.api.meta.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+
+public class ConstantTest extends FieldUniverse {
+
+    @Test
+    public void testNegativeZero() {
+        Assert.assertTrue("Constant for 0.0f must be different from -0.0f", Constant.FLOAT_0 != Constant.forFloat(-0.0F));
+        Assert.assertTrue("Constant for 0.0d must be different from -0.0d", Constant.DOUBLE_0 != Constant.forDouble(-0.0d));
+    }
+
+    @Test
+    public void testNullIsNull() {
+        Assert.assertTrue(Constant.NULL_OBJECT.isNull());
+    }
+
+    @Test
+    public void testOne() {
+        for (Kind kind : Kind.values()) {
+            if (kind.isNumericInteger() || kind.isNumericFloat()) {
+                Assert.assertTrue(Constant.one(kind).getKind() == kind);
+            }
+        }
+        Assert.assertEquals(1, Constant.one(Kind.Int).asInt());
+        Assert.assertEquals(1L, Constant.one(Kind.Long).asLong());
+        Assert.assertEquals(1, Constant.one(Kind.Byte).asInt());
+        Assert.assertEquals(1, Constant.one(Kind.Short).asInt());
+        Assert.assertEquals(1, Constant.one(Kind.Char).asInt());
+        Assert.assertTrue(1F == Constant.one(Kind.Float).asFloat());
+        Assert.assertTrue(1D == Constant.one(Kind.Double).asDouble());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testIllegalOne() {
+        Constant.one(Kind.Illegal);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testVoidOne() {
+        Constant.one(Kind.Void);
+    }
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -32,7 +32,7 @@
 
     public static final AllocatableValue[] NONE = {};
 
-    public AllocatableValue(PlatformKind platformKind) {
-        super(platformKind);
+    public AllocatableValue(LIRKind lirKind) {
+        super(lirKind);
     }
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,38 +32,25 @@
 
     private static final long serialVersionUID = -6355452536852663986L;
 
-    private static final Constant[] INT_CONSTANT_CACHE = new Constant[100];
-    static {
-        for (int i = 0; i < INT_CONSTANT_CACHE.length; ++i) {
-            INT_CONSTANT_CACHE[i] = new PrimitiveConstant(Kind.Int, i);
-        }
-    }
-
+    /*
+     * Using a larger cache for integers leads to only a slight increase in cache hit ratio which is
+     * not enough to justify the impact on startup time.
+     */
     public static final Constant NULL_OBJECT = new NullConstant();
     public static final Constant INT_MINUS_1 = new PrimitiveConstant(Kind.Int, -1);
-    public static final Constant INT_0 = forInt(0);
-    public static final Constant INT_1 = forInt(1);
-    public static final Constant INT_2 = forInt(2);
-    public static final Constant INT_3 = forInt(3);
-    public static final Constant INT_4 = forInt(4);
-    public static final Constant INT_5 = forInt(5);
+    public static final Constant INT_0 = new PrimitiveConstant(Kind.Int, 0);
+    public static final Constant INT_1 = new PrimitiveConstant(Kind.Int, 1);
+    public static final Constant INT_2 = new PrimitiveConstant(Kind.Int, 2);
     public static final Constant LONG_0 = new PrimitiveConstant(Kind.Long, 0L);
     public static final Constant LONG_1 = new PrimitiveConstant(Kind.Long, 1L);
     public static final Constant FLOAT_0 = new PrimitiveConstant(Kind.Float, Float.floatToRawIntBits(0.0F));
     public static final Constant FLOAT_1 = new PrimitiveConstant(Kind.Float, Float.floatToRawIntBits(1.0F));
-    public static final Constant FLOAT_2 = new PrimitiveConstant(Kind.Float, Float.floatToRawIntBits(2.0F));
     public static final Constant DOUBLE_0 = new PrimitiveConstant(Kind.Double, Double.doubleToRawLongBits(0.0D));
     public static final Constant DOUBLE_1 = new PrimitiveConstant(Kind.Double, Double.doubleToRawLongBits(1.0D));
     public static final Constant TRUE = new PrimitiveConstant(Kind.Boolean, 1L);
     public static final Constant FALSE = new PrimitiveConstant(Kind.Boolean, 0L);
 
-    static {
-        assert FLOAT_0 != forFloat(-0.0F) : "Constant for 0.0f must be different from -0.0f";
-        assert DOUBLE_0 != forDouble(-0.0d) : "Constant for 0.0d must be different from -0.0d";
-        assert NULL_OBJECT.isNull();
-    }
-
-    protected Constant(PlatformKind kind) {
+    protected Constant(LIRKind kind) {
         super(kind);
     }
 
@@ -183,9 +170,6 @@
         if (Float.compare(f, 1.0F) == 0) {
             return FLOAT_1;
         }
-        if (Float.compare(f, 2.0F) == 0) {
-            return FLOAT_2;
-        }
         return new PrimitiveConstant(Kind.Float, Float.floatToRawIntBits(f));
     }
 
@@ -196,7 +180,13 @@
      * @return a boxed copy of {@code value}
      */
     public static Constant forLong(long i) {
-        return i == 0 ? LONG_0 : i == 1 ? LONG_1 : new PrimitiveConstant(Kind.Long, i);
+        if (i == 0) {
+            return LONG_0;
+        } else if (i == 1) {
+            return LONG_1;
+        } else {
+            return new PrimitiveConstant(Kind.Long, i);
+        }
     }
 
     /**
@@ -206,13 +196,18 @@
      * @return a boxed copy of {@code value}
      */
     public static Constant forInt(int i) {
-        if (i == -1) {
-            return INT_MINUS_1;
+        switch (i) {
+            case -1:
+                return INT_MINUS_1;
+            case 0:
+                return INT_0;
+            case 1:
+                return INT_1;
+            case 2:
+                return INT_2;
+            default:
+                return new PrimitiveConstant(Kind.Int, i);
         }
-        if (i >= 0 && i < INT_CONSTANT_CACHE.length) {
-            return INT_CONSTANT_CACHE[i];
-        }
-        return new PrimitiveConstant(Kind.Int, i);
     }
 
     /**
@@ -346,6 +341,8 @@
      */
     public static Constant zero(Kind kind) {
         switch (kind) {
+            case Boolean:
+                return FALSE;
             case Byte:
                 return forByte((byte) 0);
             case Char:
@@ -370,6 +367,8 @@
      */
     public static Constant one(Kind kind) {
         switch (kind) {
+            case Boolean:
+                return TRUE;
             case Byte:
                 return forByte((byte) 1);
             case Char:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LIRKind.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,204 @@
+/*
+ * 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.api.meta;
+
+/**
+ * Represents the type of values in the LIR. It is composed of a {@link PlatformKind} that gives the
+ * low level representation of the value, and a {@link #referenceMask} that describes the location
+ * of object references in the value.
+ */
+public final class LIRKind {
+
+    /**
+     * The non-type. This uses {@link #derivedReference}, so it can never be part of an oop map.
+     */
+    public static final LIRKind Illegal = derivedReference(Kind.Illegal);
+
+    private final PlatformKind platformKind;
+    private final int referenceMask;
+
+    private static final int DERIVED_REFERENCE = -1;
+
+    private LIRKind(PlatformKind platformKind, int referenceMask) {
+        this.platformKind = platformKind;
+        this.referenceMask = referenceMask;
+    }
+
+    /**
+     * Create a {@link LIRKind} of type {@code platformKind} that contains a primitive value.
+     */
+    public static LIRKind value(PlatformKind platformKind) {
+        assert platformKind != Kind.Object : "Object should always be used as reference type";
+        return new LIRKind(platformKind, 0);
+    }
+
+    /**
+     * Create a {@link LIRKind} of type {@code platformKind} that contains a single tracked oop
+     * reference.
+     */
+    public static LIRKind reference(PlatformKind platformKind) {
+        int length = platformKind.getVectorLength();
+        assert 0 < length && length < 32 : "vector of " + length + " references not supported";
+        return new LIRKind(platformKind, (1 << length) - 1);
+    }
+
+    /**
+     * Create a {@link LIRKind} of type {@code platformKind} that contains a value that is derived
+     * from a reference. Values of this {@link LIRKind} can not be live at safepoints.
+     */
+    public static LIRKind derivedReference(PlatformKind platformKind) {
+        return new LIRKind(platformKind, DERIVED_REFERENCE);
+    }
+
+    /**
+     * Create a new {@link LIRKind} with the same reference information and a new
+     * {@linkplain #getPlatformKind platform kind}. If the new kind is a longer vector than this,
+     * the new elements are marked as untracked values.
+     */
+    public LIRKind changeType(PlatformKind newPlatformKind) {
+        if (isDerivedReference()) {
+            return derivedReference(newPlatformKind);
+        } else if (referenceMask == 0) {
+            // value type
+            return new LIRKind(newPlatformKind, 0);
+        } else {
+            // reference type
+            int newLength = Math.min(32, newPlatformKind.getVectorLength());
+            int newReferenceMask = referenceMask & (0xFFFFFFFF >>> (32 - newLength));
+            assert newReferenceMask != DERIVED_REFERENCE;
+            return new LIRKind(newPlatformKind, newReferenceMask);
+        }
+    }
+
+    /**
+     * Create a new {@link LIRKind} with a new {@linkplain #getPlatformKind platform kind}. If the
+     * new kind is longer than this, the reference positions are repeated to fill the vector.
+     */
+    public LIRKind repeat(PlatformKind newPlatformKind) {
+        if (isDerivedReference()) {
+            return derivedReference(newPlatformKind);
+        } else if (referenceMask == 0) {
+            // value type
+            return new LIRKind(newPlatformKind, 0);
+        } else {
+            // reference type
+            int oldLength = platformKind.getVectorLength();
+            int newLength = newPlatformKind.getVectorLength();
+            assert oldLength <= newLength && newLength < 32 && (newLength % oldLength) == 0;
+
+            // repeat reference mask to fill new kind
+            int newReferenceMask = 0;
+            for (int i = 0; i < newLength; i += platformKind.getVectorLength()) {
+                newReferenceMask |= referenceMask << i;
+            }
+
+            assert newReferenceMask != DERIVED_REFERENCE;
+            return new LIRKind(newPlatformKind, newReferenceMask);
+        }
+    }
+
+    /**
+     * Create a new {@link LIRKind} with the same type, but marked as containing a derivedReference.
+     */
+    public LIRKind makeDerivedReference() {
+        return new LIRKind(platformKind, DERIVED_REFERENCE);
+    }
+
+    /**
+     * Get the low level type that is used in code generation.
+     */
+    public PlatformKind getPlatformKind() {
+        return platformKind;
+    }
+
+    /**
+     * Check whether this value is derived from a reference. If this returns {@code true}, this
+     * value must not be live at safepoints.
+     */
+    public boolean isDerivedReference() {
+        return referenceMask == DERIVED_REFERENCE;
+    }
+
+    /**
+     * Check whether the {@code idx}th part of this value is a reference that must be tracked at
+     * safepoints.
+     *
+     * @param idx The index into the vector if this is a vector kind. Must be 0 if this is a scalar
+     *            kind.
+     */
+    public boolean isReference(int idx) {
+        assert 0 <= idx && idx < platformKind.getVectorLength() : "invalid index " + idx + " in " + this;
+        return !isDerivedReference() && (referenceMask & 1 << idx) != 0;
+    }
+
+    /**
+     * Check whether this kind is a value type that doesn't need to be tracked at safepoints.
+     */
+    public boolean isValue() {
+        return referenceMask == 0;
+    }
+
+    @Override
+    public String toString() {
+        if (isValue()) {
+            return platformKind.name();
+        } else if (isDerivedReference()) {
+            return platformKind.name() + "[*]";
+        } else {
+            StringBuilder ret = new StringBuilder();
+            ret.append(platformKind.name());
+            ret.append('[');
+            for (int i = 0; i < platformKind.getVectorLength(); i++) {
+                if (isReference(i)) {
+                    ret.append('.');
+                } else {
+                    ret.append(' ');
+                }
+            }
+            ret.append(']');
+            return ret.toString();
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((platformKind == null) ? 0 : platformKind.hashCode());
+        result = prime * result + referenceMask;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof LIRKind)) {
+            return false;
+        }
+
+        LIRKind other = (LIRKind) obj;
+        return platformKind == other.platformKind && referenceMask == other.referenceMask;
+    }
+}
\ No newline at end of file
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NullConstant.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NullConstant.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,7 +30,7 @@
     private static final long serialVersionUID = 8906209595800783961L;
 
     protected NullConstant() {
-        super(Kind.Object);
+        super(LIRKind.reference(Kind.Object));
     }
 
     @Override
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PlatformKind.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PlatformKind.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -30,4 +30,8 @@
     String name();
 
     Constant getDefaultValue();
+
+    default int getVectorLength() {
+        return 1;
+    }
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PrimitiveConstant.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PrimitiveConstant.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,7 @@
     private final long primitive;
 
     protected PrimitiveConstant(Kind kind, long primitive) {
-        super(kind);
+        super(LIRKind.value(kind));
         this.primitive = primitive;
 
         assert kind.isPrimitive() || kind == Kind.Illegal;
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
 
     private static final long serialVersionUID = -6909397188697766469L;
 
-    @SuppressWarnings("serial") public static final AllocatableValue ILLEGAL = new AllocatableValue(Kind.Illegal) {
+    @SuppressWarnings("serial") public static final AllocatableValue ILLEGAL = new AllocatableValue(LIRKind.Illegal) {
 
         @Override
         public String toString() {
@@ -41,17 +41,17 @@
     };
 
     private final Kind kind;
-    private final PlatformKind platformKind;
+    private final LIRKind lirKind;
 
     /**
      * Initializes a new value of the specified kind.
      *
-     * @param platformKind the kind
+     * @param lirKind the kind
      */
-    protected Value(PlatformKind platformKind) {
-        this.platformKind = platformKind;
-        if (platformKind instanceof Kind) {
-            this.kind = (Kind) platformKind;
+    protected Value(LIRKind lirKind) {
+        this.lirKind = lirKind;
+        if (getPlatformKind() instanceof Kind) {
+            this.kind = (Kind) getPlatformKind();
         } else {
             this.kind = Kind.Illegal;
         }
@@ -72,23 +72,27 @@
         return kind;
     }
 
+    public final LIRKind getLIRKind() {
+        return lirKind;
+    }
+
     /**
      * Returns the platform specific kind used to store this value.
      */
     public final PlatformKind getPlatformKind() {
-        return platformKind;
+        return lirKind.getPlatformKind();
     }
 
     @Override
     public int hashCode() {
-        return 41 + platformKind.hashCode();
+        return 41 + lirKind.hashCode();
     }
 
     @Override
     public boolean equals(Object obj) {
         if (obj instanceof Value) {
             Value that = (Value) obj;
-            return kind.equals(that.kind) && platformKind.equals(that.platformKind);
+            return kind.equals(that.kind) && lirKind.equals(that.lirKind);
         }
         return false;
     }
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Mon Jun 30 12:02:19 2014 +0200
@@ -185,7 +185,7 @@
     }
 
     private void emitArithImm8(int op, Register dst, int imm8) {
-        int encode = prefixAndEncode(op, dst.encoding, true);
+        int encode = prefixAndEncode(op, false, dst.encoding, true);
         emitByte(0x80);
         emitByte(0xC0 | encode);
         emitByte(imm8);
@@ -560,7 +560,7 @@
     }
 
     public final void cmpb(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding, true);
+        int encode = prefixAndEncode(dst.encoding, true, src.encoding, true);
         emitByte(0x3A);
         emitByte(0xC0 | encode);
     }
@@ -1137,7 +1137,7 @@
     }
 
     public final void movsbl(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding, true);
+        int encode = prefixAndEncode(dst.encoding, false, src.encoding, true);
         emitByte(0x0F);
         emitByte(0xBE);
         emitByte(0xC0 | encode);
@@ -2042,17 +2042,17 @@
     }
 
     private int prefixAndEncode(int dstEnc, int srcEnc) {
-        return prefixAndEncode(dstEnc, srcEnc, false);
+        return prefixAndEncode(dstEnc, false, srcEnc, false);
     }
 
-    private int prefixAndEncode(int dstEncoding, int srcEncoding, boolean byteinst) {
+    private int prefixAndEncode(int dstEncoding, boolean dstIsByte, int srcEncoding, boolean srcIsByte) {
         int srcEnc = srcEncoding;
         int dstEnc = dstEncoding;
         if (dstEnc < 8) {
             if (srcEnc >= 8) {
                 emitByte(Prefix.REXB);
                 srcEnc -= 8;
-            } else if (byteinst && srcEnc >= 4) {
+            } else if ((srcIsByte && srcEnc >= 4) || (dstIsByte && dstEnc >= 4)) {
                 emitByte(Prefix.REX);
             }
         } else {
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Mon Jun 30 12:02:19 2014 +0200
@@ -35,7 +35,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
@@ -482,7 +481,7 @@
             Value classRef = lirBuilder.getClassConstant(field.getDeclaringClass());
             long displacement = lirBuilder.getFieldOffset(field);
             Value address = gen.emitAddress(classRef, displacement, Value.ILLEGAL, 0);
-            PlatformKind readKind = gen.getPlatformKind(StampFactory.forKind(field.getKind()));
+            LIRKind readKind = backend.getTarget().getLIRKind(field.getKind());
             LIRFrameState state = createFrameState(frameState);
             return gen.emitLoad(readKind, address, state);
         }
@@ -506,7 +505,7 @@
         emitNullCheck(array);
         long displacement = lirBuilder.getArrayLengthOffset();
         Value address = gen.emitAddress(array, displacement, Value.ILLEGAL, 0);
-        PlatformKind readKind = gen.getPlatformKind(StampFactory.forKind(Kind.Int));
+        LIRKind readKind = backend.getTarget().getLIRKind(Kind.Int);
         LIRFrameState state = createFrameState(frameState);
         return gen.emitLoad(readKind, address, state);
     }
@@ -682,7 +681,7 @@
         for (int i = 0; i < frameState.stackSize(); i++) {
             Value src = frameState.stackAt(i);
             if (src instanceof Constant) {
-                AllocatableValue dst = gen.newVariable(src.getPlatformKind());
+                AllocatableValue dst = gen.newVariable(src.getLIRKind());
                 gen.emitMove(dst, src);
                 frameState.storeStack(i, dst);
                 Debug.log("introduce new variabe %s for stackslot %d (end of block %s", dst, i, currentBlock);
@@ -691,7 +690,7 @@
         for (int i = 0; i < frameState.localsSize(); i++) {
             Value src = frameState.localAt(i);
             if (src instanceof Constant) {
-                AllocatableValue dst = gen.newVariable(src.getPlatformKind());
+                AllocatableValue dst = gen.newVariable(src.getLIRKind());
                 gen.emitMove(dst, src);
                 frameState.storeLocal(i, dst);
                 Debug.log("introduce new variabe %s for local %d (end of block %s", dst, i, currentBlock);
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -77,11 +77,11 @@
  */
 public abstract class AMD64LIRGenerator extends LIRGenerator {
 
-    private static final RegisterValue RAX_I = AMD64.rax.asValue(Kind.Int);
-    private static final RegisterValue RAX_L = AMD64.rax.asValue(Kind.Long);
-    private static final RegisterValue RDX_I = AMD64.rdx.asValue(Kind.Int);
-    private static final RegisterValue RDX_L = AMD64.rdx.asValue(Kind.Long);
-    private static final RegisterValue RCX_I = AMD64.rcx.asValue(Kind.Int);
+    private static final RegisterValue RAX_I = AMD64.rax.asValue(LIRKind.value(Kind.Int));
+    private static final RegisterValue RAX_L = AMD64.rax.asValue(LIRKind.value(Kind.Long));
+    private static final RegisterValue RDX_I = AMD64.rdx.asValue(LIRKind.value(Kind.Int));
+    private static final RegisterValue RDX_L = AMD64.rdx.asValue(LIRKind.value(Kind.Long));
+    private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(Kind.Int));
 
     private class AMD64SpillMoveFactory implements LIR.SpillMoveFactory {
 
@@ -125,7 +125,7 @@
 
     @Override
     public Variable emitMove(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         emitMove(result, input);
         return result;
     }
@@ -208,7 +208,8 @@
             }
         }
 
-        return new AMD64AddressValue(target().wordKind, baseRegister, indexRegister, scaleEnum, displacementInt);
+        LIRKind resultKind = getAddressKind(base, displacement, index);
+        return new AMD64AddressValue(resultKind, baseRegister, indexRegister, scaleEnum, displacementInt);
     }
 
     public AMD64AddressValue asAddressValue(Value address) {
@@ -221,7 +222,7 @@
 
     @Override
     public Variable emitAddress(StackSlot address) {
-        Variable result = newVariable(target().wordKind);
+        Variable result = newVariable(LIRKind.value(target().wordKind));
         append(new StackLeaOp(result, address));
         return result;
     }
@@ -270,7 +271,7 @@
         boolean mirrored = emitCompare(cmpKind, left, right);
         Condition finalCondition = mirrored ? cond.mirror() : cond;
 
-        Variable result = newVariable(trueValue.getKind());
+        Variable result = newVariable(trueValue.getLIRKind());
         if (cmpKind == Kind.Float || cmpKind == Kind.Double) {
             append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
         } else {
@@ -282,7 +283,7 @@
     @Override
     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
         emitIntegerTest(left, right);
-        Variable result = newVariable(trueValue.getKind());
+        Variable result = newVariable(trueValue.getLIRKind());
         append(new CondMoveOp(result, Condition.EQ, load(trueValue), loadNonConst(falseValue)));
         return result;
     }
@@ -432,7 +433,7 @@
     @Override
     public Variable emitNegate(Value inputVal) {
         AllocatableValue input = asAllocatable(inputVal);
-        Variable result = newVariable(input.getKind());
+        Variable result = newVariable(input.getLIRKind());
         switch (input.getKind()) {
             case Int:
                 append(new Unary1Op(INEG, result, input));
@@ -455,7 +456,7 @@
     @Override
     public Variable emitNot(Value inputVal) {
         AllocatableValue input = asAllocatable(inputVal);
-        Variable result = newVariable(input.getKind());
+        Variable result = newVariable(input.getLIRKind());
         switch (input.getKind()) {
             case Int:
                 append(new Unary1Op(INOT, result, input));
@@ -492,7 +493,7 @@
             case IXOR:
             case LXOR:
                 if (NumUtil.isInt(b.asLong())) {
-                    Variable result = newVariable(a.getKind());
+                    Variable result = newVariable(a.getLIRKind());
                     append(new BinaryRegConst(op, result, a, b));
                     return result;
                 }
@@ -501,7 +502,7 @@
             case IMUL:
             case LMUL:
                 if (NumUtil.isInt(b.asLong())) {
-                    Variable result = newVariable(a.getKind());
+                    Variable result = newVariable(a.getLIRKind());
                     append(new BinaryRegStackConst(op, result, a, b));
                     return result;
                 }
@@ -512,7 +513,7 @@
     }
 
     private Variable emitBinaryVar(AMD64Arithmetic op, boolean commutative, AllocatableValue a, AllocatableValue b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         if (commutative) {
             append(new BinaryCommutative(op, result, a, b));
         } else {
@@ -601,13 +602,13 @@
     }
 
     public Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         append(new BinaryMemory(op, kind, result, a, location, state));
         return result;
     }
 
     protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, AMD64AddressValue address, LIRFrameState state) {
-        Variable result = newVariable(kind);
+        Variable result = newVariable(LIRKind.value(kind));
         append(new Unary2MemoryOp(op, result, (Kind) null, address, state));
         return result;
     }
@@ -615,13 +616,13 @@
     protected Value emitZeroExtendMemory(Kind memoryKind, int resultBits, AMD64AddressValue address, LIRFrameState state) {
         // Issue a zero extending load of the proper bit size and set the result to
         // the proper kind.
-        Variable result = newVariable(resultBits == 32 ? Kind.Int : Kind.Long);
+        Variable result = newVariable(LIRKind.value(resultBits == 32 ? Kind.Int : Kind.Long));
         append(new ZeroExtendLoadOp(memoryKind, result, address, state));
         return result;
     }
 
     private void emitDivRem(AMD64Arithmetic op, Value a, Value b, LIRFrameState state) {
-        AllocatableValue rax = AMD64.rax.asValue(a.getPlatformKind());
+        AllocatableValue rax = AMD64.rax.asValue(a.getLIRKind());
         emitMove(rax, a);
         append(new DivRemOp(op, rax, asAllocatable(b), state));
     }
@@ -649,12 +650,12 @@
                 emitDivRem(LDIV, a, b, state);
                 return emitMove(RAX_L);
             case Float: {
-                Variable result = newVariable(a.getPlatformKind());
+                Variable result = newVariable(a.getLIRKind());
                 append(new BinaryRegStack(FDIV, result, asAllocatable(a), asAllocatable(b)));
                 return result;
             }
             case Double: {
-                Variable result = newVariable(a.getPlatformKind());
+                Variable result = newVariable(a.getLIRKind());
                 append(new BinaryRegStack(DDIV, result, asAllocatable(a), asAllocatable(b)));
                 return result;
             }
@@ -673,12 +674,12 @@
                 emitDivRem(LREM, a, b, state);
                 return emitMove(RDX_L);
             case Float: {
-                Variable result = newVariable(a.getPlatformKind());
+                Variable result = newVariable(a.getLIRKind());
                 append(new FPDivRemOp(FREM, result, load(a), load(b)));
                 return result;
             }
             case Double: {
-                Variable result = newVariable(a.getPlatformKind());
+                Variable result = newVariable(a.getLIRKind());
                 append(new FPDivRemOp(DREM, result, load(a), load(b)));
                 return result;
             }
@@ -752,7 +753,7 @@
     }
 
     private Variable emitShift(AMD64Arithmetic op, Value a, Value b) {
-        Variable result = newVariable(a.getPlatformKind());
+        Variable result = newVariable(a.getLIRKind());
         AllocatableValue input = asAllocatable(a);
         if (isConstant(b)) {
             append(new BinaryRegConst(op, result, input, asConstant(b)));
@@ -821,22 +822,22 @@
         }
     }
 
-    private AllocatableValue emitConvert2RegOp(PlatformKind kind, AMD64Arithmetic op, AllocatableValue input) {
+    private AllocatableValue emitConvert2RegOp(LIRKind kind, AMD64Arithmetic op, AllocatableValue input) {
         Variable result = newVariable(kind);
         append(new Unary2RegOp(op, result, input));
         return result;
     }
 
-    private AllocatableValue emitConvert2Op(PlatformKind kind, AMD64Arithmetic op, AllocatableValue input) {
+    private AllocatableValue emitConvert2Op(LIRKind kind, AMD64Arithmetic op, AllocatableValue input) {
         Variable result = newVariable(kind);
         append(new Unary2Op(op, result, input));
         return result;
     }
 
     @Override
-    public Value emitReinterpret(PlatformKind to, Value inputVal) {
-        Kind from = inputVal.getKind();
-        if (to == from) {
+    public Value emitReinterpret(LIRKind to, Value inputVal) {
+        LIRKind from = inputVal.getLIRKind();
+        if (to.equals(from)) {
             return inputVal;
         }
 
@@ -845,27 +846,28 @@
          * Conversions between integer to floating point types require moves between CPU and FPU
          * registers.
          */
-        switch ((Kind) to) {
+        Kind fromKind = (Kind) from.getPlatformKind();
+        switch ((Kind) to.getPlatformKind()) {
             case Int:
-                switch (from) {
+                switch (fromKind) {
                     case Float:
                         return emitConvert2Op(to, MOV_F2I, input);
                 }
                 break;
             case Long:
-                switch (from) {
+                switch (fromKind) {
                     case Double:
                         return emitConvert2Op(to, MOV_D2L, input);
                 }
                 break;
             case Float:
-                switch (from) {
+                switch (fromKind) {
                     case Int:
                         return emitConvert2Op(to, MOV_I2F, input);
                 }
                 break;
             case Double:
-                switch (from) {
+                switch (fromKind) {
                     case Long:
                         return emitConvert2Op(to, MOV_L2D, input);
                 }
@@ -878,25 +880,25 @@
         AllocatableValue input = asAllocatable(inputVal);
         switch (op) {
             case D2F:
-                return emitConvert2Op(Kind.Float, D2F, input);
+                return emitConvert2Op(LIRKind.value(Kind.Float), D2F, input);
             case D2I:
-                return emitConvert2Op(Kind.Int, D2I, input);
+                return emitConvert2Op(LIRKind.value(Kind.Int), D2I, input);
             case D2L:
-                return emitConvert2Op(Kind.Long, D2L, input);
+                return emitConvert2Op(LIRKind.value(Kind.Long), D2L, input);
             case F2D:
-                return emitConvert2Op(Kind.Double, F2D, input);
+                return emitConvert2Op(LIRKind.value(Kind.Double), F2D, input);
             case F2I:
-                return emitConvert2Op(Kind.Int, F2I, input);
+                return emitConvert2Op(LIRKind.value(Kind.Int), F2I, input);
             case F2L:
-                return emitConvert2Op(Kind.Long, F2L, input);
+                return emitConvert2Op(LIRKind.value(Kind.Long), F2L, input);
             case I2D:
-                return emitConvert2Op(Kind.Double, I2D, input);
+                return emitConvert2Op(LIRKind.value(Kind.Double), I2D, input);
             case I2F:
-                return emitConvert2Op(Kind.Float, I2F, input);
+                return emitConvert2Op(LIRKind.value(Kind.Float), I2F, input);
             case L2D:
-                return emitConvert2Op(Kind.Double, L2D, input);
+                return emitConvert2Op(LIRKind.value(Kind.Double), L2D, input);
             case L2F:
-                return emitConvert2Op(Kind.Float, L2F, input);
+                return emitConvert2Op(LIRKind.value(Kind.Float), L2F, input);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -906,7 +908,7 @@
     public Value emitNarrow(Value inputVal, int bits) {
         if (inputVal.getKind() == Kind.Long && bits <= 32) {
             // TODO make it possible to reinterpret Long as Int in LIR without move
-            return emitConvert2RegOp(Kind.Int, L2I, asAllocatable(inputVal));
+            return emitConvert2RegOp(LIRKind.value(Kind.Int), L2I, asAllocatable(inputVal));
         } else {
             return inputVal;
         }
@@ -921,11 +923,11 @@
             // sign extend to 64 bits
             switch (fromBits) {
                 case 8:
-                    return emitConvert2Op(Kind.Long, B2L, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.value(Kind.Long), B2L, asAllocatable(inputVal));
                 case 16:
-                    return emitConvert2Op(Kind.Long, S2L, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.value(Kind.Long), S2L, asAllocatable(inputVal));
                 case 32:
-                    return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.value(Kind.Long), I2L, asAllocatable(inputVal));
                 default:
                     throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
             }
@@ -933,9 +935,9 @@
             // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
             switch (fromBits) {
                 case 8:
-                    return emitConvert2Op(Kind.Int, B2I, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.value(Kind.Int), B2I, asAllocatable(inputVal));
                 case 16:
-                    return emitConvert2Op(Kind.Int, S2I, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.value(Kind.Int), S2I, asAllocatable(inputVal));
                 case 32:
                     return inputVal;
                 default:
@@ -951,17 +953,17 @@
             return inputVal;
         } else if (fromBits > 32) {
             assert inputVal.getKind() == Kind.Long;
-            Variable result = newVariable(Kind.Long);
+            Variable result = newVariable(LIRKind.value(Kind.Long));
             long mask = IntegerStamp.defaultMask(fromBits);
             append(new BinaryRegConst(AMD64Arithmetic.LAND, result, asAllocatable(inputVal), Constant.forLong(mask)));
             return result;
         } else {
             assert inputVal.getKind().getStackKind() == Kind.Int;
-            Variable result = newVariable(Kind.Int);
+            Variable result = newVariable(LIRKind.value(Kind.Int));
             int mask = (int) IntegerStamp.defaultMask(fromBits);
             append(new BinaryRegConst(AMD64Arithmetic.IAND, result, asAllocatable(inputVal), Constant.forInt(mask)));
             if (toBits > 32) {
-                Variable longResult = newVariable(Kind.Long);
+                Variable longResult = newVariable(LIRKind.value(Kind.Long));
                 emitMove(longResult, result);
                 return longResult;
             } else {
@@ -991,85 +993,95 @@
     }
 
     @Override
-    public void emitBitCount(Variable result, Value value) {
+    public Value emitBitCount(Value value) {
+        Variable result = newVariable(LIRKind.value(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
             append(new AMD64BitManipulationOp(IPOPCNT, result, asAllocatable(value)));
         } else {
             append(new AMD64BitManipulationOp(LPOPCNT, result, asAllocatable(value)));
         }
+        return result;
     }
 
     @Override
-    public void emitBitScanForward(Variable result, Value value) {
+    public Value emitBitScanForward(Value value) {
+        Variable result = newVariable(LIRKind.value(Kind.Int));
         append(new AMD64BitManipulationOp(BSF, result, asAllocatable(value)));
+        return result;
     }
 
     @Override
-    public void emitBitScanReverse(Variable result, Value value) {
+    public Value emitBitScanReverse(Value value) {
+        Variable result = newVariable(LIRKind.value(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
             append(new AMD64BitManipulationOp(IBSR, result, asAllocatable(value)));
         } else {
             append(new AMD64BitManipulationOp(LBSR, result, asAllocatable(value)));
         }
+        return result;
     }
 
     @Override
     public Value emitMathAbs(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new BinaryRegConst(DAND, result, asAllocatable(input), Constant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL))));
         return result;
     }
 
     @Override
     public Value emitMathSqrt(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new Unary2Op(SQRT, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathLog(Value input, boolean base10) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new AMD64MathIntrinsicOp(base10 ? LOG10 : LOG, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathCos(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new AMD64MathIntrinsicOp(COS, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathSin(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new AMD64MathIntrinsicOp(SIN, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathTan(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new AMD64MathIntrinsicOp(TAN, result, asAllocatable(input)));
         return result;
     }
 
     @Override
-    public void emitByteSwap(Variable result, Value input) {
+    public Value emitByteSwap(Value input) {
+        Variable result = newVariable(input.getLIRKind());
         append(new AMD64ByteSwapOp(result, input));
+        return result;
     }
 
     @Override
-    public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) {
+    public Value emitArrayEquals(Kind kind, Value array1, Value array2, Value length) {
+        Variable result = newVariable(LIRKind.value(Kind.Int));
         append(new AMD64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length)));
+        return result;
     }
 
     @Override
     public void emitReturn(Value input) {
         AllocatableValue operand = Value.ILLEGAL;
         if (input != null) {
-            operand = resultOperandFor(input.getKind());
+            operand = resultOperandFor(input.getLIRKind());
             emitMove(operand, input);
         }
         append(new ReturnOp(operand));
@@ -1079,12 +1091,12 @@
     public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
         // a temp is needed for loading object constants
         boolean needsTemp = key.getKind() == Kind.Object;
-        append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL));
+        append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getLIRKind()) : Value.ILLEGAL));
     }
 
     @Override
     protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
-        append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(target().wordKind), newVariable(key.getPlatformKind())));
+        append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().wordKind)), newVariable(key.getLIRKind())));
     }
 
 }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,8 +64,8 @@
                 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
                 if (((fixedWithNextNode instanceof IntegerDivNode) || (fixedWithNextNode instanceof IntegerRemNode)) && fixedWithNextNode.getClass() != divRem.getClass()) {
                     FixedBinaryNode otherDivRem = (FixedBinaryNode) fixedWithNextNode;
-                    if (otherDivRem.x() == divRem.x() && otherDivRem.y() == divRem.y() && !hasOperand(otherDivRem)) {
-                        Value[] results = ((AMD64LIRGenerator) gen).emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()), state((DeoptimizingNode) valueNode));
+                    if (otherDivRem.getX() == divRem.getX() && otherDivRem.getY() == divRem.getY() && !hasOperand(otherDivRem)) {
+                        Value[] results = ((AMD64LIRGenerator) gen).emitIntegerDivRem(operand(divRem.getX()), operand(divRem.getY()), state((DeoptimizingNode) valueNode));
                         if (divRem instanceof IntegerDivNode) {
                             setResult(divRem, results[0]);
                             setResult(otherDivRem, results[1]);
@@ -90,7 +90,7 @@
     }
 
     protected Kind getMemoryKind(Access access) {
-        return (Kind) gen.getPlatformKind(access.asNode().stamp());
+        return (Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind();
     }
 
     protected AMD64AddressValue makeAddress(Access access) {
@@ -133,33 +133,27 @@
             }
         }
 
-        PlatformKind cmpKind = gen.getPlatformKind(compare.x().stamp());
-        if (cmpKind instanceof Kind) {
-            // emitCompareBranchMemory expects the memory on the right, so mirror the condition if
-            // that's not true. It might be mirrored again the actual compare is emitted but that's
-            // ok.
-            Condition finalCondition = uncast(compare.x()) == access ? cond.mirror() : cond;
-            return new ComplexMatchResult() {
-                public Value evaluate(NodeLIRBuilder builder) {
-                    LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
-                    LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
-                    boolean unorderedIsTrue = compare.unorderedIsTrue();
-                    double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
-                    Value other;
-                    if (value.isConstant()) {
-                        other = value.asConstant();
-                    } else {
-                        other = operand(value);
-                    }
+        // emitCompareBranchMemory expects the memory on the right, so mirror the condition if
+        // that's not true. It might be mirrored again the actual compare is emitted but that's
+        // ok.
+        Condition finalCondition = uncast(compare.getX()) == access ? cond.mirror() : cond;
+        return new ComplexMatchResult() {
+            public Value evaluate(NodeLIRBuilder builder) {
+                LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+                LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+                boolean unorderedIsTrue = compare.unorderedIsTrue();
+                double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+                Value other;
+                if (value.isConstant()) {
+                    other = value.asConstant();
+                } else {
+                    other = operand(value);
+                }
 
-                    getLIRGeneratorTool().emitCompareBranchMemory((Kind) cmpKind, other, makeAddress(access), getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel,
-                                    trueLabelProbability);
-                    return null;
-                }
-            };
-        }
-        return null;
-
+                getLIRGeneratorTool().emitCompareBranchMemory(kind, other, makeAddress(access), getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
+                return null;
+            }
+        };
     }
 
     private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, Access access) {
@@ -273,7 +267,7 @@
         return null;
     }
 
-    private Value emitReinterpretMemory(PlatformKind to, Access access) {
+    private Value emitReinterpretMemory(LIRKind to, Access access) {
         AMD64AddressValue address = makeAddress(access);
         LIRFrameState state = getState(access);
         return getLIRGeneratorTool().emitLoad(to, address, state);
@@ -370,8 +364,8 @@
 
     @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))")
     public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) {
-        if ((lshift.getShiftAmountMask() & (lshift.y().asConstant().asInt() + rshift.y().asConstant().asInt())) == 0) {
-            return builder -> getLIRGeneratorTool().emitRol(operand(lshift.x()), operand(lshift.y()));
+        if ((lshift.getShiftAmountMask() & (lshift.getY().asConstant().asInt() + rshift.getY().asConstant().asInt())) == 0) {
+            return builder -> getLIRGeneratorTool().emitRol(operand(lshift.getX()), operand(lshift.getY()));
         }
         return null;
     }
@@ -421,9 +415,9 @@
     @MatchRule("(Write Narrow=narrow location value)")
     public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) {
         return builder -> {
-            PlatformKind writeKind = getLIRGeneratorTool().getPlatformKind(root.value().stamp());
+            LIRKind writeKind = getLIRGeneratorTool().getLIRKind(root.value().stamp());
             Value address = root.location().generateAddress(builder, getLIRGeneratorTool(), operand(root.object()));
-            Value v = operand(narrow.getInput());
+            Value v = operand(narrow.getValue());
             getLIRGeneratorTool().emitStore(writeKind, address, v, state(root));
             return null;
         };
@@ -461,7 +455,7 @@
     @MatchRule("(Reinterpret FloatingRead=access)")
     public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) {
         return builder -> {
-            PlatformKind kind = getLIRGeneratorTool().getPlatformKind(root.stamp());
+            LIRKind kind = getLIRGeneratorTool().getLIRKind(root.stamp());
             return emitReinterpretMemory(kind, access);
         };
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlock.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlock.java	Mon Jun 30 12:02:19 2014 +0200
@@ -64,6 +64,7 @@
      * True if block {@code a} dominates block {@code b}.
      */
     static boolean dominates(AbstractBlock<?> a, AbstractBlock<?> b) {
+        assert a != null;
         return isDominatedBy(b, a);
     }
 
@@ -71,6 +72,7 @@
      * True if block {@code a} is dominated by block {@code b}.
      */
     static boolean isDominatedBy(AbstractBlock<?> a, AbstractBlock<?> b) {
+        assert a != null;
         if (a == b) {
             return true;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/LIRKindTool.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,37 @@
+/*
+ * 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.compiler.common.spi;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * This interface can be used to access platform and VM specific kinds.
+ */
+public interface LIRKindTool {
+
+    LIRKind getIntegerKind(int bits);
+
+    LIRKind getFloatingKind(int bits);
+
+    LIRKind getObjectKind();
+}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/PlatformKindTool.java	Mon Jun 30 08:50:26 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +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.compiler.common.spi;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * This interface can be used to access platform and VM specific kinds.
- */
-public interface PlatformKindTool {
-
-    PlatformKind getIntegerKind(int bits);
-
-    PlatformKind getFloatingKind(int bits);
-
-    PlatformKind getObjectKind();
-}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -74,7 +74,7 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(PlatformKindTool tool) {
+    public LIRKind getLIRKind(LIRKindTool tool) {
         return tool.getFloatingKind(getBits());
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -40,7 +40,7 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(PlatformKindTool tool) {
+    public LIRKind getLIRKind(LIRKindTool tool) {
         throw GraalInternalError.shouldNotReachHere("illegal stamp should not reach backend");
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -84,7 +84,7 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(PlatformKindTool tool) {
+    public LIRKind getLIRKind(LIRKindTool tool) {
         return tool.getIntegerKind(getBits());
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -42,7 +42,7 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(PlatformKindTool tool) {
+    public LIRKind getLIRKind(LIRKindTool tool) {
         return tool.getObjectKind();
     }
 
@@ -64,4 +64,13 @@
         }
         return false;
     }
+
+    @Override
+    public Constant asConstant() {
+        if (alwaysNull()) {
+            return Constant.NULL_OBJECT;
+        } else {
+            return null;
+        }
+    }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -51,10 +51,9 @@
     public abstract Kind getStackKind();
 
     /**
-     * Gets a platform dependent {@link PlatformKind} that can be used to store a value of this
-     * stamp.
+     * Gets a platform dependent {@link LIRKind} that can be used to store a value of this stamp.
      */
-    public abstract PlatformKind getPlatformKind(PlatformKindTool tool);
+    public abstract LIRKind getLIRKind(LIRKindTool tool);
 
     /**
      * Returns the union of this stamp and the given stamp. Typically used to create stamps for phi
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -45,7 +45,7 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(PlatformKindTool tool) {
+    public LIRKind getLIRKind(LIRKindTool tool) {
         throw GraalInternalError.shouldNotReachHere("void stamp has no value");
     }
 
--- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java	Mon Jun 30 12:02:19 2014 +0200
@@ -152,13 +152,17 @@
         return true;
     }
 
+    HotSpotNmethod installedCode;
+
     @Override
     protected void dispatchKernelOkra(int range, Object... args) {
         HSAILHotSpotBackend backend = getHSAILBackend();
         if (backend.isDeviceInitialized()) {
             try {
-                HotSpotNmethod code = backend.compileAndInstallKernel(testMethod);
-                backend.executeKernel(code, range, args);
+                if (installedCode == null) {
+                    installedCode = backend.compileAndInstallKernel(testMethod);
+                }
+                backend.executeKernel(installedCode, range, args);
             } catch (InvalidInstalledCodeException e) {
                 Debug.log("WARNING:Invalid installed code: " + e);
                 e.printStackTrace();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndAddTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndAddTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -45,11 +45,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndSetTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndSetTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -45,11 +45,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndAddTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndAddTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -45,11 +45,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndSetTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndSetTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -45,11 +45,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMost20000StressGCTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * A version which is likely to get a GC while running the never_rans, and so is good for oops_do
+ * testing.
+ */
+public class BoundsCatchMost20000StressGCTest extends BoundsCatchManyBase {
+
+    @Override
+    int getGlobalSize() {
+        return 20000;
+    }
+
+    boolean isMyDeoptGid(int gid) {
+        return (gid > 100 && gid % 100 != 1);
+    }
+
+    int[] dummyArray;
+
+    // copied run routine here because otherwise polymorphic calls to isDeoptGid
+    @Override
+    public void run(int gid) {
+        int outval = getOutval(gid);
+        try {
+            int index = (isMyDeoptGid(gid) ? num + 1 : gid);
+            outArray[index] = outval;
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // set up so we can detect if we go thru here twice
+            outArray[gid] += outval;
+            // note: cannot record the exceptiongid here for many deopts in parallel
+
+            // allocate something so GCs happen more often
+            dummyArray = new int[1000];
+        }
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+
+        for (int i = 0; i < 10; i++) {
+            // we should not get an exception escaping from the kernel
+            dispatchMethodKernel(num);
+        }
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/EscapingNewStringConcatTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/EscapingNewStringConcatTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -50,8 +50,7 @@
         myOutArray[gid] = inArray[(gid + NUM / 2) % NUM] + inArray[gid];
     }
 
-    // Node implementing Lowerable not handled in HSAIL Backend: 6274|MonitorEnter
-    @Ignore
+    @Ignore("emitDirectCall unimplemented")
     @Test
     public void test() {
         try (DebugConfigScope s = disableIntercept()) {
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ArrayListGetTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ArrayListGetTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -23,14 +23,11 @@
 
 package com.oracle.graal.compiler.hsail.test.lambda;
 
-import static com.oracle.graal.debug.Debug.*;
-
 import java.util.*;
 
 import org.junit.*;
 
 import com.oracle.graal.compiler.hsail.test.infra.*;
-import com.oracle.graal.debug.*;
 
 /**
  * Tests calling ArrayList.get().
@@ -58,13 +55,10 @@
         });
     }
 
-    // NYI emitForeignCall charAlignedDisjointArraycopy
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
-    @Ignore
+    @Ignore("emitDirectCall unimplemented")
+    @Test
     public void testUsingLambdaMethod() {
-        try (DebugConfigScope s = disableIntercept()) {
-            testGeneratedHsailUsingLambdaMethod();
-        }
+        testGeneratedHsailUsingLambdaMethod();
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ArrayListSetTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+import java.util.*;
+
+/**
+ * Tests calling ArrayList.set().
+ */
+public class ArrayListSetTest extends GraalKernelTester {
+
+    final static int NUM = 50;
+    ArrayList<Integer> aryList = new ArrayList<>();
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < NUM; i++) {
+            aryList.add(-1);
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            aryList.set(gid, gid);
+        });
+    }
+
+    @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canHandleObjectAllocation());
+    }
+
+    @Test
+    @Ignore
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntAddAndGetGidTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntAddAndGetGidTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -47,11 +47,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntAddAndGetTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntAddAndGetTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,11 +44,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntDecAndGetTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntDecAndGetTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,11 +44,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndAddTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndAddTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,11 +44,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndDecTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndDecTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,11 +44,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndIncTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndIncTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,11 +44,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntIncAndGetTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntIncAndGetTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,11 +44,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongAddAndGetTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongAddAndGetTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -46,11 +46,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongGetAndAddTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongGetAndAddTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,11 +44,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongGetAndIncTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongGetAndIncTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,11 +44,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongIncAndGetTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongIncAndGetTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,11 +44,6 @@
     }
 
     @Override
-    protected boolean supportsRequiredCapabilities() {
-        return (canDeoptimize());
-    }
-
-    @Override
     public void runTest() {
         setupArrays();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ByteArrayCopyConjointTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests copying a byte array where src and dest overlap.
+ */
+public class ByteArrayCopyConjointTest extends GraalKernelTester {
+
+    final static int MAXOUTSIZ = 100;
+    final static int NUM = 20;
+
+    @Result byte[][] outArray = new byte[NUM][MAXOUTSIZ];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < NUM; i++) {
+            for (int j = 0; j < outArray[i].length; j++) {
+                outArray[i][j] = (byte) (i + j);
+            }
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            System.arraycopy(outArray[gid], 0, outArray[gid], gid % NUM, NUM);
+        });
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ByteArrayCopyDisjointTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,54 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests copying a byte array where src and dest do not overlap.
+ */
+public class ByteArrayCopyDisjointTest extends GraalKernelTester {
+
+    final static int MAXOUTSIZ = 100;
+    final static int NUM = 20;
+
+    @Result byte[][] outArray = new byte[NUM][MAXOUTSIZ];
+    byte[] inArray = new byte[NUM + MAXOUTSIZ];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < inArray.length; i++) {
+            inArray[i] = (byte) i;
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            System.arraycopy(inArray, gid, outArray[gid], 0, MAXOUTSIZ);
+        });
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/CharArrayCopyConjointTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests copying a char array where src and dest overlap.
+ */
+public class CharArrayCopyConjointTest extends GraalKernelTester {
+
+    final static int MAXOUTSIZ = 100;
+    final static int NUM = 20;
+
+    @Result char[][] outArray = new char[NUM][MAXOUTSIZ];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < NUM; i++) {
+            for (int j = 0; j < outArray[i].length; j++) {
+                outArray[i][j] = (char) (i + j);
+            }
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            System.arraycopy(outArray[gid], 0, outArray[gid], gid % NUM, NUM);
+        });
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/CharArrayCopyDisjointTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,54 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests copying a char array where src and dest do not overlap.
+ */
+public class CharArrayCopyDisjointTest extends GraalKernelTester {
+
+    final static int MAXOUTSIZ = 100;
+    final static int NUM = 20;
+
+    @Result char[][] outArray = new char[NUM][MAXOUTSIZ];
+    char[] inArray = new char[NUM + MAXOUTSIZ];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < inArray.length; i++) {
+            inArray[i] = (char) i;
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            System.arraycopy(inArray, gid, outArray[gid], 0, MAXOUTSIZ);
+        });
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/IntArrayCopyConjointTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests copying a int array where src and dest overlap.
+ */
+public class IntArrayCopyConjointTest extends GraalKernelTester {
+
+    final static int MAXOUTSIZ = 100;
+    final static int NUM = 20;
+
+    @Result int[][] outArray = new int[NUM][MAXOUTSIZ];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < NUM; i++) {
+            for (int j = 0; j < outArray[i].length; j++) {
+                outArray[i][j] = i + j;
+            }
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            System.arraycopy(outArray[gid], 0, outArray[gid], gid % NUM, NUM);
+        });
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/IntArrayCopyDisjointTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,54 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests copying a int array where src and dest do not overlap.
+ */
+public class IntArrayCopyDisjointTest extends GraalKernelTester {
+
+    final static int MAXOUTSIZ = 100;
+    final static int NUM = 20;
+
+    @Result int[][] outArray = new int[NUM][MAXOUTSIZ];
+    int[] inArray = new int[NUM + MAXOUTSIZ];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < inArray.length; i++) {
+            inArray[i] = i;
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            System.arraycopy(inArray, gid, outArray[gid], 0, MAXOUTSIZ);
+        });
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/LongArrayCopyConjointTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests copying a long array where src and dest overlap.
+ */
+public class LongArrayCopyConjointTest extends GraalKernelTester {
+
+    final static int MAXOUTSIZ = 100;
+    final static int NUM = 20;
+
+    @Result long[][] outArray = new long[NUM][MAXOUTSIZ];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < NUM; i++) {
+            for (int j = 0; j < outArray[i].length; j++) {
+                outArray[i][j] = i + j;
+            }
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            System.arraycopy(outArray[gid], 0, outArray[gid], gid % NUM, NUM);
+        });
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/LongArrayCopyDisjointTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,54 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests copying a long array where src and dest do not overlap.
+ */
+public class LongArrayCopyDisjointTest extends GraalKernelTester {
+
+    final static int MAXOUTSIZ = 100;
+    final static int NUM = 20;
+
+    @Result long[][] outArray = new long[NUM][MAXOUTSIZ];
+    long[] inArray = new long[NUM + MAXOUTSIZ];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < inArray.length; i++) {
+            inArray[i] = i;
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            System.arraycopy(inArray, gid, outArray[gid], 0, MAXOUTSIZ);
+        });
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NewStringEqualsTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NewStringEqualsTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -52,6 +52,12 @@
         setupArrays();
         String base = "ABCDEFGHIJ";
 
+        // Resolving StringIndexOutOfBoundsException causes compilation of the
+        // lambda to fail as. Combined with use of InlineEverything and RemoveNeverExecutedCode
+        // the inlining budget is blown before String.equals can be inlined leaving
+        // a DirectCallTargetNode in the graph which cannot be lowered by HSAIL.
+        new StringIndexOutOfBoundsException().fillInStackTrace();
+
         dispatchLambdaKernel(NUM, (gid) -> {
             outArray[gid] = new String(chars, 0, 10 + (gid % 3)).equals(base);
         });
@@ -63,8 +69,7 @@
         return (canHandleObjectAllocation());
     }
 
-    // NYI emitForeignCall charAlignedDisjointArraycopy
-    @Ignore
+    @Ignore("see comment in runTest")
     @Test
     public void test() {
         try (DebugConfigScope s = disableIntercept()) {
@@ -72,7 +77,7 @@
         }
     }
 
-    @Ignore
+    @Ignore("see comment in runTest")
     @Test
     public void testUsingLambdaMethod() {
         try (DebugConfigScope s = disableIntercept()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ObjArrayCopyConjointTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests {@link System#arraycopy} for object arrays where dest and src type are same, and overlap.
+ */
+public class ObjArrayCopyConjointTest extends GraalKernelTester {
+
+    final static int MAXOUTSIZ = 100;
+    final static int NUM = 20;
+
+    @Result String[][] outArray = new String[NUM][MAXOUTSIZ];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < NUM; i++) {
+            for (int j = 0; j < outArray[i].length; j++) {
+                outArray[i][j] = Integer.toString(i * 100 + j);
+            }
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            System.arraycopy(outArray[gid], 0, outArray[gid], gid % NUM, NUM);
+        });
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ObjArrayCopyDisjointNonExactTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests {@link System#arraycopy} for object arrays where dest is a superclass of src.
+ */
+public class ObjArrayCopyDisjointNonExactTest extends GraalKernelTester {
+
+    final static int MAXOUTSIZ = 100;
+    final static int NUM = 20;
+
+    @Result Object[][] outArray = new Object[NUM][MAXOUTSIZ];
+    String[] inArray = new String[NUM + MAXOUTSIZ];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < inArray.length; i++) {
+            inArray[i] = Integer.toString(i * 1111);
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            System.arraycopy(inArray, gid, outArray[gid], 0, MAXOUTSIZ);
+        });
+    }
+
+    // this fails because we do not have a pure java snippet for this case
+    // see ArrayCopySnippets.arrayCopy(Object, int, Object, int, int)
+    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ObjArrayCopyDisjointTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,54 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests {@link System#arraycopy} for object arrays where dest and src type are same, no overlap.
+ */
+public class ObjArrayCopyDisjointTest extends GraalKernelTester {
+
+    final static int MAXOUTSIZ = 100;
+    final static int NUM = 20;
+
+    @Result String[][] outArray = new String[NUM][MAXOUTSIZ];
+    String[] inArray = new String[NUM + MAXOUTSIZ];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < inArray.length; i++) {
+            inArray[i] = Integer.toString(i * 1111);
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            System.arraycopy(inArray, gid, outArray[gid], 0, MAXOUTSIZ);
+        });
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ReduceMaxTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,101 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.runtime;
+import com.oracle.graal.hotspot.HotSpotVMConfig;
+import static org.junit.Assert.*;
+import org.junit.*;
+
+import java.util.*;
+import java.util.stream.IntStream;
+
+public class ReduceMaxTest {
+    // The length of the input array
+    static int jobSize = 1027 * 1023 * 13;
+    static int loops = 1;
+
+    // The source array
+    int bigArray[] = null;
+
+    // result for baseline single threaded stream
+    int resultStream = 0;
+    // result for parallel CPU and offloaded streams
+    int resultOffload = 0;
+
+    int evaluate(boolean doParallelStream) {
+        int result = 0;
+        for (int i = 0; i < loops; i++) {
+            IntStream s = Arrays.stream(bigArray);
+            if (doParallelStream == true) {
+                OptionalInt resultParallel = s.parallel().reduce(Integer::max);
+                result = resultParallel.getAsInt();
+            } else {
+                result = s.reduce(Integer::max).getAsInt();
+            }
+        }
+        return result;
+    }
+
+    int evaluateWithIdentity(boolean doParallelStream) {
+        int result = 0;
+        for (int i = 0; i < loops; i++) {
+            IntStream s = Arrays.stream(bigArray);
+            if (doParallelStream == true) {
+                result = s.parallel().reduce(0, Integer::max);
+            } else {
+                result = s.reduce(0, Integer::max);
+            }
+        }
+        return result;
+    }
+
+    @Test
+    public void testReduce() {
+        // Handmade reduce does not support +UseCompressedOops
+        HotSpotVMConfig config = runtime().getConfig();
+        if (config.useCompressedOops == true || config.useHSAILDeoptimization == true) {
+            return;
+        }
+
+        bigArray = new int[jobSize];
+        for (int i = 0; i < jobSize; i++) {
+            // bigArray[i] = i + 1;
+            bigArray[i] = -1024 + i + 1;
+        }
+
+        // Get non parallel baseline
+        resultStream = evaluate(false);
+
+        // Get OptionalInt version kernel
+        resultOffload = evaluate(true);
+        assertTrue(resultStream == resultOffload);
+
+        // Do identity version kernel
+        // Get non parallel baseline
+        resultStream = evaluateWithIdentity(false);
+
+        resultOffload = evaluateWithIdentity(true);
+        assertTrue(resultStream == resultOffload);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ReduceMinTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,100 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.runtime;
+import com.oracle.graal.hotspot.HotSpotVMConfig;
+import static org.junit.Assert.*;
+import org.junit.*;
+
+import java.util.*;
+import java.util.stream.IntStream;
+
+public class ReduceMinTest {
+    // The length of the input array
+    static int jobSize = 1027 * 1023 * 13;
+    static int loops = 1;
+
+    // The input array to the kernel
+    int bigArray[] = null;
+
+    // result for baseline single threaded stream
+    int resultStream = 0;
+    // result for parallel CPU and offloaded streams
+    int resultOffload = 0;
+
+    int evaluate(boolean doParallelStream) {
+        int result = 0;
+        for (int i = 0; i < loops; i++) {
+            IntStream s = Arrays.stream(bigArray);
+            if (doParallelStream == true) {
+                OptionalInt resultParallel = s.parallel().reduce(Integer::min);
+                result = resultParallel.getAsInt();
+            } else {
+                result = s.reduce(Integer::min).getAsInt();
+            }
+        }
+        return result;
+    }
+
+    int evaluateWithIdentity(boolean doParallelStream) {
+        int result = 0;
+        for (int i = 0; i < loops; i++) {
+            IntStream s = Arrays.stream(bigArray);
+            if (doParallelStream == true) {
+                result = s.parallel().reduce(0, Integer::min);
+            } else {
+                result = s.reduce(0, Integer::min);
+            }
+        }
+        return result;
+    }
+
+    @Test
+    public void testReduce() {
+        // Handmade reduce does not support +UseCompressedOops
+        HotSpotVMConfig config = runtime().getConfig();
+        if (config.useCompressedOops == true || config.useHSAILDeoptimization == true) {
+            return;
+        }
+
+        bigArray = new int[jobSize];
+        for (int i = 0; i < jobSize; i++) {
+            bigArray[i] = -1024 + i + 1;
+        }
+
+        // Get non parallel baseline
+        resultStream = evaluate(false);
+
+        // Get OptionalInt version kernel
+        resultOffload = evaluate(true);
+        assertTrue(resultStream == resultOffload);
+
+        // Do identity version kernel
+        // Get non parallel baseline
+        resultStream = evaluateWithIdentity(false);
+
+        resultOffload = evaluateWithIdentity(true);
+        assertTrue(resultStream == resultOffload);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ReduceSumTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,98 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+//import com.oracle.graal.compiler.common.GraalInternalError;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.runtime;
+import com.oracle.graal.hotspot.HotSpotVMConfig;
+import org.junit.*;
+
+import java.util.*;
+import java.util.stream.IntStream;
+
+public class ReduceSumTest {
+    // The length of the input array
+    static int jobSize = 1027 * 1023 * 13;
+    static int loops = 1;
+
+    // The array to be summed
+    int bigArray[] = null;
+
+    // sum for baseline single threaded stream
+    int sumStream = 0;
+    // sum for parallel CPU and offloaded streams
+    int sumOffload = 0;
+
+    int evaluate(boolean doParallelStream) {
+        int sum = 0;
+        for (int i = 0; i < loops; i++) {
+            IntStream s = Arrays.stream(bigArray);
+            if (doParallelStream == true) {
+                OptionalInt resultParallel = s.parallel().reduce(Integer::sum);
+                sum = resultParallel.getAsInt();
+            } else {
+                OptionalInt resultStream = s.reduce(Integer::sum);
+                sum = resultStream.getAsInt();
+            }
+        }
+        return sum;
+    }
+
+    int evaluateWithIdentity(boolean doParallelStream) {
+        int sum = 0;
+        for (int i = 0; i < loops; i++) {
+            IntStream s = Arrays.stream(bigArray);
+            if (doParallelStream == true) {
+                sum = s.parallel().reduce(0, Integer::sum);
+            } else {
+                sum = s.reduce(0, Integer::sum);
+            }
+        }
+        return sum;
+    }
+
+    @Test
+    public void testReduce() {
+        // Handmade reduce does not support +UseCompressedOops
+        HotSpotVMConfig config = runtime().getConfig();
+        if (config.useCompressedOops == true || config.useHSAILDeoptimization == true) {
+            return;
+        }
+
+        bigArray = new int[jobSize];
+        for (int i = 0; i < jobSize; i++) {
+            bigArray[i] = -1024 + i + 1;
+        }
+
+        // Get non parallel baseline
+        sumStream = evaluate(false);
+
+        // Get OptionalInt version kernel
+        sumOffload = evaluate(true);
+        assert sumStream == sumOffload : "Offload sum is wrong, stream:" + sumStream + " != offload:" + sumOffload;
+
+        // Get identity version kernel
+        sumOffload = evaluateWithIdentity(true);
+        assert sumStream == sumOffload : "Offload sum is wrong, stream:" + sumStream + " != offload:" + sumOffload;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/StringBuilderTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,57 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests creating a new String using StringBuilder (relies on {@link System#arraycopy}).
+ */
+public class StringBuilderTest extends GraalKernelTester {
+
+    final static int NUM = 20;
+    StringBuilder[] builders = new StringBuilder[NUM];
+    @Result String[] resultString = new String[NUM];
+
+    @Override
+    public void runTest() {
+        for (int i = 0; i < NUM; i++) {
+            builders[i] = new StringBuilder().append(i).append("abc");
+        }
+        dispatchLambdaKernel(NUM, (gid) -> {
+            resultString[gid] = builders[gid].append(gid * 1234).toString();
+        });
+    }
+
+    @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canHandleObjectAllocation());
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/StringSubsequenceTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests creating a new {@link CharSequence} using {@link String#subSequence(int, int)}.
+ */
+public class StringSubsequenceTest extends GraalKernelTester {
+
+    final static int NUM = 50;
+    String inputString;
+    @Result CharSequence[] resultSequence = new String[NUM];
+
+    @Override
+    public void runTest() {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < NUM + 10; i++) {
+            builder.append(i);
+        }
+        inputString = builder.toString();
+        dispatchLambdaKernel(NUM, (gid) -> {
+            resultSequence[gid] = inputString.subSequence(gid, gid + 10);
+        });
+
+        // for (int i = 0; i < NUM; i++) {
+        // System.out.println(resultSequence[i]);
+        // }
+    }
+
+    @Ignore("emitDirectCall unimplemented")
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/StringSubstringTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+import org.junit.*;
+
+/**
+ * Tests creating a new String using {@link String#substring(int, int)}.
+ */
+public class StringSubstringTest extends GraalKernelTester {
+
+    final static int NUM = 50;
+    String inputString;
+    @Result String[] resultString = new String[NUM];
+
+    @Override
+    public void runTest() {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < NUM + 10; i++) {
+            builder.append(i);
+        }
+        inputString = builder.toString();
+        dispatchLambdaKernel(NUM, (gid) -> {
+            resultString[gid] = inputString.substring(gid, gid + 10);
+        });
+    }
+
+    @Ignore("emitDirectCall unimplemented")
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/CompileAndDispatch.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/CompileAndDispatch.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,4 +32,12 @@
     Object createKernel(Class<?> consumerClass);
 
     boolean dispatchKernel(Object kernel, int jobSize, Object[] args);
+
+    Object createKernelFromHsailString(String code, String methodName);
+
+    String getIntegerReduceIntrinsic(String reducerName);
+
+    Integer offloadIntReduceImpl(Object kernel, int identity, int[] streamSource);
+
+    String getIntReduceTargetName(Class<?> opClass);
 }
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Mon Jun 30 12:02:19 2014 +0200
@@ -81,7 +81,7 @@
 
     @Override
     public Variable emitMove(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         emitMove(result, input);
         return result;
     }
@@ -149,7 +149,9 @@
                 }
             }
         }
-        return new HSAILAddressValue(target().wordKind, baseRegister, finalDisp);
+
+        LIRKind resultKind = getAddressKind(base, displacement, index);
+        return new HSAILAddressValue(resultKind, baseRegister, finalDisp);
     }
 
     @Override
@@ -184,7 +186,7 @@
                     double trueDestinationProbability) {
         // We don't have to worry about mirroring the condition on HSAIL.
         Condition finalCondition = cond;
-        Variable result = newVariable(left.getKind());
+        Variable result = newVariable(left.getLIRKind());
         Kind kind = left.getKind().getStackKind();
         switch (kind) {
             case Int:
@@ -209,14 +211,14 @@
     @Override
     public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
         Variable result = emitAnd(left, right);
-        Variable dummyResult = newVariable(left.getKind());
+        Variable dummyResult = newVariable(left.getLIRKind());
         append(new CompareBranchOp(mapKindToCompareOp(left.getKind()), Condition.EQ, result, Constant.forInt(0), dummyResult, dummyResult, trueDestination, falseDestination, false));
     }
 
     @Override
     public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
         Condition finalCondition = cond;
-        Variable result = newVariable(trueValue.getKind());
+        Variable result = newVariable(trueValue.getLIRKind());
         Kind kind = left.getKind().getStackKind();
         switch (kind) {
             case Int:
@@ -247,7 +249,7 @@
      */
     @Override
     public Variable emitNegate(Value input) {
-        Variable result = newVariable(input.getKind());
+        Variable result = newVariable(input.getLIRKind());
         switch (input.getKind()) {
             case Int:
                 // Note: The Int case also handles the negation of shorts, bytes, and chars because
@@ -278,7 +280,7 @@
      */
     @Override
     public Variable emitNot(Value input) {
-        Variable result = newVariable(input.getKind());
+        Variable result = newVariable(input.getLIRKind());
         switch (input.getKind()) {
             case Int:
                 // Note: The Int case also covers other primitive integral types smaller than an int
@@ -296,7 +298,7 @@
     }
 
     public Variable emitTestAddressAdd(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(IADD, result, a, loadNonConst(b)));
@@ -321,7 +323,7 @@
 
     @Override
     public Variable emitAdd(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(IADD, result, a, loadNonConst(b)));
@@ -346,7 +348,7 @@
 
     @Override
     public Variable emitSub(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(ISUB, result, a, loadNonConst(b)));
@@ -368,7 +370,7 @@
 
     @Override
     public Variable emitMul(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(IMUL, result, a, loadNonConst(b)));
@@ -389,7 +391,7 @@
     }
 
     public Variable emitUMul(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(LUMUL, result, a, loadNonConst(b)));
@@ -415,7 +417,7 @@
 
     @Override
     public Value emitDiv(Value a, Value b, LIRFrameState state) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(IDIV, result, a, loadNonConst(b)));
@@ -438,7 +440,7 @@
 
     @Override
     public Value emitRem(Value a, Value b, LIRFrameState state) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(IREM, result, a, loadNonConst(b)));
@@ -470,7 +472,7 @@
 
     @Override
     public Variable emitAnd(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(IAND, result, a, loadNonConst(b)));
@@ -486,7 +488,7 @@
 
     @Override
     public Variable emitOr(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(IOR, result, a, loadNonConst(b)));
@@ -502,7 +504,7 @@
 
     @Override
     public Variable emitXor(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(IXOR, result, a, loadNonConst(b)));
@@ -525,7 +527,7 @@
      */
     @Override
     public Variable emitShl(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 // Note: The Int case also covers the shifting of bytes, shorts and chars because
@@ -550,7 +552,7 @@
      */
     @Override
     public Variable emitShr(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 // Note: The Int case also covers the shifting of bytes, shorts and chars because
@@ -575,7 +577,7 @@
      */
     @Override
     public Variable emitUShr(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new ShiftOp(IUSHR, result, a, b));
@@ -623,24 +625,24 @@
             case D2I:
             case F2I:
                 to = "s32";
-                result = newVariable(Kind.Int);
+                result = newVariable(LIRKind.value(Kind.Int));
                 break;
             case D2L:
             case F2L:
                 to = "s64";
-                result = newVariable(Kind.Long);
+                result = newVariable(LIRKind.value(Kind.Long));
                 break;
             case F2D:
             case I2D:
             case L2D:
                 to = "f64";
-                result = newVariable(Kind.Double);
+                result = newVariable(LIRKind.value(Kind.Double));
                 break;
             case D2F:
             case I2F:
             case L2F:
                 to = "f32";
-                result = newVariable(Kind.Float);
+                result = newVariable(LIRKind.value(Kind.Float));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -653,7 +655,7 @@
     @Override
     public Value emitNarrow(Value inputVal, int bits) {
         Variable input = load(inputVal);
-        Variable result = newVariable(bits > 32 ? Kind.Long : Kind.Int);
+        Variable result = newVariable(LIRKind.value(bits > 32 ? Kind.Long : Kind.Int));
         append(new ConvertOp(result, input, "s" + bits, input.getKind() == Kind.Long ? "s64" : "s32"));
         return result;
     }
@@ -661,7 +663,7 @@
     @Override
     public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
         Variable input = load(inputVal);
-        Variable result = newVariable(toBits > 32 ? Kind.Long : Kind.Int);
+        Variable result = newVariable(LIRKind.value(toBits > 32 ? Kind.Long : Kind.Int));
         append(new ConvertOp(result, input, "s" + toBits, "s" + fromBits));
         return result;
     }
@@ -669,13 +671,13 @@
     @Override
     public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
         Variable input = load(inputVal);
-        Variable result = newVariable(toBits > 32 ? Kind.Long : Kind.Int);
+        Variable result = newVariable(LIRKind.value(toBits > 32 ? Kind.Long : Kind.Int));
         append(new ConvertOp(result, input, "u" + toBits, "u" + fromBits));
         return result;
     }
 
     @Override
-    public Value emitReinterpret(PlatformKind to, Value inputVal) {
+    public Value emitReinterpret(LIRKind to, Value inputVal) {
         Variable result = newVariable(to);
         emitMove(result, inputVal);
         return result;
@@ -693,21 +695,23 @@
     }
 
     @Override
-    public void emitBitCount(Variable result, Value value) {
+    public Value emitBitCount(Value value) {
+        Variable result = newVariable(LIRKind.value(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
             append(new HSAILBitManipulationOp(IPOPCNT, result, value));
         } else {
             append(new HSAILBitManipulationOp(LPOPCNT, result, value));
         }
+        return result;
     }
 
     @Override
-    public void emitBitScanForward(Variable result, Value value) {
+    public Value emitBitScanForward(Value value) {
         throw GraalInternalError.unimplemented();
     }
 
     @Override
-    public void emitBitScanReverse(Variable result, Value value) {
+    public Value emitBitScanReverse(Value value) {
         throw GraalInternalError.unimplemented();
     }
 
@@ -719,7 +723,7 @@
      */
     @Override
     public Value emitMathAbs(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new Op1Reg(ABS, result, input));
         return result;
     }
@@ -731,7 +735,7 @@
      * @return Value representing the result of the operation
      */
     public Value emitMathCeil(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new Op1Reg(CEIL, result, input));
         return result;
     }
@@ -743,7 +747,7 @@
      * @return Value representing the result of the operation
      */
     public Value emitMathFloor(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new Op1Reg(FLOOR, result, input));
         return result;
     }
@@ -755,7 +759,7 @@
      * @return Value representing the result of the operation
      */
     public Value emitMathRint(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new Op1Reg(RINT, result, input));
         return result;
     }
@@ -768,7 +772,7 @@
      */
     @Override
     public Value emitMathSqrt(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new Op1Reg(SQRT, result, input));
         return result;
     }
@@ -794,12 +798,12 @@
     }
 
     @Override
-    public void emitByteSwap(Variable result, Value input) {
+    public Value emitByteSwap(Value input) {
         throw GraalInternalError.unimplemented();
     }
 
     @Override
-    public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) {
+    public Value emitArrayEquals(Kind kind, Value array1, Value array2, Value length) {
         // TODO Auto-generated method stub
         throw GraalInternalError.unimplemented();
     }
@@ -808,7 +812,7 @@
     public void emitReturn(Value input) {
         AllocatableValue operand = Value.ILLEGAL;
         if (input != null) {
-            operand = resultOperandFor(input.getKind());
+            operand = resultOperandFor(input.getLIRKind());
             emitMove(operand, input);
         }
         append(new ReturnOp(operand));
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Mon Jun 30 12:02:19 2014 +0200
@@ -47,12 +47,12 @@
 
     @Override
     protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        throw GraalInternalError.unimplemented();
+        throw GraalInternalError.unimplemented(MetaUtil.format("direct call to %H.%n(%p)", callTarget.target()));
     }
 
     @Override
     protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        throw GraalInternalError.unimplemented();
+        throw GraalInternalError.unimplemented(MetaUtil.format("direct call to %H.%n(%p)", callTarget.target()));
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,7 +24,6 @@
 package com.oracle.graal.compiler.ptx;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.api.meta.Value.*;
 import static com.oracle.graal.lir.ptx.PTXArithmetic.*;
 import static com.oracle.graal.lir.ptx.PTXBitManipulationOp.IntrinsicOpcode.*;
 import static com.oracle.graal.lir.ptx.PTXCompare.*;
@@ -112,24 +111,9 @@
         }
     }
 
-    protected static AllocatableValue toParamKind(AllocatableValue value) {
-        if (value.getKind().getStackKind() != value.getKind()) {
-            // We only have stack-kinds in the LIR, so convert the operand kind for values from the
-            // calling convention.
-            if (isRegister(value)) {
-                return asRegister(value).asValue(value.getKind().getStackKind());
-            } else if (isStackSlot(value)) {
-                return StackSlot.get(value.getKind().getStackKind(), asStackSlot(value).getRawOffset(), asStackSlot(value).getRawAddFrameSize());
-            } else {
-                throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-        return value;
-    }
-
     public Variable emitWarpParam(Kind kind, Warp annotation) {
-        Variable result = newVariable(kind);
-        Variable tid = newVariable(Kind.Char);
+        Variable result = newVariable(target().getLIRKind(kind));
+        Variable tid = newVariable(LIRKind.value(Kind.Char));
 
         switch (annotation.dimension()) {
             case X:
@@ -149,7 +133,7 @@
 
     @Override
     public Variable emitMove(Value input) {
-        Variable result = newVariable(input.getKind());
+        Variable result = newVariable(input.getLIRKind());
         emitMove(result, input);
         return result;
     }
@@ -208,14 +192,15 @@
                 if (baseRegister.equals(Value.ILLEGAL)) {
                     baseRegister = asAllocatable(indexRegister);
                 } else {
-                    Variable longBaseRegister = newVariable(Kind.Long);
+                    Variable longBaseRegister = newVariable(LIRKind.value(Kind.Long));
                     emitMove(longBaseRegister, baseRegister);
                     baseRegister = emitAdd(longBaseRegister, indexRegister);
                 }
             }
         }
 
-        return new PTXAddressValue(target().wordKind, baseRegister, finalDisp);
+        LIRKind resultKind = getAddressKind(base, displacement, index);
+        return new PTXAddressValue(resultKind, baseRegister, finalDisp);
     }
 
     private PTXAddressValue asAddress(Value address) {
@@ -229,18 +214,18 @@
     }
 
     @Override
-    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
+    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
         PTXAddressValue loadAddress = asAddress(address);
         Variable result = newVariable(kind);
-        append(new LoadOp((Kind) kind, result, loadAddress, state));
+        append(new LoadOp((Kind) kind.getPlatformKind(), result, loadAddress, state));
         return result;
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
+    public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) {
         PTXAddressValue storeAddress = asAddress(address);
         Variable input = load(inputVal);
-        append(new StoreOp((Kind) kind, storeAddress, input, state));
+        append(new StoreOp((Kind) kind.getPlatformKind(), storeAddress, input, state));
     }
 
     @Override
@@ -301,7 +286,7 @@
 
         emitCompare(finalCondition, left, right);
 
-        Variable result = newVariable(trueValue.getKind());
+        Variable result = newVariable(trueValue.getLIRKind());
         switch (left.getKind().getStackKind()) {
             case Int:
             case Long:
@@ -366,7 +351,7 @@
     @Override
     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
         emitIntegerTest(left, right);
-        Variable result = newVariable(trueValue.getKind());
+        Variable result = newVariable(trueValue.getLIRKind());
         append(new CondMoveOp(result, Condition.EQ, load(trueValue), loadNonConst(falseValue), nextPredRegNum));
         nextPredRegNum++;
 
@@ -385,7 +370,7 @@
 
     @Override
     public Variable emitNegate(Value input) {
-        Variable result = newVariable(input.getKind());
+        Variable result = newVariable(input.getLIRKind());
         switch (input.getKind()) {
             case Int:
                 append(new Op1Stack(INEG, result, input));
@@ -404,7 +389,7 @@
 
     @Override
     public Variable emitNot(Value input) {
-        Variable result = newVariable(input.getKind());
+        Variable result = newVariable(input.getLIRKind());
         switch (input.getKind()) {
             case Int:
                 append(new Op1Stack(INOT, result, input));
@@ -420,7 +405,7 @@
 
     @Override
     public Variable emitAdd(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Stack(IADD, result, a, loadNonConst(b)));
@@ -442,7 +427,7 @@
 
     @Override
     public Variable emitSub(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Stack(ISUB, result, a, loadNonConst(b)));
@@ -464,7 +449,7 @@
 
     @Override
     public Variable emitMul(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(IMUL, result, a, loadNonConst(b)));
@@ -496,7 +481,7 @@
 
     @Override
     public Value emitDiv(Value a, Value b, LIRFrameState state) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(IDIV, result, a, loadNonConst(b)));
@@ -518,7 +503,7 @@
 
     @Override
     public Value emitRem(Value a, Value b, LIRFrameState state) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Reg(IREM, result, a, loadNonConst(b)));
@@ -544,7 +529,7 @@
 
     @Override
     public Variable emitAnd(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Stack(IAND, result, a, loadNonConst(b)));
@@ -560,7 +545,7 @@
 
     @Override
     public Variable emitOr(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Stack(IOR, result, a, loadNonConst(b)));
@@ -576,7 +561,7 @@
 
     @Override
     public Variable emitXor(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Stack(IXOR, result, a, loadNonConst(b)));
@@ -592,7 +577,7 @@
 
     @Override
     public Variable emitShl(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Stack(ISHL, result, a, loadNonConst(b)));
@@ -608,7 +593,7 @@
 
     @Override
     public Variable emitShr(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new Op2Stack(ISHR, result, a, loadNonConst(b)));
@@ -624,7 +609,7 @@
 
     @Override
     public Variable emitUShr(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind()) {
             case Int:
                 append(new ShiftOp(IUSHR, result, a, b));
@@ -640,7 +625,7 @@
 
     public Variable emitConvertOp(Kind from, Kind to, Value inputVal) {
         Variable input = load(inputVal);
-        Variable result = newVariable(to);
+        Variable result = newVariable(LIRKind.value(to));
         append(new ConvertOp(result, input, to, from));
         return result;
     }
@@ -723,17 +708,17 @@
             return inputVal;
         } else if (fromBits > 32) {
             assert inputVal.getKind() == Kind.Long;
-            Variable result = newVariable(Kind.Long);
+            Variable result = newVariable(LIRKind.value(Kind.Long));
             long mask = IntegerStamp.defaultMask(fromBits);
             append(new Op2Stack(LAND, result, inputVal, Constant.forLong(mask)));
             return result;
         } else {
             assert inputVal.getKind() == Kind.Int;
-            Variable result = newVariable(Kind.Int);
+            Variable result = newVariable(LIRKind.value(Kind.Int));
             int mask = (int) IntegerStamp.defaultMask(fromBits);
             append(new Op2Stack(IAND, result, inputVal, Constant.forInt(mask)));
             if (toBits > 32) {
-                Variable longResult = newVariable(Kind.Long);
+                Variable longResult = newVariable(LIRKind.value(Kind.Long));
                 emitMove(longResult, result);
                 return longResult;
             } else {
@@ -743,7 +728,7 @@
     }
 
     @Override
-    public Value emitReinterpret(PlatformKind to, Value inputVal) {
+    public Value emitReinterpret(LIRKind to, Value inputVal) {
         Variable result = newVariable(to);
         emitMove(result, inputVal);
         return result;
@@ -765,21 +750,23 @@
     }
 
     @Override
-    public void emitBitCount(Variable result, Value value) {
+    public Value emitBitCount(Value value) {
+        Variable result = newVariable(LIRKind.value(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
             append(new PTXBitManipulationOp(IPOPCNT, result, value));
         } else {
             append(new PTXBitManipulationOp(LPOPCNT, result, value));
         }
+        return result;
     }
 
     @Override
-    public void emitBitScanForward(Variable result, Value value) {
+    public Value emitBitScanForward(Value value) {
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitBitScanForward()");
     }
 
     @Override
-    public void emitBitScanReverse(Variable result, Value value) {
+    public Value emitBitScanReverse(Value value) {
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitBitScanReverse()");
     }
 
@@ -814,12 +801,12 @@
     }
 
     @Override
-    public void emitByteSwap(Variable result, Value input) {
+    public Value emitByteSwap(Value input) {
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitByteSwap()");
     }
 
     @Override
-    public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) {
+    public Value emitArrayEquals(Kind kind, Value array1, Value array2, Value length) {
         // TODO Auto-generated method stub
         throw GraalInternalError.unimplemented();
     }
@@ -827,7 +814,7 @@
     @Override
     public void emitReturn(Value input) {
         if (input != null) {
-            AllocatableValue operand = resultOperandFor(input.getKind());
+            AllocatableValue operand = resultOperandFor(input.getLIRKind());
             // Load the global memory address from return parameter
             Variable loadVar = emitLoadReturnAddress(operand.getKind(), operand, null);
             // Store input in global memory whose location is loadVar
@@ -843,7 +830,7 @@
     @Override
     public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
         boolean needsTemp = key.getKind() == Kind.Object;
-        append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL, nextPredRegNum++));
+        append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getLIRKind()) : Value.ILLEGAL, nextPredRegNum++));
     }
 
     @Override
@@ -851,7 +838,7 @@
         // Making a copy of the switch value is necessary because jump table destroys the input
         // value
         Variable tmp = emitMove(key);
-        append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(target().wordKind), nextPredRegNum++));
+        append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(LIRKind.value(target().wordKind)), nextPredRegNum++));
     }
 
     @Override
@@ -862,7 +849,7 @@
     public Variable emitLoadParam(Kind kind, Value address, LIRFrameState state) {
 
         PTXAddressValue loadAddress = asAddress(address);
-        Variable result = newVariable(kind);
+        Variable result = newVariable(target().getLIRKind(kind));
         append(new LoadParamOp(kind, result, loadAddress, state));
 
         return result;
@@ -873,13 +860,13 @@
         Variable result;
         switch (kind) {
             case Float:
-                result = newVariable(Kind.Int);
+                result = newVariable(LIRKind.value(Kind.Int));
                 break;
             case Double:
-                result = newVariable(Kind.Long);
+                result = newVariable(LIRKind.value(Kind.Long));
                 break;
             default:
-                result = newVariable(kind);
+                result = newVariable(target().getLIRKind(kind));
         }
         append(new LoadReturnAddrOp(kind, result, loadAddress, state));
 
@@ -893,10 +880,7 @@
     }
 
     @Override
-    public AllocatableValue resultOperandFor(Kind kind) {
-        if (kind == Kind.Void) {
-            return ILLEGAL;
-        }
+    public AllocatableValue resultOperandFor(LIRKind kind) {
         return (new Variable(kind, 0));
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon Jun 30 12:02:19 2014 +0200
@@ -90,7 +90,7 @@
 
     @Override
     public Variable emitMove(Value input) {
-        Variable result = newVariable(input.getKind());
+        Variable result = newVariable(input.getLIRKind());
         emitMove(result, input);
         return result;
     }
@@ -177,14 +177,15 @@
                 if (finalDisp == 0) {
                     // Nothing to do. Just use the base register.
                 } else {
-                    Variable longBaseRegister = newVariable(Kind.Long);
+                    Variable longBaseRegister = newVariable(LIRKind.derivedReference(Kind.Long));
                     emitMove(longBaseRegister, baseRegister);
                     baseRegister = emitAdd(longBaseRegister, Constant.forLong(finalDisp));
                 }
             }
         }
 
-        return new SPARCAddressValue(target().wordKind, baseRegister, indexRegister, displacementInt);
+        LIRKind resultKind = getAddressKind(base, displacement, index);
+        return new SPARCAddressValue(resultKind, baseRegister, indexRegister, displacementInt);
     }
 
     protected SPARCAddressValue asAddressValue(Value address) {
@@ -197,7 +198,7 @@
 
     @Override
     public Value emitAddress(StackSlot address) {
-        Variable result = newVariable(target().wordKind);
+        Variable result = newVariable(LIRKind.value(target().wordKind));
         append(new StackLoadAddressOp(result, address));
         return result;
     }
@@ -206,7 +207,7 @@
     public void emitReturn(Value input) {
         AllocatableValue operand = Value.ILLEGAL;
         if (input != null) {
-            operand = resultOperandFor(input.getKind());
+            operand = resultOperandFor(input.getLIRKind());
             emitMove(operand, input);
         }
         append(new ReturnOp(operand));
@@ -268,7 +269,7 @@
         boolean mirrored = emitCompare(left, right);
         Condition finalCondition = mirrored ? cond.mirror() : cond;
 
-        Variable result = newVariable(trueValue.getKind());
+        Variable result = newVariable(trueValue.getLIRKind());
         Kind kind = left.getKind().getStackKind();
         switch (kind) {
             case Int:
@@ -332,7 +333,7 @@
     @Override
     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
         emitIntegerTest(left, right);
-        Variable result = newVariable(trueValue.getKind());
+        Variable result = newVariable(trueValue.getLIRKind());
         Kind kind = left.getKind().getStackKind();
         append(new CondMoveOp(kind, result, Condition.EQ, load(trueValue), loadNonConst(falseValue)));
         return result;
@@ -352,7 +353,7 @@
     public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
         // a temp is needed for loading long and object constants
         boolean needsTemp = key.getKind() == Kind.Long || key.getKind() == Kind.Object;
-        append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL));
+        append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getLIRKind()) : Value.ILLEGAL));
     }
 
     @Override
@@ -360,88 +361,96 @@
         // Making a copy of the switch value is necessary because jump table destroys the input
         // value
         Variable tmp = emitMove(key);
-        append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(target().wordKind)));
+        append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(LIRKind.value(target().wordKind))));
     }
 
     @Override
-    public void emitBitCount(Variable result, Value operand) {
+    public Value emitBitCount(Value operand) {
+        Variable result = newVariable(LIRKind.value(Kind.Int));
         if (operand.getKind().getStackKind() == Kind.Int) {
             append(new SPARCBitManipulationOp(IPOPCNT, result, asAllocatable(operand), this));
         } else {
             append(new SPARCBitManipulationOp(LPOPCNT, result, asAllocatable(operand), this));
         }
+        return result;
     }
 
     @Override
-    public void emitBitScanForward(Variable result, Value operand) {
+    public Value emitBitScanForward(Value operand) {
+        Variable result = newVariable(LIRKind.value(Kind.Int));
         append(new SPARCBitManipulationOp(BSF, result, asAllocatable(operand), this));
+        return result;
     }
 
     @Override
-    public void emitBitScanReverse(Variable result, Value operand) {
+    public Value emitBitScanReverse(Value operand) {
+        Variable result = newVariable(LIRKind.value(Kind.Int));
         if (operand.getKind().getStackKind() == Kind.Int) {
             append(new SPARCBitManipulationOp(IBSR, result, asAllocatable(operand), this));
         } else {
             append(new SPARCBitManipulationOp(LBSR, result, asAllocatable(operand), this));
         }
+        return result;
     }
 
     @Override
     public Value emitMathAbs(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new BinaryRegConst(DAND, result, asAllocatable(input), Constant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL))));
         return result;
     }
 
     @Override
     public Value emitMathSqrt(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new SPARCMathIntrinsicOp(SQRT, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathLog(Value input, boolean base10) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new SPARCMathIntrinsicOp(LOG, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathCos(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new SPARCMathIntrinsicOp(COS, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathSin(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new SPARCMathIntrinsicOp(SIN, result, asAllocatable(input)));
         return result;
     }
 
     @Override
     public Value emitMathTan(Value input) {
-        Variable result = newVariable(input.getPlatformKind());
+        Variable result = newVariable(input.getLIRKind());
         append(new SPARCMathIntrinsicOp(TAN, result, asAllocatable(input)));
         return result;
     }
 
     @Override
-    public void emitByteSwap(Variable result, Value input) {
+    public Value emitByteSwap(Value input) {
+        Variable result = newVariable(input.getLIRKind());
         append(new SPARCByteSwapOp(result, input));
+        return result;
     }
 
     @Override
-    public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) {
+    public Value emitArrayEquals(Kind kind, Value array1, Value array2, Value length) {
         // TODO Auto-generated method stub
         throw GraalInternalError.unimplemented();
     }
 
     @Override
     public Value emitNegate(Value input) {
-        Variable result = newVariable(input.getKind());
+        Variable result = newVariable(input.getLIRKind());
         switch (input.getKind().getStackKind()) {
             case Long:
                 append(new Op1Stack(LNEG, result, input));
@@ -463,7 +472,7 @@
 
     @Override
     public Value emitNot(Value input) {
-        Variable result = newVariable(input.getKind());
+        Variable result = newVariable(input.getLIRKind());
         switch (input.getKind().getStackKind()) {
             case Int:
                 append(new Op1Stack(INOT, result, input));
@@ -502,7 +511,7 @@
             case IMUL:
             case LMUL:
                 if (NumUtil.isInt(b.asLong())) {
-                    Variable result = newVariable(a.getKind());
+                    Variable result = newVariable(a.getLIRKind());
                     append(new BinaryRegConst(op, result, a, b));
                     return result;
                 }
@@ -513,7 +522,7 @@
     }
 
     private Variable emitBinaryVar(SPARCArithmetic op, boolean commutative, AllocatableValue a, AllocatableValue b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         if (commutative) {
             append(new BinaryCommutative(op, result, a, b));
         } else {
@@ -540,7 +549,7 @@
 
     @Override
     public Variable emitSub(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind().getStackKind()) {
             case Int:
                 append(new Op2Stack(ISUB, result, a, loadNonConst(b)));
@@ -562,7 +571,7 @@
 
     @Override
     public Variable emitMul(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind().getStackKind()) {
             case Int:
                 append(new BinaryRegReg(IMUL, result, a, loadNonConst(b)));
@@ -594,13 +603,13 @@
 
     @Override
     public Value emitDiv(Value a, Value b, LIRFrameState state) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind().getStackKind()) {
             case Int:
                 append(new BinaryRegReg(IDIV, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new BinaryRegReg(LDIV, result, a, loadNonConst(b), state));
+                append(new BinaryRegReg(LDIV, result, a, loadNonConst(b)));
                 break;
             case Float:
                 append(new Op2Stack(FDIV, result, a, loadNonConst(b)));
@@ -616,7 +625,7 @@
 
     @Override
     public Value emitRem(Value a, Value b, LIRFrameState state) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         Variable q = null;
         switch (a.getKind().getStackKind()) {
             case Int:
@@ -626,7 +635,7 @@
                 append(new RemOp(LREM, result, a, loadNonConst(b), state, this));
                 break;
             case Float:
-                q = newVariable(Kind.Float);
+                q = newVariable(LIRKind.value(Kind.Float));
                 append(new Op2Stack(FDIV, q, a, b));
                 append(new Unary2Op(F2I, q, q));
                 append(new Unary2Op(I2F, q, q));
@@ -634,7 +643,7 @@
                 append(new Op2Stack(FSUB, result, a, q));
                 break;
             case Double:
-                q = newVariable(Kind.Double);
+                q = newVariable(LIRKind.value(Kind.Double));
                 append(new Op2Stack(DDIV, q, a, b));
                 append(new Unary2Op(D2L, q, q));
                 append(new Unary2Op(L2D, q, q));
@@ -679,7 +688,7 @@
 
     @Override
     public Variable emitAnd(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind().getStackKind()) {
             case Int:
                 append(new Op2Stack(IAND, result, a, loadNonConst(b)));
@@ -696,7 +705,7 @@
 
     @Override
     public Variable emitOr(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind().getStackKind()) {
             case Int:
                 append(new Op2Stack(IOR, result, a, loadNonConst(b)));
@@ -712,7 +721,7 @@
 
     @Override
     public Variable emitXor(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getLIRKind());
         switch (a.getKind().getStackKind()) {
             case Int:
                 append(new Op2Stack(IXOR, result, a, loadNonConst(b)));
@@ -727,7 +736,7 @@
     }
 
     private Variable emitShift(SPARCArithmetic op, Value a, Value b) {
-        Variable result = newVariable(a.getPlatformKind());
+        Variable result = newVariable(a.getLIRKind());
         AllocatableValue input = asAllocatable(a);
         if (isConstant(b)) {
             append(new BinaryRegConst(op, result, input, asConstant(b)));
@@ -773,13 +782,13 @@
         }
     }
 
-    private AllocatableValue emitConvertMove(PlatformKind kind, AllocatableValue input) {
+    private AllocatableValue emitConvertMove(LIRKind kind, AllocatableValue input) {
         Variable result = newVariable(kind);
         emitMove(result, input);
         return result;
     }
 
-    private AllocatableValue emitConvert2Op(PlatformKind kind, SPARCArithmetic op, AllocatableValue input) {
+    private AllocatableValue emitConvert2Op(LIRKind kind, SPARCArithmetic op, AllocatableValue input) {
         Variable result = newVariable(kind);
         append(new Unary2Op(op, result, input));
         return result;
@@ -793,14 +802,14 @@
         SPARCArithmetic conversionInstruction = null;
         switch (op) {
             case D2F:
-                return emitConvert2Op(Kind.Float, D2F, input);
+                return emitConvert2Op(LIRKind.value(Kind.Float), D2F, input);
             case D2I:
                 fromRegisterKind = Kind.Double;
                 toRegisterKind = Kind.Int;
                 conversionInstruction = D2I;
                 break;
             case F2L:
-                Variable v = newVariable(Kind.Double);
+                Variable v = newVariable(LIRKind.value(Kind.Double));
                 emitMove(v, input);
                 input = v;
             case D2L:
@@ -809,26 +818,26 @@
                 conversionInstruction = D2L;
                 break;
             case F2D:
-                return emitConvert2Op(Kind.Double, F2D, input);
+                return emitConvert2Op(LIRKind.value(Kind.Double), F2D, input);
             case F2I:
                 fromRegisterKind = Kind.Float;
                 toRegisterKind = Kind.Int;
                 conversionInstruction = F2I;
                 break;
             case I2D:
-                return emitConvert2Op(Kind.Double, L2D, emitConvert2Op(Kind.Long, I2L, input));
+                return emitConvert2Op(LIRKind.value(Kind.Double), I2D, input);
             case I2F:
-                return emitConvert2Op(Kind.Float, I2F, input);
+                return emitConvert2Op(LIRKind.value(Kind.Float), I2F, input);
             case L2D:
-                return emitConvert2Op(Kind.Double, L2D, input);
+                return emitConvert2Op(LIRKind.value(Kind.Double), L2D, input);
             case L2F:
-                return emitConvert2Op(Kind.Float, D2F, emitConvert2Op(Kind.Double, L2D, input));
+                return emitConvert2Op(LIRKind.value(Kind.Float), L2F, input);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
         if (fromRegisterKind != null) {
-            AllocatableValue var = newVariable(toRegisterKind);
-            emitMove(var, emitConvert2Op(fromRegisterKind, conversionInstruction, input));
+            AllocatableValue var = newVariable(LIRKind.value(toRegisterKind));
+            emitMove(var, emitConvert2Op(LIRKind.value(fromRegisterKind), conversionInstruction, input));
             return var;
         } else {
             throw GraalInternalError.shouldNotReachHere();
@@ -838,7 +847,7 @@
     @Override
     public Value emitNarrow(Value inputVal, int bits) {
         if (inputVal.getKind() == Kind.Long && bits <= 32) {
-            return emitConvert2Op(Kind.Int, L2I, asAllocatable(inputVal));
+            return emitConvert2Op(LIRKind.value(Kind.Int), L2I, asAllocatable(inputVal));
         } else {
             return inputVal;
         }
@@ -853,11 +862,11 @@
             // sign extend to 64 bits
             switch (fromBits) {
                 case 8:
-                    return emitConvert2Op(Kind.Long, B2L, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.value(Kind.Long), B2L, asAllocatable(inputVal));
                 case 16:
-                    return emitConvert2Op(Kind.Long, S2L, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.value(Kind.Long), S2L, asAllocatable(inputVal));
                 case 32:
-                    return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.value(Kind.Long), I2L, asAllocatable(inputVal));
                 default:
                     throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
             }
@@ -865,9 +874,9 @@
             // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
             switch (fromBits) {
                 case 8:
-                    return emitConvert2Op(Kind.Int, B2I, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.value(Kind.Int), B2I, asAllocatable(inputVal));
                 case 16:
-                    return emitConvert2Op(Kind.Int, S2I, asAllocatable(inputVal));
+                    return emitConvert2Op(LIRKind.value(Kind.Int), S2I, asAllocatable(inputVal));
                 case 32:
                     return inputVal;
                 default:
@@ -882,25 +891,25 @@
         if (fromBits == toBits) {
             return inputVal;
         } else if (fromBits > 32) {
-            assert inputVal.getKind() == Kind.Long : inputVal.getKind();
-            Variable result = newVariable(Kind.Long);
+            assert inputVal.getKind() == Kind.Long;
+            Variable result = newVariable(LIRKind.value(Kind.Long));
             long mask = IntegerStamp.defaultMask(fromBits);
             append(new BinaryRegConst(SPARCArithmetic.LAND, result, asAllocatable(inputVal), Constant.forLong(mask)));
             return result;
         } else {
             assert inputVal.getKind() == Kind.Int || inputVal.getKind() == Kind.Short || inputVal.getKind() == Kind.Byte : inputVal.getKind();
-            Variable result = newVariable(Kind.Int);
+            Variable result = newVariable(LIRKind.value(Kind.Int));
             int mask = (int) IntegerStamp.defaultMask(fromBits);
             Constant constant = Constant.forInt(mask);
             if (canInlineConstant(constant)) {
                 append(new BinaryRegConst(SPARCArithmetic.IAND, result, asAllocatable(inputVal), constant));
             } else {
-                Variable maskVar = newVariable(Kind.Int);
+                Variable maskVar = newVariable(LIRKind.value(Kind.Int));
                 emitMove(maskVar, constant);
                 append(new BinaryRegReg(IAND, result, maskVar, (inputVal)));
             }
             if (toBits > 32) {
-                Variable longResult = newVariable(Kind.Long);
+                Variable longResult = newVariable(LIRKind.value(Kind.Long));
                 emitMove(longResult, result);
                 return longResult;
             } else {
@@ -910,12 +919,12 @@
     }
 
     @Override
-    public AllocatableValue emitReinterpret(PlatformKind to, Value inputVal) {
+    public AllocatableValue emitReinterpret(LIRKind to, Value inputVal) {
         Kind from = inputVal.getKind();
         AllocatableValue input = asAllocatable(inputVal);
 
         // These cases require a move between CPU and FPU registers:
-        switch ((Kind) to) {
+        switch ((Kind) to.getPlatformKind()) {
             case Int:
                 switch (from) {
                     case Float:
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/AllocSpy.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/AllocSpy.java	Mon Jun 30 12:02:19 2014 +0200
@@ -39,11 +39,11 @@
  * trace is governed by the value of the "AllocSpy.ContextSize" system property (default is 5).
  * <p>
  * Using this facility requires using -javaagent on the command line. For example:
- * 
+ *
  * <pre>
  * mx --vm server unittest -javaagent:lib/java-allocation-instrumenter.jar -dsa -DAllocSpy.ContextSize=6 BC_iadd2
  * </pre>
- * 
+ *
  * @see #SampleBytes
  * @see #SampleInstances
  * @see #HistogramLimit
@@ -237,8 +237,8 @@
                     } else {
                         if (!excludeFrame(className)) {
                             sb.append("type=").append(desc);
-                            if (count != 1) {
-                                sb.append("[]");
+                            if (count != -1) {
+                                sb.append('[').append(count).append(']');
                             }
                             append(sb.append('\n'), e);
                         }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Mon Jun 30 12:02:19 2014 +0200
@@ -27,6 +27,7 @@
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
+import java.util.concurrent.*;
 import java.util.zip.*;
 
 import org.junit.*;
@@ -34,6 +35,8 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.CompilerThreadFactory.DebugConfigAccess;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
@@ -42,6 +45,7 @@
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.phases.verify.*;
+import com.oracle.graal.printer.*;
 import com.oracle.graal.runtime.*;
 import com.oracle.graal.test.*;
 
@@ -97,7 +101,15 @@
         String property = System.getProperty(CheckGraalInvariants.class.getName() + ".filters");
         String[] filters = property == null ? null : property.split(",");
 
-        List<String> errors = new ArrayList<>();
+        CompilerThreadFactory factory = new CompilerThreadFactory("CheckInvariantsThread", new DebugConfigAccess() {
+            public GraalDebugConfig getDebugConfig() {
+                return DebugEnvironment.initialize(System.out);
+            }
+        });
+        int availableProcessors = Runtime.getRuntime().availableProcessors();
+        ThreadPoolExecutor executor = new ThreadPoolExecutor(availableProcessors, availableProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
+
+        List<String> errors = Collections.synchronizedList(new ArrayList<>());
         for (String className : classNames) {
             try {
                 Class<?> c = Class.forName(className, false, CheckGraalInvariants.class.getClassLoader());
@@ -107,22 +119,24 @@
                     } else {
                         String methodName = className + "." + m.getName();
                         if (matches(filters, methodName)) {
-                            StructuredGraph graph = new StructuredGraph(metaAccess.lookupJavaMethod(m));
-                            try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT))) {
-                                graphBuilderSuite.apply(graph, context);
-                                checkGraph(context, graph);
-                            } catch (VerificationError e) {
-                                errors.add(e.getMessage());
-                            } catch (LinkageError e) {
-                                // suppress linkages errors resulting from eager resolution
-                            } catch (BailoutException e) {
-                                // Graal bail outs on certain patterns in Java bytecode (e.g.,
-                                // unbalanced monitors introduced by jacoco).
-                            } catch (Throwable e) {
-                                StringWriter sw = new StringWriter();
-                                e.printStackTrace(new PrintWriter(sw));
-                                errors.add(String.format("Error while checking %s:%n%s", methodName, sw));
-                            }
+                            executor.execute(() -> {
+                                StructuredGraph graph = new StructuredGraph(metaAccess.lookupJavaMethod(m));
+                                try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT))) {
+                                    graphBuilderSuite.apply(graph, context);
+                                    checkGraph(context, graph);
+                                } catch (VerificationError e) {
+                                    errors.add(e.getMessage());
+                                } catch (LinkageError e) {
+                                    // suppress linkages errors resulting from eager resolution
+                                } catch (BailoutException e) {
+                                    // Graal bail outs on certain patterns in Java bytecode (e.g.,
+                                    // unbalanced monitors introduced by jacoco).
+                                } catch (Throwable e) {
+                                    StringWriter sw = new StringWriter();
+                                    e.printStackTrace(new PrintWriter(sw));
+                                    errors.add(String.format("Error while checking %s:%n%s", methodName, sw));
+                                }
+                            });
                         }
                     }
                 }
@@ -131,6 +145,13 @@
                 e.printStackTrace();
             }
         }
+        executor.shutdown();
+        try {
+            executor.awaitTermination(1, TimeUnit.HOURS);
+        } catch (InterruptedException e1) {
+            throw new RuntimeException(e1);
+        }
+
         if (!errors.isEmpty()) {
             StringBuilder msg = new StringBuilder();
             String nl = String.format("%n");
@@ -153,6 +174,7 @@
         new VerifyUsageWithEquals(JavaType.class).apply(graph, context);
         new VerifyUsageWithEquals(JavaMethod.class).apply(graph, context);
         new VerifyUsageWithEquals(JavaField.class).apply(graph, context);
+        new VerifyUsageWithEquals(LIRKind.class).apply(graph, context);
         new VerifyDebugUsage().apply(graph, context);
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -103,7 +103,7 @@
             IntegerTestNode test = (IntegerTestNode) conditional.condition();
             ParameterNode param0 = graph.getParameter(0);
             ParameterNode param1 = graph.getParameter(1);
-            assertTrue((test.x() == param0 && test.y() == param1) || (test.x() == param1 && test.y() == param0));
+            assertTrue((test.getX() == param0 && test.getY() == param1) || (test.getX() == param1 && test.getY() == param0));
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatOptimizationTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,85 @@
+/*
+ * 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.compiler.test;
+
+import org.junit.*;
+
+/**
+ * Check for incorrect elimination of 0.0 and -0.0 from computations. They can affect the sign of
+ * the result of an add or substract.
+ */
+public class FloatOptimizationTest extends GraalCompilerTest {
+
+    @Test
+    public void test1() {
+        test("test1Snippet", -0.0);
+    }
+
+    @SuppressWarnings("all")
+    public static double test1Snippet(double x) {
+        return x + 0.0;
+    }
+
+    @Test
+    public void test2() {
+        test("test2Snippet", -0.0f);
+    }
+
+    @SuppressWarnings("all")
+    public static double test2Snippet(float x) {
+        return x + 0.0f;
+    }
+
+    @Test
+    public void test3() {
+        test("test3Snippet", -0.0);
+    }
+
+    @SuppressWarnings("all")
+    public static double test3Snippet(double x) {
+        return x - -0.0;
+    }
+
+    @Test
+    public void test4() {
+        test("test4Snippet", -0.0f);
+    }
+
+    @SuppressWarnings("all")
+    public static double test4Snippet(float x) {
+        return x - -0.0f;
+    }
+
+    @Override
+    protected void assertDeepEquals(String message, Object expected, Object actual, double delta) {
+        if (expected instanceof Double && actual instanceof Double) {
+            double e = (double) expected;
+            double a = (double) actual;
+            if (Double.doubleToRawLongBits(a) != Double.doubleToRawLongBits(e)) {
+                Assert.fail((message == null ? "" : message) + "raw double bits not equal " + Double.doubleToRawLongBits(a) + " != " + Double.doubleToRawLongBits(e));
+            }
+        } else {
+            super.assertDeepEquals(message, expected, actual, delta);
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -384,7 +384,7 @@
 
     public StructuredGraph visualize(StructuredGraph graph, String title) {
         DebugConfig debugConfig = DebugScope.getConfig();
-        DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, false, debugConfig.dumpHandlers(), debugConfig.output());
+        DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.verifyHandlers(), debugConfig.output());
         try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
             Debug.dump(graph, title);
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSensitiveReductionTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSensitiveReductionTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -148,9 +148,7 @@
         new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
         for (ConstantNode constant : getConstantNodes(graph)) {
-            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
-                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
-            }
+            assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
         }
     }
 
@@ -186,9 +184,7 @@
         new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), null));
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
         for (ConstantNode constant : getConstantNodes(graph)) {
-            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
-                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
-            }
+            assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
         }
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -213,14 +213,8 @@
     protected int countUnusedConstants(StructuredGraph graph) {
         int total = 0;
         for (ConstantNode node : getConstantNodes(graph)) {
-            if (!ConstantNodeRecordsUsages) {
-                if (node.gatherUsages(graph).isEmpty()) {
-                    total++;
-                }
-            } else {
-                if (node.usages().isEmpty()) {
-                    total++;
-                }
+            if (node.usages().isEmpty()) {
+                total++;
             }
         }
         return total;
@@ -275,7 +269,7 @@
             }
             result.append("\n");
             for (Node node : schedule.getBlockToNodesMap().get(block)) {
-                if (node.recordsUsages()) {
+                if (node.isAlive() && node.recordsUsages()) {
                     if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode)) {
                         int id;
                         if (canonicalId.get(node) != null) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -651,7 +651,7 @@
                 MidTierContext midContext = new MidTierContext(getProviders(), assumptions, getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
                 new GuardLoweringPhase().apply(graph, midContext);
                 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
-                new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
+                new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, midContext);
 
                 SchedulePhase schedule = new SchedulePhase(schedulingStrategy, memsched);
                 schedule.apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -85,9 +85,11 @@
     private StructuredGraph parseAndProcess(String snippet) {
         StructuredGraph graph = parse(snippet);
         ParameterNode param = graph.getNodes(ParameterNode.class).first();
-        ConstantNode constant = ConstantNode.forInt(0, graph);
-        for (Node n : param.usages().filter(isNotA(FrameState.class)).snapshot()) {
-            n.replaceFirstInput(param, constant);
+        if (param != null) {
+            ConstantNode constant = ConstantNode.forInt(0, graph);
+            for (Node n : param.usages().filter(isNotA(FrameState.class)).snapshot()) {
+                n.replaceFirstInput(param, constant);
+            }
         }
         Map<Invoke, Double> hints = new HashMap<>();
         for (Invoke invoke : graph.getInvokes()) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -80,18 +80,20 @@
             }
         }
 
-        private void collectStats(final LIRInstruction instr) {
-            instr.forEachOutput(new ValueProcedure() {
+        private ValueProcedure collectStatsProc = new ValueProcedure() {
 
-                @Override
-                public Value doValue(Value value) {
-                    if (ValueUtil.isRegister(value)) {
-                        final Register reg = ValueUtil.asRegister(value);
-                        registers.add(reg);
-                    }
-                    return value;
+            @Override
+            public Value doValue(Value value) {
+                if (ValueUtil.isRegister(value)) {
+                    final Register reg = ValueUtil.asRegister(value);
+                    registers.add(reg);
                 }
-            });
+                return value;
+            }
+        };
+
+        private void collectStats(final LIRInstruction instr) {
+            instr.forEachOutput(collectStatsProc);
 
             if (instr instanceof MoveOp) {
                 MoveOp move = (MoveOp) instr;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -25,10 +25,9 @@
 import org.junit.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.loop.phases.*;
-import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
@@ -279,7 +278,7 @@
 
     @SuppressWarnings("unused")
     public static void testNewNodeSnippet() {
-        new IntegerAddNode(new IntegerStamp(32, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0xFFFFFFFF), null, null);
+        new ValueAnchorNode(null);
     }
 
     /**
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Mon Jun 30 12:02:19 2014 +0200
@@ -42,6 +42,8 @@
     public static final OptionValue<String> Dump = new OptionValue<>(null);
     @Option(help = "Pattern for scope(s) to in which metering is enabled (see DebugFilter and Debug.metric)")
     public static final OptionValue<String> Meter = new OptionValue<>(null);
+    @Option(help = "Pattern for scope(s) to in which verification is enabled (see DebugFilter and Debug.verify)")
+    public static final OptionValue<String> Verify = new OptionValue<>(null);
     @Option(help = "Pattern for scope(s) to in which memory use tracking is enabled (see DebugFilter and Debug.metric)")
     public static final OptionValue<String> TrackMemUse = new OptionValue<>(null);
     @Option(help = "Pattern for scope(s) to in which timing is enabled (see DebugFilter and Debug.timer)")
@@ -89,18 +91,21 @@
     private final DebugFilter trackMemUseFilter;
     private final DebugFilter timerFilter;
     private final DebugFilter dumpFilter;
+    private final DebugFilter verifyFilter;
     private final MethodFilter[] methodFilter;
     private final List<DebugDumpHandler> dumpHandlers;
+    private final List<DebugVerifyHandler> verifyHandlers;
     private final PrintStream output;
     private final Set<Object> extraFilters = new HashSet<>();
 
-    public GraalDebugConfig(String logFilter, String meterFilter, String trackMemUseFilter, String timerFilter, String dumpFilter, String methodFilter, PrintStream output,
-                    List<DebugDumpHandler> dumpHandlers) {
+    public GraalDebugConfig(String logFilter, String meterFilter, String trackMemUseFilter, String timerFilter, String dumpFilter, String verifyFilter, String methodFilter, PrintStream output,
+                    List<DebugDumpHandler> dumpHandlers, List<DebugVerifyHandler> verifyHandlers) {
         this.logFilter = DebugFilter.parse(logFilter);
         this.meterFilter = DebugFilter.parse(meterFilter);
         this.trackMemUseFilter = DebugFilter.parse(trackMemUseFilter);
         this.timerFilter = DebugFilter.parse(timerFilter);
         this.dumpFilter = DebugFilter.parse(dumpFilter);
+        this.verifyFilter = DebugFilter.parse(verifyFilter);
         if (methodFilter == null || methodFilter.isEmpty()) {
             this.methodFilter = null;
         } else {
@@ -112,6 +117,7 @@
             // TTY.println(Thread.currentThread().getName() + ": " + toString());
         }
         this.dumpHandlers = dumpHandlers;
+        this.verifyHandlers = verifyHandlers;
         this.output = output;
     }
 
@@ -127,10 +133,6 @@
         return isEnabled(meterFilter);
     }
 
-    public boolean isMetderEnabled() {
-        return isEnabled(meterFilter);
-    }
-
     public boolean isMemUseTrackingEnabled() {
         return isEnabled(trackMemUseFilter);
     }
@@ -143,6 +145,14 @@
         return isEnabledForMethod(dumpFilter);
     }
 
+    public boolean isVerifyEnabled() {
+        return isEnabled(verifyFilter);
+    }
+
+    public boolean isVerifyEnabledForMethod() {
+        return isEnabledForMethod(verifyFilter);
+    }
+
     public boolean isTimeEnabled() {
         return isEnabled(timerFilter);
     }
@@ -231,7 +241,7 @@
         if (e instanceof BailoutException) {
             return null;
         }
-        Debug.setConfig(Debug.fixedConfig(true, true, false, false, false, dumpHandlers, output));
+        Debug.setConfig(Debug.fixedConfig(true, true, false, false, false, false, dumpHandlers, verifyHandlers, output));
         Debug.log(String.format("Exception occurred in scope: %s", Debug.currentScope()));
         for (Object o : Debug.context()) {
             if (o instanceof Graph) {
@@ -269,6 +279,11 @@
     }
 
     @Override
+    public Collection<DebugVerifyHandler> verifyHandlers() {
+        return verifyHandlers;
+    }
+
+    @Override
     public void addToContext(Object o) {
         extraFilters.add(o);
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -451,7 +451,7 @@
     /**
      * The kind of this interval.
      */
-    private PlatformKind kind;
+    private LIRKind kind;
 
     /**
      * The head of the list of ranges describing this interval. This list is sorted by
@@ -533,7 +533,7 @@
     void assignLocation(AllocatableValue newLocation) {
         if (isRegister(newLocation)) {
             assert this.location == null : "cannot re-assign location for " + this;
-            if (newLocation.getPlatformKind() == Kind.Illegal && kind != Kind.Illegal) {
+            if (newLocation.getLIRKind().equals(LIRKind.Illegal) && !kind.equals(LIRKind.Illegal)) {
                 this.location = asRegister(newLocation).asValue(kind);
                 return;
             }
@@ -542,8 +542,8 @@
         } else {
             assert this.location == null || isRegister(this.location) : "cannot re-assign location for " + this;
             assert isStackSlot(newLocation);
-            assert newLocation.getPlatformKind() != Kind.Illegal;
-            assert newLocation.getPlatformKind() == this.kind;
+            assert !newLocation.getLIRKind().equals(LIRKind.Illegal);
+            assert newLocation.getLIRKind().equals(this.kind);
         }
         this.location = newLocation;
     }
@@ -556,13 +556,13 @@
         return location;
     }
 
-    public PlatformKind kind() {
+    public LIRKind kind() {
         assert !isRegister(operand) : "cannot access type for fixed interval";
         return kind;
     }
 
-    void setKind(PlatformKind kind) {
-        assert isRegister(operand) || this.kind() == Kind.Illegal || this.kind() == kind : "overwriting existing type";
+    void setKind(LIRKind kind) {
+        assert isRegister(operand) || this.kind().equals(LIRKind.Illegal) || this.kind().equals(kind) : "overwriting existing type";
         this.kind = kind;
     }
 
@@ -715,7 +715,7 @@
         } else {
             assert isIllegal(operand) || isVariable(operand);
         }
-        this.kind = Kind.Illegal;
+        this.kind = LIRKind.Illegal;
         this.first = Range.EndMarker;
         this.usePosList = new UsePosList(4);
         this.current = Range.EndMarker;
@@ -774,7 +774,7 @@
                 Interval i1 = splitChildren.get(i);
 
                 assert i1.splitParent() == this : "not a split child of this interval";
-                assert i1.kind() == kind() : "must be equal for all split children";
+                assert i1.kind().equals(kind()) : "must be equal for all split children";
                 assert (i1.spillSlot() == null && spillSlot == null) || i1.spillSlot().equals(spillSlot()) : "must be equal for all split children";
 
                 for (int j = i + 1; j < splitChildren.size(); j++) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.LIRInstruction.StateProcedure;
@@ -959,13 +960,13 @@
         }
     }
 
-    void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, PlatformKind kind) {
+    void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
         if (!isProcessed(operand)) {
             return;
         }
 
         Interval interval = getOrCreateInterval(operand);
-        if (kind != Kind.Illegal) {
+        if (!kind.equals(LIRKind.Illegal)) {
             interval.setKind(kind);
         }
 
@@ -977,13 +978,13 @@
         Debug.log("add use: %s, from %d to %d (%s)", interval, from, to, registerPriority.name());
     }
 
-    void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, PlatformKind kind) {
+    void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
         if (!isProcessed(operand)) {
             return;
         }
 
         Interval interval = getOrCreateInterval(operand);
-        if (kind != Kind.Illegal) {
+        if (!kind.equals(LIRKind.Illegal)) {
             interval.setKind(kind);
         }
 
@@ -998,14 +999,14 @@
         return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable();
     }
 
-    void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, PlatformKind kind) {
+    void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
         if (!isProcessed(operand)) {
             return;
         }
         int defPos = op.id();
 
         Interval interval = getOrCreateInterval(operand);
-        if (kind != Kind.Illegal) {
+        if (!kind.equals(LIRKind.Illegal)) {
             interval.setKind(kind);
         }
 
@@ -1123,6 +1124,70 @@
     void buildIntervals() {
 
         try (Indent indent = Debug.logAndIndent("build intervals")) {
+            InstructionValueProcedure outputProc = new InstructionValueProcedure() {
+
+                @Override
+                public Value doValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    if (isVariableOrRegister(operand)) {
+                        addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind());
+                        addRegisterHint(op, operand, mode, flags, true);
+                    }
+                    return operand;
+                }
+            };
+
+            InstructionValueProcedure tempProc = new InstructionValueProcedure() {
+
+                @Override
+                public Value doValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    if (isVariableOrRegister(operand)) {
+                        addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind());
+                        addRegisterHint(op, operand, mode, flags, false);
+                    }
+                    return operand;
+                }
+            };
+
+            InstructionValueProcedure aliveProc = new InstructionValueProcedure() {
+
+                @Override
+                public Value doValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    if (isVariableOrRegister(operand)) {
+                        RegisterPriority p = registerPriorityOfInputOperand(flags);
+                        final int opId = op.id();
+                        final int blockFrom = getFirstLirInstructionId((blockForId(opId)));
+                        addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind());
+                        addRegisterHint(op, operand, mode, flags, false);
+                    }
+                    return operand;
+                }
+            };
+
+            InstructionValueProcedure inputProc = new InstructionValueProcedure() {
+
+                @Override
+                public Value doValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    if (isVariableOrRegister(operand)) {
+                        final int opId = op.id();
+                        final int blockFrom = getFirstLirInstructionId((blockForId(opId)));
+                        RegisterPriority p = registerPriorityOfInputOperand(flags);
+                        addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind());
+                        addRegisterHint(op, operand, mode, flags, false);
+                    }
+                    return operand;
+                }
+            };
+
+            InstructionValueProcedure stateProc = new InstructionValueProcedure() {
+
+                @Override
+                public Value doValue(LIRInstruction op, Value operand) {
+                    final int opId = op.id();
+                    final int blockFrom = getFirstLirInstructionId((blockForId(opId)));
+                    addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind());
+                    return operand;
+                }
+            };
 
             // create a list with all caller-save registers (cpu, fpu, xmm)
             Register[] callerSaveRegs = frameMap.registerConfig.getCallerSaveRegisters();
@@ -1147,7 +1212,7 @@
                         AllocatableValue operand = intervalFor(operandNum).operand;
                         Debug.log("live in %d: %s", operandNum, operand);
 
-                        addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, Kind.Illegal);
+                        addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, LIRKind.Illegal);
 
                         // add special use positions for loop-end blocks when the
                         // interval is used anywhere inside this loop. It's possible
@@ -1171,72 +1236,23 @@
                             if (op.destroysCallerSavedRegisters()) {
                                 for (Register r : callerSaveRegs) {
                                     if (attributes(r).isAllocatable()) {
-                                        addTemp(r.asValue(), opId, RegisterPriority.None, Kind.Illegal);
+                                        addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal);
                                     }
                                 }
                                 Debug.log("operation destroys all caller-save registers");
                             }
 
-                            op.forEachOutput(new ValueProcedure() {
-
-                                @Override
-                                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                                    if (isVariableOrRegister(operand)) {
-                                        addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getPlatformKind());
-                                        addRegisterHint(op, operand, mode, flags, true);
-                                    }
-                                    return operand;
-                                }
-                            });
-                            op.forEachTemp(new ValueProcedure() {
-
-                                @Override
-                                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                                    if (isVariableOrRegister(operand)) {
-                                        addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getPlatformKind());
-                                        addRegisterHint(op, operand, mode, flags, false);
-                                    }
-                                    return operand;
-                                }
-                            });
-                            op.forEachAlive(new ValueProcedure() {
-
-                                @Override
-                                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                                    if (isVariableOrRegister(operand)) {
-                                        RegisterPriority p = registerPriorityOfInputOperand(flags);
-                                        addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getPlatformKind());
-                                        addRegisterHint(op, operand, mode, flags, false);
-                                    }
-                                    return operand;
-                                }
-                            });
-                            op.forEachInput(new ValueProcedure() {
-
-                                @Override
-                                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                                    if (isVariableOrRegister(operand)) {
-                                        RegisterPriority p = registerPriorityOfInputOperand(flags);
-                                        addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getPlatformKind());
-                                        addRegisterHint(op, operand, mode, flags, false);
-                                    }
-                                    return operand;
-                                }
-                            });
+                            op.forEachOutput(outputProc);
+                            op.forEachTemp(tempProc);
+                            op.forEachAlive(aliveProc);
+                            op.forEachInput(inputProc);
 
                             // Add uses of live locals from interpreter's point of view for proper
                             // debug information generation
                             // Treat these operands as temp values (if the live range is extended
                             // to a call site, the value would be in a register at
                             // the call otherwise)
-                            op.forEachState(new ValueProcedure() {
-
-                                @Override
-                                public Value doValue(Value operand) {
-                                    addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getPlatformKind());
-                                    return operand;
-                                }
-                            });
+                            op.forEachState(stateProc);
 
                             // special steps for some instructions (especially moves)
                             handleMethodArguments(op);
@@ -1682,42 +1698,44 @@
         return attributes(asRegister(operand)).isCallerSave();
     }
 
+    private InstructionValueProcedure debugInfoProc = new InstructionValueProcedure() {
+
+        @Override
+        public Value doValue(LIRInstruction op, Value operand) {
+            int tempOpId = op.id();
+            OperandMode mode = OperandMode.USE;
+            AbstractBlock<?> block = blockForId(tempOpId);
+            if (block.getSuccessorCount() == 1 && tempOpId == getLastLirInstructionId(block)) {
+                // generating debug information for the last instruction of a block.
+                // if this instruction is a branch, spill moves are inserted before this branch
+                // and so the wrong operand would be returned (spill moves at block boundaries
+                // are not
+                // considered in the live ranges of intervals)
+                // Solution: use the first opId of the branch target block instead.
+                final LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1);
+                if (instr instanceof StandardOp.JumpOp) {
+                    if (blockData.get(block).liveOut.get(operandNumber(operand))) {
+                        tempOpId = getFirstLirInstructionId(block.getSuccessors().iterator().next());
+                        mode = OperandMode.DEF;
+                    }
+                }
+            }
+
+            // Get current location of operand
+            // The operand must be live because debug information is considered when building
+            // the intervals
+            // if the interval is not live, colorLirOperand will cause an assert on failure
+            Value result = colorLirOperand((Variable) operand, tempOpId, mode);
+            assert !hasCall(tempOpId) || isStackSlot(result) || isConstant(result) || !isCallerSave(result) : "cannot have caller-save register operands at calls";
+            return result;
+        }
+    };
+
     private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRFrameState info) {
         info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !callKillsRegisters);
         markFrameLocations(iw, op, info);
 
-        info.forEachState(new ValueProcedure() {
-
-            @Override
-            public Value doValue(Value operand) {
-                int tempOpId = op.id();
-                OperandMode mode = OperandMode.USE;
-                AbstractBlock<?> block = blockForId(tempOpId);
-                if (block.getSuccessorCount() == 1 && tempOpId == getLastLirInstructionId(block)) {
-                    // generating debug information for the last instruction of a block.
-                    // if this instruction is a branch, spill moves are inserted before this branch
-                    // and so the wrong operand would be returned (spill moves at block boundaries
-                    // are not
-                    // considered in the live ranges of intervals)
-                    // Solution: use the first opId of the branch target block instead.
-                    final LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1);
-                    if (instr instanceof StandardOp.JumpOp) {
-                        if (blockData.get(block).liveOut.get(operandNumber(operand))) {
-                            tempOpId = getFirstLirInstructionId(block.getSuccessors().iterator().next());
-                            mode = OperandMode.DEF;
-                        }
-                    }
-                }
-
-                // Get current location of operand
-                // The operand must be live because debug information is considered when building
-                // the intervals
-                // if the interval is not live, colorLirOperand will cause an assert on failure
-                Value result = colorLirOperand((Variable) operand, tempOpId, mode);
-                assert !hasCall(tempOpId) || isStackSlot(result) || isConstant(result) || !isCallerSave(result) : "cannot have caller-save register operands at calls";
-                return result;
-            }
-        });
+        info.forEachState(op, debugInfoProc);
         info.finish(op, frameMap);
     }
 
@@ -1725,6 +1743,17 @@
         int numInst = instructions.size();
         boolean hasDead = false;
 
+        InstructionValueProcedure assignProc = new InstructionValueProcedure() {
+
+            @Override
+            public Value doValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVariable(operand)) {
+                    return colorLirOperand((Variable) operand, op.id(), mode);
+                }
+                return operand;
+            }
+        };
+
         for (int j = 0; j < numInst; j++) {
             final LIRInstruction op = instructions.get(j);
             if (op == null) { // this can happen when spill-moves are removed in eliminateSpillMoves
@@ -1749,17 +1778,6 @@
                 }
             }
 
-            ValueProcedure assignProc = new ValueProcedure() {
-
-                @Override
-                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                    if (isVariable(operand)) {
-                        return colorLirOperand((Variable) operand, op.id(), mode);
-                    }
-                    return operand;
-                }
-            };
-
             op.forEachInput(assignProc);
             op.forEachAlive(assignProc);
             op.forEachTemp(assignProc);
@@ -1918,7 +1936,7 @@
                     throw new GraalInternalError("");
                 }
 
-                if (isVariable(i1.operand) && i1.kind() == Kind.Illegal) {
+                if (isVariable(i1.operand) && i1.kind().equals(LIRKind.Illegal)) {
                     Debug.log("Interval %d has no type assigned", i1.operandNumber);
                     Debug.log(i1.logString(this));
                     throw new GraalInternalError("");
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -773,7 +773,7 @@
     }
 
     void initVarsForAlloc(Interval interval) {
-        availableRegs = allocator.frameMap.registerConfig.getAllocatableRegisters(interval.kind());
+        availableRegs = allocator.frameMap.registerConfig.getAllocatableRegisters(interval.kind().getPlatformKind());
     }
 
     static boolean isMove(LIRInstruction op, Interval from, Interval to) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -197,7 +197,7 @@
 
     private void insertMove(Interval fromInterval, Interval toInterval) {
         assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert fromInterval.kind() == toInterval.kind() : "move between different types";
+        assert fromInterval.kind().equals(toInterval.kind()) : "move between different types";
         assert insertIdx != -1 : "must setup insert position first";
 
         AllocatableValue fromOpr = fromInterval.operand;
@@ -209,7 +209,7 @@
     }
 
     private void insertMove(Value fromOpr, Interval toInterval) {
-        assert fromOpr.getPlatformKind() == toInterval.kind() : "move between different types";
+        assert fromOpr.getLIRKind().equals(toInterval.kind()) : "move between different types";
         assert insertIdx != -1 : "must setup insert position first";
 
         AllocatableValue toOpr = toInterval.operand;
@@ -339,7 +339,7 @@
         Debug.log("add move mapping from %s to %s", fromInterval, toInterval);
 
         assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert fromInterval.kind() == toInterval.kind();
+        assert fromInterval.kind().equals(toInterval.kind());
         mappingFrom.add(fromInterval);
         mappingFromOpr.add(Value.ILLEGAL);
         mappingTo.add(toInterval);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,9 +32,9 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -187,6 +187,38 @@
     }
 
     void processOperations(List<LIRInstruction> ops, final Interval[] inputState) {
+        InstructionValueProcedure useProc = new InstructionValueProcedure() {
+
+            @Override
+            public Value doValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
+                    Interval interval = intervalAt(operand);
+                    if (op.id() != -1) {
+                        interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
+                    }
+
+                    assert checkState(inputState, interval.location(), interval.splitParent());
+                }
+                return operand;
+            }
+        };
+
+        InstructionValueProcedure defProc = new InstructionValueProcedure() {
+
+            @Override
+            public Value doValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
+                    Interval interval = intervalAt(operand);
+                    if (op.id() != -1) {
+                        interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
+                    }
+
+                    statePut(inputState, interval.location(), interval.splitParent());
+                }
+                return operand;
+            }
+        };
+
         // visit all instructions of the block
         for (int i = 0; i < ops.size(); i++) {
             final LIRInstruction op = ops.get(i);
@@ -195,38 +227,6 @@
                 Debug.log("%s", op.toStringWithIdPrefix());
             }
 
-            ValueProcedure useProc = new ValueProcedure() {
-
-                @Override
-                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                    if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
-                        Interval interval = intervalAt(operand);
-                        if (op.id() != -1) {
-                            interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
-                        }
-
-                        assert checkState(inputState, interval.location(), interval.splitParent());
-                    }
-                    return operand;
-                }
-            };
-
-            ValueProcedure defProc = new ValueProcedure() {
-
-                @Override
-                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                    if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
-                        Interval interval = intervalAt(operand);
-                        if (op.id() != -1) {
-                            interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
-                        }
-
-                        statePut(inputState, interval.location(), interval.splitParent());
-                    }
-                    return operand;
-                }
-            };
-
             // check if input operands are correct
             op.forEachInput(useProc);
             // invalidate all caller save registers at calls
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.lir.LIR.*;
-import static com.oracle.graal.nodes.ConstantNode.*;
 
 import java.util.*;
 import java.util.Map.Entry;
@@ -44,7 +43,6 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.lir.gen.LIRGenerator.LoadConstant;
 import com.oracle.graal.lir.gen.LIRGenerator.Options;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -57,19 +55,19 @@
  * This class traverses the HIR instructions and generates LIR instructions from them.
  */
 @MatchableNode(nodeClass = ConstantNode.class, shareable = true)
-@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"value"})
 @MatchableNode(nodeClass = FloatSubNode.class, inputs = {"x", "y"})
 @MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"object", "location"})
 @MatchableNode(nodeClass = IfNode.class, inputs = {"condition"})
 @MatchableNode(nodeClass = IntegerSubNode.class, inputs = {"x", "y"})
 @MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"})
-@MatchableNode(nodeClass = NarrowNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = NarrowNode.class, inputs = {"value"})
 @MatchableNode(nodeClass = ReadNode.class, inputs = {"object", "location"})
 @MatchableNode(nodeClass = ReinterpretNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"value"})
 @MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = {"x", "y"})
 @MatchableNode(nodeClass = WriteNode.class, inputs = {"object", "location", "value"})
-@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"value"})
 @MatchableNode(nodeClass = AndNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = FloatAddNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = FloatEqualsNode.class, inputs = {"x", "y"}, commutative = true)
@@ -135,48 +133,7 @@
         if (nodeOperands == null) {
             return null;
         }
-        Value operand = nodeOperands.get(node);
-        if (operand == null) {
-            operand = getConstantOperand(node);
-        }
-        return operand;
-    }
-
-    private Value getConstantOperand(ValueNode node) {
-        if (!ConstantNodeRecordsUsages) {
-            Constant value = node.asConstant();
-            if (value != null) {
-                if (gen.canInlineConstant(value)) {
-                    return setResult(node, value);
-                } else {
-                    Variable loadedValue;
-                    if (gen.getConstantLoads() == null) {
-                        gen.setConstantLoads(new HashMap<>());
-                    }
-                    LoadConstant load = gen.getConstantLoads().get(value);
-                    assert gen.getCurrentBlock() instanceof Block;
-                    if (load == null) {
-                        int index = gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).size();
-                        loadedValue = gen.emitMove(value);
-                        LIRInstruction op = gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).get(index);
-                        gen.getConstantLoads().put(value, new LoadConstant(loadedValue, gen.getCurrentBlock(), index, op));
-                    } else {
-                        AbstractBlock<?> dominator = ControlFlowGraph.commonDominator((Block) load.getBlock(), (Block) gen.getCurrentBlock());
-                        loadedValue = load.getVariable();
-                        if (dominator != load.getBlock()) {
-                            load.unpin(gen.getResult().getLIR());
-                        } else {
-                            assert load.getBlock() != gen.getCurrentBlock() || load.getIndex() < gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).size();
-                        }
-                        load.setBlock(dominator);
-                    }
-                    return loadedValue;
-                }
-            }
-        } else {
-            // Constant is loaded by ConstantNode.generate()
-        }
-        return null;
+        return nodeOperands.get(node);
     }
 
     public ValueNode valueForOperand(Value value) {
@@ -252,10 +209,7 @@
             if (Options.TraceLIRGeneratorLevel.getValue() >= 3) {
                 TTY.println("LIRGen for " + instr);
             }
-            if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) {
-                // Loading of constants is done lazily by operand()
-
-            } else if (instr instanceof ValueNode) {
+            if (instr instanceof ValueNode) {
                 ValueNode valueNode = (ValueNode) instr;
                 Value operand = getOperand(valueNode);
                 if (operand == null) {
@@ -418,8 +372,8 @@
         append(new JumpOp(getLIRBlock(merge)));
     }
 
-    protected PlatformKind getPhiKind(PhiNode phi) {
-        return gen.getPlatformKind(phi.stamp());
+    protected LIRKind getPhiKind(PhiNode phi) {
+        return gen.getLIRKind(phi.stamp());
     }
 
     private Value operandForPhi(ValuePhiNode phi) {
@@ -454,17 +408,17 @@
     }
 
     private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        PlatformKind kind = gen.getPlatformKind(node.object().stamp());
-        gen.emitCompareBranch(kind, operand(node.object()), kind.getDefaultValue(), Condition.EQ, false, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        PlatformKind kind = gen.getLIRKind(node.getValue().stamp()).getPlatformKind();
+        gen.emitCompareBranch(kind, operand(node.getValue()), kind.getDefaultValue(), Condition.EQ, false, trueSuccessor, falseSuccessor, trueSuccessorProbability);
     }
 
     public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        PlatformKind kind = gen.getPlatformKind(compare.x().stamp());
-        gen.emitCompareBranch(kind, operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        PlatformKind kind = gen.getLIRKind(compare.getX().stamp()).getPlatformKind();
+        gen.emitCompareBranch(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability);
     }
 
     public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        gen.emitIntegerTestBranch(operand(test.x()), operand(test.y()), trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        gen.emitIntegerTestBranch(operand(test.getX()), operand(test.getY()), trueSuccessor, falseSuccessor, trueSuccessorProbability);
     }
 
     public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) {
@@ -482,17 +436,17 @@
     public Variable emitConditional(LogicNode node, Value trueValue, Value falseValue) {
         if (node instanceof IsNullNode) {
             IsNullNode isNullNode = (IsNullNode) node;
-            PlatformKind kind = gen.getPlatformKind(isNullNode.object().stamp());
-            return gen.emitConditionalMove(kind, operand(isNullNode.object()), kind.getDefaultValue(), Condition.EQ, false, trueValue, falseValue);
+            PlatformKind kind = gen.getLIRKind(isNullNode.getValue().stamp()).getPlatformKind();
+            return gen.emitConditionalMove(kind, operand(isNullNode.getValue()), kind.getDefaultValue(), Condition.EQ, false, trueValue, falseValue);
         } else if (node instanceof CompareNode) {
             CompareNode compare = (CompareNode) node;
-            PlatformKind kind = gen.getPlatformKind(compare.x().stamp());
-            return gen.emitConditionalMove(kind, operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueValue, falseValue);
+            PlatformKind kind = gen.getLIRKind(compare.getX().stamp()).getPlatformKind();
+            return gen.emitConditionalMove(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueValue, falseValue);
         } else if (node instanceof LogicConstantNode) {
             return gen.emitMove(((LogicConstantNode) node).getValue() ? trueValue : falseValue);
         } else if (node instanceof IntegerTestNode) {
             IntegerTestNode test = (IntegerTestNode) node;
-            return gen.emitIntegerTestMove(operand(test.x()), operand(test.y()), trueValue, falseValue);
+            return gen.emitIntegerTestMove(operand(test.getX()), operand(test.getY()), trueValue, falseValue);
         } else {
             throw GraalInternalError.unimplemented(node.toString());
         }
@@ -573,7 +527,7 @@
             if (keyCount == 1) {
                 assert defaultTarget != null;
                 double probability = x.probability(x.keySuccessor(0));
-                PlatformKind kind = gen.getPlatformKind(x.value().stamp());
+                PlatformKind kind = gen.getLIRKind(x.value().stamp()).getPlatformKind();
                 gen.emitCompareBranch(kind, gen.load(operand(x.value())), x.keyAt(0), Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget, probability);
             } else {
                 LabelRef[] keyTargets = new LabelRef[keyCount];
@@ -647,26 +601,6 @@
         gen.emitOverflowCheckBranch(getLIRBlock(overflowSuccessor), getLIRBlock(next), probability);
     }
 
-    public final void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) {
-        gen.emitArrayEquals(kind, result, array1, array2, length);
-    }
-
-    public final Variable newVariable(Kind i) {
-        return gen.newVariable(i);
-    }
-
-    public final void emitBitCount(Variable result, Value operand) {
-        gen.emitBitCount(result, operand);
-    }
-
-    public final void emitBitScanForward(Variable result, Value operand) {
-        gen.emitBitScanForward(result, operand);
-    }
-
-    final void emitBitScanReverse(Variable result, Value operand) {
-        gen.emitBitScanReverse(result, operand);
-    }
-
     @Override
     public LIRGeneratorTool getLIRGeneratorTool() {
         return gen;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -231,7 +231,7 @@
 
     private void moveToTemp(Value src) {
         assert isIllegal(temp);
-        temp = gen.newVariable(src.getPlatformKind());
+        temp = gen.newVariable(src.getLIRKind());
         emitMove(temp, src);
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java	Mon Jun 30 12:02:19 2014 +0200
@@ -37,7 +37,7 @@
      * This is the Value of a node which was matched as part of a complex match. The value isn't
      * actually useable but this marks it as having been evaluated.
      */
-    @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(Kind.Illegal) {
+    @SuppressWarnings("serial") public static final Value INTERIOR_MATCH = new Value(LIRKind.Illegal) {
 
         @Override
         public String toString() {
@@ -54,7 +54,7 @@
     final ComplexMatchResult result;
 
     public ComplexMatchValue(ComplexMatchResult result) {
-        super(Kind.Illegal);
+        super(LIRKind.Illegal);
         this.result = result;
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Mon Jun 30 12:02:19 2014 +0200
@@ -219,18 +219,20 @@
      */
     private static final boolean DEBUG = false;
 
-    private static final String LOGFILE = new File(System.getProperty("java.io.tmpdir"), "matchprocessor.log").getPath();
-
-    private static PrintWriter log;
+    private PrintWriter log;
 
     /**
-     * Logging facility for the debugging the annotation processor.
+     * Logging facility for debugging the annotation processor.
      */
 
-    private static synchronized PrintWriter getLog() {
+    private PrintWriter getLog() {
         if (log == null) {
             try {
-                log = new PrintWriter(new FileWriter(LOGFILE, true));
+                // Create the log file within the generated source directory so it's easy to find.
+                // /tmp isn't platform independent and java.io.tmpdir can map anywhere, particularly
+                // on the mac.
+                FileObject file = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", getClass().getSimpleName() + "log");
+                log = new PrintWriter(new FileWriter(file.toUri().getPath(), true));
             } catch (IOException e) {
                 // Do nothing
             }
@@ -238,7 +240,7 @@
         return log;
     }
 
-    private static synchronized void logMessage(String format, Object... args) {
+    private void logMessage(String format, Object... args) {
         if (!DEBUG) {
             return;
         }
@@ -249,7 +251,7 @@
         }
     }
 
-    private static synchronized void logException(Throwable t) {
+    private void logException(Throwable t) {
         if (!DEBUG) {
             return;
         }
@@ -265,9 +267,11 @@
      * throws as errors.
      */
     private void reportExceptionThrow(Element element, Throwable t) {
-        logMessage("throw for %s:\n", element);
+        if (element != null) {
+            logMessage("throw for %s:\n", element);
+        }
         logException(t);
-        processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 4)), element);
+        errorMessage(element, "Exception throw during processing: %s %s", t, Arrays.toString(Arrays.copyOf(t.getStackTrace(), 4)));
     }
 
     static class TypeDescriptor {
@@ -334,7 +338,7 @@
      * The mapping between elements with MatchRules and the wrapper class used invoke the code
      * generation after the match.
      */
-    private Map<ExecutableElement, MethodInvokerItem> invokers = new LinkedHashMap<>();
+    private Map<String, MethodInvokerItem> invokers = new LinkedHashMap<>();
 
     private TypeDescriptor valueType;
 
@@ -564,7 +568,7 @@
         try {
             createProviderFile(pkg, matchStatementClassName, originatingElements);
         } catch (IOException e) {
-            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType);
+            reportExceptionThrow(info.topDeclaringType, e);
         }
     }
 
@@ -608,7 +612,7 @@
          * @return a string which will construct the MatchStatement instance to match this pattern.
          */
         public String ruleBuilder() {
-            return String.format("new MatchStatement(\"%s\", %s, %s.instance, %s)", invoker.name, matchPattern, invoker.wrapperClass(), invoker.argumentsListName());
+            return String.format("new MatchStatement(\"%s\", %s, %s.instance, %s)", invoker.methodName, matchPattern, invoker.wrapperClass(), invoker.argumentsListName());
         }
     }
 
@@ -616,15 +620,15 @@
      * Used to generate the wrapper class to invoke the code generation method.
      */
     static class MethodInvokerItem {
-        final String name;
+        final String methodName;
         final String nodeLIRBuilderClass;
-        final String methodName;
+        final ExecutableElement method;
         final List<? extends VariableElement> fields;
 
-        MethodInvokerItem(String name, String nodeLIRBuilderClass, String methodName, List<? extends VariableElement> fields) {
-            this.name = name;
+        MethodInvokerItem(String methodName, String nodeLIRBuilderClass, ExecutableElement method, List<? extends VariableElement> fields) {
+            this.methodName = methodName;
             this.nodeLIRBuilderClass = nodeLIRBuilderClass;
-            this.methodName = methodName;
+            this.method = method;
             this.fields = fields;
         }
 
@@ -672,6 +676,7 @@
         if (roundEnv.processingOver()) {
             return true;
         }
+
         logMessage("Starting round %s\n", roundEnv);
         matchRulesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRules.class.getCanonicalName()).asType();
         matchRuleTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRule.class.getCanonicalName()).asType();
@@ -679,7 +684,16 @@
         matchableNodeTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNode.class.getCanonicalName()).asType();
         matchableNodesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNodes.class.getCanonicalName()).asType();
 
+        Element currentElement = null;
         try {
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNode.class)) {
+                logMessage("%s\n", element);
+                processMatchableNode(element);
+            }
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodes.class)) {
+                logMessage("%s\n", element);
+                processMatchableNode(element);
+            }
             // Define a TypeDescriptor for the generic node but don't enter it into the nodeTypes
             // table since it shouldn't be mentioned in match rules.
             TypeMirror valueTypeMirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
@@ -688,18 +702,21 @@
             Map<TypeElement, MatchRuleDescriptor> map = new LinkedHashMap<>();
 
             for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) {
+                currentElement = element;
                 processMatchRule(map, element, findAnnotationMirror(element, matchRuleTypeMirror));
             }
             for (Element element : roundEnv.getElementsAnnotatedWith(MatchRules.class)) {
+                currentElement = element;
                 processMatchRule(map, element, findAnnotationMirror(element, matchRulesTypeMirror));
             }
 
+            currentElement = null;
             for (MatchRuleDescriptor info : map.values()) {
                 createFiles(info);
             }
 
         } catch (Throwable t) {
-            processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 2)));
+            reportExceptionThrow(currentElement, t);
         }
 
         return true;
@@ -754,7 +771,12 @@
         } else {
             nodeClass = nodeClassMirror.toString();
         }
-        nodePackage = findPackage(processingEnv.getElementUtils().getTypeElement(nodeClass));
+        TypeElement typeElement = processingEnv.getElementUtils().getTypeElement(nodeClass);
+        if (typeElement == null) {
+            errorMessage(element, mirror, "Class \"%s\" cannot be resolved to a type", nodeClass);
+            return;
+        }
+        nodePackage = findPackage(typeElement);
         assert nodeClass.startsWith(nodePackage);
         nodeClass = nodeClass.substring(nodePackage.length() + 1);
         assert nodeClass.endsWith("Node");
@@ -776,8 +798,7 @@
                 current = (TypeElement) typeUtils.asElement(theSuper);
             }
             if (!ok) {
-                String msg = String.format("Input named \"%s\" doesn't exist in %s", input, nodeClassElement.getSimpleName());
-                processingEnv.getMessager().printMessage(Kind.ERROR, msg, element, mirror);
+                errorMessage(element, mirror, "Input named \"%s\" doesn't exist in %s", input, nodeClassElement.getSimpleName());
             }
         }
 
@@ -853,21 +874,18 @@
         Types typeUtils = typeUtils();
 
         if (!method.getModifiers().contains(Modifier.PUBLIC)) {
-            String msg = String.format("MatchRule method %s must be public", method.getSimpleName());
-            processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+            errorMessage(method, "MatchRule method %s must be public", method.getSimpleName());
             return;
         }
         if (method.getModifiers().contains(Modifier.STATIC)) {
-            String msg = String.format("MatchRule method %s must be non-static", method.getSimpleName());
-            processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+            errorMessage(method, "MatchRule method %s must be non-static", method.getSimpleName());
             return;
         }
 
         try {
             TypeMirror returnType = method.getReturnType();
             if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(ComplexMatchResult.class.getName()).asType())) {
-                String msg = String.format("MatchRule method return type must be %s", ComplexMatchResult.class.getName());
-                processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                errorMessage(method, "MatchRule method return type must be %s", ComplexMatchResult.class.getName());
                 return;
             }
 
@@ -877,8 +895,7 @@
             ArrayList<String> expectedNames = parser.capturedNames();
             List<? extends VariableElement> actualParameters = method.getParameters();
             if (expectedTypes.size() + 1 < actualParameters.size()) {
-                String msg = String.format("Too many arguments for match method %s %s", expectedTypes.size() + 1, actualParameters.size());
-                processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                errorMessage(method, "Too many arguments for match method %s != %s", expectedTypes.size() + 1, actualParameters.size());
                 return;
             }
 
@@ -889,22 +906,26 @@
                 String name = parameter.getSimpleName().toString();
                 int nameIndex = expectedNames.indexOf(name);
                 if (nameIndex == -1) {
-                    String msg = String.format("Argument \"%s\" isn't captured in the match rule", name);
-                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                    errorMessage(method, "Argument \"%s\" isn't captured in the match rule", name);
                     return;
                 }
                 TypeMirror type = parameter.asType();
                 if (!typeUtils.isAssignable(expectedTypes.get(nameIndex).mirror, type)) {
-                    String msg = String.format("Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type);
-                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                    errorMessage(method, "Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type);
                     return;
                 }
             }
 
-            MethodInvokerItem invoker = invokers.get(method);
+            String methodName = method.getSimpleName().toString();
+            MethodInvokerItem invoker = invokers.get(methodName);
             if (invoker == null) {
-                invoker = new MethodInvokerItem(method.getSimpleName().toString(), topDeclaringType(method).getSimpleName().toString(), method.getSimpleName().toString(), actualParameters);
-                invokers.put(method, invoker);
+                invoker = new MethodInvokerItem(methodName, topDeclaringType(method).getSimpleName().toString(), method, actualParameters);
+                invokers.put(methodName, invoker);
+            } else if (invoker.method != method) {
+                // This could be supported but it's easier if they are unique since the names
+                // are used in log output and snippet counters.
+                errorMessage(method, "Use unique method names for match methods.");
+                return;
             }
 
             Element enclosing = method.getEnclosingElement();
@@ -915,8 +936,7 @@
             while (enclosing != null) {
                 if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
                     if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
-                        String msg = String.format("MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
-                        processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                        errorMessage(method, "MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
                         return;
                     }
                     originatingElementsList.add(enclosing);
@@ -938,10 +958,18 @@
                 info.matchRules.add(new MatchRuleItem(match, invoker));
             }
         } catch (RuleParseError e) {
-            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), method, mirror);
+            errorMessage(method, mirror, e.getMessage());
         }
     }
 
+    private void errorMessage(Element element, String format, Object... args) {
+        processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element);
+    }
+
+    private void errorMessage(Element element, AnnotationMirror mirror, String format, Object... args) {
+        processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element, mirror);
+    }
+
     // TODO borrowed from com.oracle.truffle.dsl.processor.Utils
     @SuppressWarnings("unchecked")
     private static <T> List<T> getAnnotationValueList(Class<T> expectedListType, AnnotationMirror mirror, String name) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Mon Jun 30 12:02:19 2014 +0200
@@ -68,9 +68,6 @@
         for (int i = 0; i < names.length; i++) {
             for (NodeClass.Position position : nodeClass.getFirstLevelInputPositions()) {
                 String name = nodeClass.getName(position);
-                if (name.endsWith("#NDF")) {
-                    name = name.substring(0, name.length() - 4);
-                }
                 if (name.equals(names[i])) {
                     result[i] = position;
                     break;
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Mon Jun 30 12:02:19 2014 +0200
@@ -86,6 +86,33 @@
         return ENABLED && DebugScope.getInstance().isDumpEnabled();
     }
 
+    /**
+     * Determines if verification is enabled in the current method, regardless of the
+     * {@linkplain Debug#currentScope() current debug scope}.
+     *
+     * @see Debug#verify(Object, Object)
+     */
+    public static boolean isVerifyEnabledForMethod() {
+        if (!ENABLED) {
+            return false;
+        }
+        DebugConfig config = DebugScope.getConfig();
+        if (config == null) {
+            return false;
+        }
+        return config.isVerifyEnabledForMethod();
+    }
+
+    /**
+     * Determines if verification is enabled in the {@linkplain Debug#currentScope() current debug
+     * scope}.
+     *
+     * @see Debug#verify(Object, Object)
+     */
+    public static boolean isVerifyEnabled() {
+        return ENABLED && DebugScope.getInstance().isVerifyEnabled();
+    }
+
     public static boolean isMeterEnabled() {
         return ENABLED && DebugScope.getInstance().isMeterEnabled();
     }
@@ -460,6 +487,51 @@
     }
 
     /**
+     * Calls all {@link DebugVerifyHandler}s in the current {@linkplain DebugScope#getConfig()
+     * config} to perform verification on a given object.
+     *
+     * @param object object to verify
+     * @param context object describing the context of verification
+     *
+     * @see DebugVerifyHandler#verify(Object, Object...)
+     */
+    public static void verify(Object object, Object context) {
+        if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) {
+            DebugScope.getInstance().verify(object, context);
+        }
+    }
+
+    /**
+     * Calls all {@link DebugVerifyHandler}s in the current {@linkplain DebugScope#getConfig()
+     * config} to perform verification on a given object.
+     *
+     * @param object object to verify
+     * @param context1 first object describing the context of verification
+     * @param context2 second object describing the context of verification
+     *
+     * @see DebugVerifyHandler#verify(Object, Object...)
+     */
+    public static void verify(Object object, Object context1, Object context2) {
+        if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) {
+            DebugScope.getInstance().verify(object, context1, context2);
+        }
+    }
+
+    /**
+     * This override exists to catch cases when {@link #verify(Object, Object)} is called with one
+     * argument bound to a varargs method parameter. It will bind to this method instead of the
+     * single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void verify(Object object, Object[] args) {
+        assert false : "shouldn't use this";
+        if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) {
+            DebugScope.getInstance().verify(object, args);
+        }
+    }
+
+    /**
      * Opens a new indentation level (by adding some spaces) based on the current indentation level.
      * This should be used in a {@linkplain Indent try-with-resources} pattern.
      *
@@ -773,11 +845,11 @@
     }
 
     public static DebugConfig silentConfig() {
-        return fixedConfig(false, false, false, false, false, Collections.<DebugDumpHandler> emptyList(), System.out);
+        return fixedConfig(false, false, false, false, false, false, Collections.<DebugDumpHandler> emptyList(), Collections.<DebugVerifyHandler> emptyList(), System.out);
     }
 
     public static DebugConfig fixedConfig(final boolean isLogEnabled, final boolean isDumpEnabled, final boolean isMeterEnabled, final boolean isMemUseTrackingEnabled, final boolean isTimerEnabled,
-                    final Collection<DebugDumpHandler> dumpHandlers, final PrintStream output) {
+                    final boolean isVerifyEnabled, final Collection<DebugDumpHandler> dumpHandlers, final Collection<DebugVerifyHandler> verifyHandlers, final PrintStream output) {
         return new DebugConfig() {
 
             @Override
@@ -809,6 +881,15 @@
             }
 
             @Override
+            public boolean isVerifyEnabled() {
+                return isVerifyEnabled;
+            }
+
+            public boolean isVerifyEnabledForMethod() {
+                return isVerifyEnabled;
+            }
+
+            @Override
             public boolean isTimeEnabled() {
                 return isTimerEnabled;
             }
@@ -824,6 +905,11 @@
             }
 
             @Override
+            public Collection<DebugVerifyHandler> verifyHandlers() {
+                return verifyHandlers;
+            }
+
+            @Override
             public PrintStream output() {
                 return output;
             }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Mon Jun 30 12:02:19 2014 +0200
@@ -69,6 +69,16 @@
     boolean isDumpEnabledForMethod();
 
     /**
+     * @see Debug#isVerifyEnabled()
+     */
+    boolean isVerifyEnabled();
+
+    /**
+     * @see Debug#isVerifyEnabledForMethod()
+     */
+    boolean isVerifyEnabledForMethod();
+
+    /**
      * Adds an object the context used by this configuration to do filtering.
      */
     void addToContext(Object o);
@@ -94,9 +104,14 @@
     RuntimeException interceptException(Throwable e);
 
     /**
-     * Gets the modifiable collection dump handlers registered with this configuration.
+     * Gets the modifiable collection of dump handlers registered with this configuration.
      */
     Collection<DebugDumpHandler> dumpHandlers();
 
     PrintStream output();
+
+    /**
+     * Gets the modifiable collection of verify handlers registered with this configuration.
+     */
+    Collection<DebugVerifyHandler> verifyHandlers();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugVerifyHandler.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.debug;
+
+/**
+ * Performs some kind of verification on an object.
+ */
+public interface DebugVerifyHandler {
+
+    /**
+     * Verifies that a given object satisfies some invariants.
+     *
+     * @param object object to verify
+     * @param context object(s) describing the context of verification
+     */
+    void verify(Object object, Object... context);
+
+    /**
+     * Extracts the first object of a given type from a verification input object.
+     */
+    default <T> T extract(Class<T> type, Object input) {
+        if (type.isInstance(input)) {
+            return type.cast(input);
+        }
+        if (input instanceof Object[]) {
+            for (Object nestedContext : (Object[]) input) {
+                T object = extract(type, nestedContext);
+                if (object != null) {
+                    return object;
+                }
+            }
+        }
+        return null;
+    }
+}
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java	Mon Jun 30 12:02:19 2014 +0200
@@ -55,6 +55,14 @@
          */
         DUMP_METHOD,
         /**
+         * @see Debug#isVerifyEnabled()
+         */
+        VERIFY,
+        /**
+         * @see Debug#isVerifyEnabledForMethod()
+         */
+        VERIFY_METHOD,
+        /**
          * @see Debug#isMeterEnabled()
          */
         METER,
@@ -155,6 +163,23 @@
     }
 
     @Override
+    public boolean isVerifyEnabled() {
+        Boolean fs = featureState.get(Feature.VERIFY);
+        if (fs == null) {
+            return delegate.isVerifyEnabled();
+        }
+        return fs.booleanValue();
+    }
+
+    public boolean isVerifyEnabledForMethod() {
+        Boolean fs = featureState.get(Feature.VERIFY_METHOD);
+        if (fs == null) {
+            return delegate.isVerifyEnabledForMethod();
+        }
+        return fs.booleanValue();
+    }
+
+    @Override
     public boolean isTimeEnabled() {
         Boolean fs = featureState.get(Feature.TIME);
         if (fs == null) {
@@ -178,6 +203,11 @@
     }
 
     @Override
+    public Collection<DebugVerifyHandler> verifyHandlers() {
+        return delegate.verifyHandlers();
+    }
+
+    @Override
     public PrintStream output() {
         return delegate.output();
     }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Mon Jun 30 12:02:19 2014 +0200
@@ -95,6 +95,7 @@
     private boolean timeEnabled;
     private boolean memUseTrackingEnabled;
     private boolean dumpEnabled;
+    private boolean verifyEnabled;
     private boolean logEnabled;
 
     private PrintStream output;
@@ -158,6 +159,10 @@
         return dumpEnabled;
     }
 
+    public boolean isVerifyEnabled() {
+        return verifyEnabled;
+    }
+
     public boolean isLogEnabled() {
         return logEnabled;
     }
@@ -213,6 +218,20 @@
     }
 
     /**
+     * @see Debug#verify(Object, Object)
+     */
+    public void verify(Object object, Object... ctx) {
+        if (isVerifyEnabled()) {
+            DebugConfig config = getConfig();
+            if (config != null) {
+                for (DebugVerifyHandler handler : config.verifyHandlers()) {
+                    handler.verify(object, ctx);
+                }
+            }
+        }
+    }
+
+    /**
      * Creates and enters a new debug scope which is either a child of the current scope or a
      * disjoint top level scope.
      *
@@ -269,6 +288,7 @@
             memUseTrackingEnabled = false;
             timeEnabled = false;
             dumpEnabled = false;
+            verifyEnabled = false;
 
             // Be pragmatic: provide a default log stream to prevent a crash if the stream is not
             // set while logging
@@ -278,6 +298,7 @@
             memUseTrackingEnabled = config.isMemUseTrackingEnabled();
             timeEnabled = config.isTimeEnabled();
             dumpEnabled = config.isDumpEnabled();
+            verifyEnabled = config.isVerifyEnabled();
             logEnabled = config.isLogEnabled();
             output = config.output();
         }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/MemUseTrackerImpl.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/MemUseTrackerImpl.java	Mon Jun 30 12:02:19 2014 +0200
@@ -57,8 +57,8 @@
     private final DebugValue flat;
 
     public MemUseTrackerImpl(String name) {
-        super(name + "_Accm", false);
-        this.flat = new DebugValue(name + "_Flat", false) {
+        super(name + "_Accm", true);
+        this.flat = new DebugValue(name + "_Flat", true) {
 
             @Override
             public String toString(long value) {
@@ -69,7 +69,7 @@
 
     @Override
     public Closeable start() {
-        if (!isConditional() || Debug.isTimeEnabled()) {
+        if (!isConditional() || Debug.isMemUseTrackingEnabled()) {
             CloseableImpl result = new CloseableImpl();
             currentTracker.set(result);
             return result;
--- a/graal/com.oracle.graal.gpu/src/com/oracle/graal/gpu/ExternalCompilationResult.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.gpu/src/com/oracle/graal/gpu/ExternalCompilationResult.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,6 +44,7 @@
     private StructuredGraph hostGraph;
 
     private int[] oopMapArray;
+    private boolean usesAllocation;
 
     /**
      * Set the address for the point of entry to the external compilation result.
@@ -86,4 +87,12 @@
         return oopMapArray;
     }
 
+    public void setUsesAllocationFlag(boolean val) {
+        usesAllocation = val;
+    }
+
+    public boolean getUsesAllocationFlag() {
+        return usesAllocation;
+    }
+
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,6 +28,8 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.GraphEvent.NodeEvent;
 import com.oracle.graal.graph.Node.ValueNumberable;
+import com.oracle.graal.graph.NodeClass.NodeClassIterator;
+import com.oracle.graal.graph.NodeClass.Position;
 import com.oracle.graal.graph.iterators.*;
 
 /**
@@ -72,8 +74,7 @@
      */
     int compressions;
 
-    NodeChangedListener inputChangedListener;
-    NodeChangedListener usagesDroppedToZeroListener;
+    NodeEventListener nodeEventListener;
     private final HashMap<CacheEntry, Node> cachedNodes = new HashMap<>();
 
     /*
@@ -279,64 +280,118 @@
         return add(node);
     }
 
+    public <T extends Node> T addOrUniqueWithInputs(T node) {
+        NodeClassIterator iterator = node.inputs().iterator();
+        while (iterator.hasNext()) {
+            Position pos = iterator.nextPosition();
+            Node input = pos.get(node);
+            if (input != null && !input.isAlive()) {
+                assert !input.isDeleted();
+                pos.initialize(node, addOrUniqueWithInputs(input));
+            }
+        }
+        if (node.getNodeClass().valueNumberable()) {
+            return uniqueHelper(node, true);
+        }
+        return add(node);
+    }
+
     private <T extends Node> T addHelper(T node) {
         node.initialize(this);
         return node;
     }
 
-    public interface NodeChangedListener {
+    /**
+     * Client interested in one or more node related events.
+     */
+    public interface NodeEventListener {
+
+        /**
+         * Notifies this listener of a change in a node's inputs.
+         *
+         * @param node a node who has had one of its inputs changed
+         */
+        default void inputChanged(Node node) {
+        }
 
-        void nodeChanged(Node node);
+        /**
+         * Notifies this listener of a node becoming unused.
+         *
+         * @param node a node whose {@link Node#usages()} just became empty
+         */
+        default void usagesDroppedToZero(Node node) {
+        }
+
+        /**
+         * Notifies this listener of an added node.
+         *
+         * @param node a node that was just added to the graph
+         */
+        default void nodeAdded(Node node) {
+        }
     }
 
-    private static class ChainedNodeChangedListener implements NodeChangedListener {
+    /**
+     * Registers a given {@link NodeEventListener} with the enclosing graph until this object is
+     * {@linkplain #close() closed}.
+     */
+    public final class NodeEventScope implements AutoCloseable {
+        NodeEventScope(NodeEventListener listener) {
+            if (nodeEventListener == null) {
+                nodeEventListener = listener;
+            } else {
+                nodeEventListener = new ChainedNodeEventListener(listener, nodeEventListener);
+            }
+        }
 
-        NodeChangedListener head;
-        NodeChangedListener next;
+        public void close() {
+            assert nodeEventListener != null;
+            if (nodeEventListener instanceof ChainedNodeEventListener) {
+                nodeEventListener = ((ChainedNodeEventListener) nodeEventListener).next;
+            } else {
+                nodeEventListener = null;
+            }
+        }
+    }
 
-        ChainedNodeChangedListener(NodeChangedListener head, NodeChangedListener next) {
+    private static class ChainedNodeEventListener implements NodeEventListener {
+
+        NodeEventListener head;
+        NodeEventListener next;
+
+        ChainedNodeEventListener(NodeEventListener head, NodeEventListener next) {
             this.head = head;
             this.next = next;
         }
 
-        public void nodeChanged(Node node) {
-            head.nodeChanged(node);
-            next.nodeChanged(node);
+        public void nodeAdded(Node node) {
+            head.nodeAdded(node);
+            next.nodeAdded(node);
         }
-    }
 
-    public void trackInputChange(NodeChangedListener listener) {
-        if (inputChangedListener == null) {
-            inputChangedListener = listener;
-        } else {
-            inputChangedListener = new ChainedNodeChangedListener(listener, inputChangedListener);
+        public void inputChanged(Node node) {
+            head.inputChanged(node);
+            next.inputChanged(node);
+        }
+
+        public void usagesDroppedToZero(Node node) {
+            head.inputChanged(node);
+            next.inputChanged(node);
         }
     }
 
-    public void stopTrackingInputChange() {
-        assert inputChangedListener != null;
-        if (inputChangedListener instanceof ChainedNodeChangedListener) {
-            inputChangedListener = ((ChainedNodeChangedListener) inputChangedListener).next;
-        } else {
-            inputChangedListener = null;
-        }
-    }
-
-    public void trackUsagesDroppedZero(NodeChangedListener listener) {
-        if (usagesDroppedToZeroListener == null) {
-            usagesDroppedToZeroListener = listener;
-        } else {
-            usagesDroppedToZeroListener = new ChainedNodeChangedListener(listener, usagesDroppedToZeroListener);
-        }
-    }
-
-    public void stopTrackingUsagesDroppedZero() {
-        assert usagesDroppedToZeroListener != null;
-        if (usagesDroppedToZeroListener instanceof ChainedNodeChangedListener) {
-            usagesDroppedToZeroListener = ((ChainedNodeChangedListener) usagesDroppedToZeroListener).next;
-        } else {
-            usagesDroppedToZeroListener = null;
-        }
+    /**
+     * Registers a given {@link NodeEventListener} with this graph. This should be used in
+     * conjunction with try-with-resources statement as follows:
+     *
+     * <pre>
+     * try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+     *     // make changes to the graph
+     * }
+     * </pre>
+     */
+    public NodeEventScope trackNodeEvents(NodeEventListener listener) {
+        return new NodeEventScope(listener);
     }
 
     /**
@@ -461,6 +516,14 @@
         int getValue() {
             return value;
         }
+
+        /**
+         * Determines if this mark still represents the {@linkplain Graph#getNodeCount() live node
+         * count} of the graph.
+         */
+        public boolean isCurrent() {
+            return value == graph.nodeIdCount();
+        }
     }
 
     /**
@@ -785,6 +848,9 @@
         }
 
         node.id = id;
+        if (nodeEventListener != null) {
+            nodeEventListener.nodeAdded(node);
+        }
         logNodeAdded(node);
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Jun 30 12:02:19 2014 +0200
@@ -27,7 +27,6 @@
 import java.lang.annotation.*;
 import java.util.*;
 
-import com.oracle.graal.graph.Graph.NodeChangedListener;
 import com.oracle.graal.graph.NodeClass.NodeClassIterator;
 import com.oracle.graal.graph.NodeClass.Position;
 import com.oracle.graal.graph.iterators.*;
@@ -559,12 +558,13 @@
                     assert assertTrue(result, "not found in usages, old input: %s", oldInput);
                 }
             }
+            maybeNotifyInputChanged(this);
             if (newInput != null) {
                 if (newInput.recordsUsages()) {
-                    maybeNotifyChanged(this);
                     newInput.addUsage(this);
                 }
-            } else if (oldInput != null && oldInput.recordsUsages() && oldInput.usages().isEmpty()) {
+            }
+            if (oldInput != null && oldInput.recordsUsages() && oldInput.usages().isEmpty()) {
                 maybeNotifyZeroInputs(oldInput);
             }
         }
@@ -628,7 +628,7 @@
             boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
             assert assertTrue(result, "not found in inputs, usage: %s", usage);
             if (other != null) {
-                maybeNotifyChanged(usage);
+                maybeNotifyInputChanged(usage);
                 if (other.recordsUsages()) {
                     other.addUsage(usage);
                 }
@@ -650,7 +650,7 @@
                 boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
                 assert assertTrue(result, "not found in inputs, usage: %s", usage);
                 if (other != null) {
-                    maybeNotifyChanged(usage);
+                    maybeNotifyInputChanged(usage);
                     if (other.recordsUsages()) {
                         other.addUsage(usage);
                     }
@@ -684,22 +684,22 @@
         }
     }
 
-    private void maybeNotifyChanged(Node usage) {
+    private void maybeNotifyInputChanged(Node node) {
         if (graph != null) {
             assert !graph.isFrozen();
-            NodeChangedListener listener = graph.inputChangedListener;
+            NodeEventListener listener = graph.nodeEventListener;
             if (listener != null) {
-                listener.nodeChanged(usage);
+                listener.inputChanged(node);
             }
         }
     }
 
-    private void maybeNotifyZeroInputs(Node oldInput) {
+    private void maybeNotifyZeroInputs(Node node) {
         if (graph != null) {
             assert !graph.isFrozen();
-            NodeChangedListener listener = graph.usagesDroppedToZeroListener;
+            NodeEventListener listener = graph.nodeEventListener;
             if (listener != null) {
-                listener.nodeChanged(oldInput);
+                listener.usagesDroppedToZero(node);
             }
         }
     }
@@ -735,9 +735,7 @@
         }
     }
 
-    public void clearInputs() {
-        assert assertFalse(isDeleted(), "cannot clear inputs of deleted node");
-
+    private void unregisterInputs() {
         for (Node input : inputs()) {
             if (input.recordsUsages()) {
                 removeThisFromUsages(input);
@@ -746,6 +744,12 @@
                 }
             }
         }
+    }
+
+    public void clearInputs() {
+        assert assertFalse(isDeleted(), "cannot clear inputs of deleted node");
+
+        unregisterInputs();
         getNodeClass().clearInputs(this);
     }
 
@@ -753,13 +757,17 @@
         return n.removeUsage(this);
     }
 
-    public void clearSuccessors() {
-        assert assertFalse(isDeleted(), "cannot clear successors of deleted node");
-
+    private void unregisterSuccessors() {
         for (Node successor : successors()) {
             assert assertTrue(successor.predecessor == this, "wrong predecessor in old successor (%s): %s", successor, successor.predecessor);
             successor.predecessor = null;
         }
+    }
+
+    public void clearSuccessors() {
+        assert assertFalse(isDeleted(), "cannot clear successors of deleted node");
+
+        unregisterSuccessors();
         getNodeClass().clearSuccessors(this);
     }
 
@@ -777,8 +785,8 @@
      */
     public void safeDelete() {
         assert checkDeletion();
-        clearInputs();
-        clearSuccessors();
+        unregisterInputs();
+        unregisterSuccessors();
         graph.unregister(this);
         id = DELETED_ID_START - id;
         assert isDeleted();
@@ -801,17 +809,6 @@
     }
 
     /**
-     * Must be overridden by subclasses that implement {@link Canonicalizable}. The implementation
-     * in {@link Node} exists to obviate the need to cast a node before invoking
-     * {@link Canonicalizable#canonical(CanonicalizerTool)}.
-     *
-     * @param tool
-     */
-    public Node canonical(CanonicalizerTool tool) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
      * Must be overridden by subclasses that implement {@link Simplifiable}. The implementation in
      * {@link Node} exists to obviate the need to cast a node before invoking
      * {@link Simplifiable#simplify(SimplifierTool)}.
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -116,7 +116,12 @@
     public NodeClass(Class<?> clazz, CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
         super(clazz);
         assert NODE_CLASS.isAssignableFrom(clazz);
+
         this.isCanonicalizable = Canonicalizable.class.isAssignableFrom(clazz);
+        if (Canonicalizable.Unary.class.isAssignableFrom(clazz) || Canonicalizable.Binary.class.isAssignableFrom(clazz)) {
+            assert Canonicalizable.Unary.class.isAssignableFrom(clazz) ^ Canonicalizable.Binary.class.isAssignableFrom(clazz) : clazz + " should implement either Unary or Binary, not both";
+        }
+
         this.isSimplifiable = Simplifiable.class.isAssignableFrom(clazz);
 
         FieldScanner scanner = new FieldScanner(calcOffset);
@@ -298,9 +303,6 @@
                 }
                 types.put(offset, inputAnnotation.value());
                 names.put(offset, field.getName());
-                if (inputAnnotation.value() != InputType.Value) {
-                    fieldNames.put(offset, field.getName() + "#NDF");
-                }
             } else if (field.isAnnotationPresent(Node.Successor.class)) {
                 if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) {
                     GraalInternalError.guarantee(Modifier.isFinal(field.getModifiers()), "NodeSuccessorList successor field % should be final", field);
@@ -380,6 +382,10 @@
             node.getNodeClass().set(node, this, value);
         }
 
+        void initialize(Node node, Node value) {
+            node.getNodeClass().initializePosition(node, this, value);
+        }
+
         public boolean isValidFor(Node node, Node from) {
             return node.getNodeClass().isValid(this, from.getNodeClass());
         }
@@ -1069,6 +1075,20 @@
         }
     }
 
+    public void initializePosition(Node node, Position pos, Node x) {
+        long offset = pos.isInput() ? inputOffsets[pos.getIndex()] : successorOffsets[pos.getIndex()];
+        if (pos.getSubIndex() == NOT_ITERABLE) {
+            assert x == null || fieldTypes.get((pos.isInput() ? inputOffsets : successorOffsets)[pos.getIndex()]).isAssignableFrom(x.getClass()) : this + ".set(node, pos, " + x + ")";
+            putNode(node, offset, x);
+        } else {
+            NodeList<Node> list = getNodeList(node, offset);
+            while (list.size() <= pos.getSubIndex()) {
+                list.add(null);
+            }
+            list.initialize(pos.getSubIndex(), x);
+        }
+    }
+
     public NodeClassIterable getInputIterable(final Node node) {
         assert getClazz().isInstance(node);
         return new NodeClassIterable() {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeInputList.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeInputList.java	Mon Jun 30 12:02:19 2014 +0200
@@ -49,6 +49,12 @@
         this.self = self;
     }
 
+    public NodeInputList(Node self, Collection<? extends NodeInterface> elements) {
+        super(elements);
+        assert self.usages().isEmpty();
+        this.self = self;
+    }
+
     @Override
     protected void update(T oldNode, T newNode) {
         self.updateUsages(oldNode, newNode);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Mon Jun 30 12:02:19 2014 +0200
@@ -77,6 +77,24 @@
         }
     }
 
+    protected NodeList(Collection<? extends NodeInterface> elements) {
+        if (elements == null || elements.isEmpty()) {
+            this.size = 0;
+            this.nodes = EMPTY_NODE_ARRAY;
+            this.initialSize = 0;
+        } else {
+            this.size = elements.size();
+            this.initialSize = elements.size();
+            this.nodes = new Node[elements.size()];
+            int i = 0;
+            for (NodeInterface n : elements) {
+                this.nodes[i] = n.asNode();
+                assert this.nodes[i] == null || !this.nodes[i].isDeleted();
+                i++;
+            }
+        }
+    }
+
     protected abstract void update(T oldNode, T newNode);
 
     @Override
@@ -136,6 +154,12 @@
         return oldValue;
     }
 
+    void initialize(int index, T node) {
+        incModCount();
+        assert index < size();
+        nodes[index] = node;
+    }
+
     void copy(NodeList<T> other) {
         incModCount();
         nodes = Arrays.copyOf(other.nodes, other.size);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Mon Jun 30 12:02:19 2014 +0200
@@ -50,6 +50,8 @@
 
     public abstract void add(Node node);
 
+    public abstract boolean contains(Node node);
+
     private abstract class QueueConsumingIterator implements Iterator<Node> {
 
         protected void dropDeleted() {
@@ -140,6 +142,20 @@
             }
         }
 
+        @Override
+        public boolean contains(Node node) {
+            if (inQueue != null) {
+                return inQueue.isMarked(node);
+            } else {
+                for (Node queuedNode : worklist) {
+                    if (queuedNode == node) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        }
+
         private boolean checkInfiniteWork(Node node) {
             if (lastPull == node) {
                 if (firstNoChange == null) {
@@ -186,6 +202,11 @@
         }
 
         @Override
+        public boolean contains(Node node) {
+            return visited.isMarked(node);
+        }
+
+        @Override
         public Iterator<Node> iterator() {
             return new QueueConsumingIterator() {
                 @Override
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/Canonicalizable.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/Canonicalizable.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -22,9 +22,110 @@
  */
 package com.oracle.graal.graph.spi;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 
+/**
+ * Nodes can implement {@link Canonicalizable} or one of the two sub-interfaces {@link Unary} and
+ * {@link Binary} to provide local optimizations like constant folding and strength reduction.
+ * Implementations should return a replacement that is always semantically correct for the given
+ * inputs, or "this" if they do not see an opportunity for improvement.<br/>
+ * <br/>
+ * <b>Implementations of {@link Canonicalizable#canonical(CanonicalizerTool)} or the equivalent
+ * methods of the two sub-interfaces must not have any side effects.</b><br/>
+ * They are not allowed to change inputs, successors or properties of any node (including the
+ * current one) and they also cannot add new nodes to the graph.<br/>
+ * <br/>
+ * In addition to pre-existing nodes they can return newly created nodes, which will be added to the
+ * graph automatically if (and only if) the effects of the canonicalization are committed.
+ * Non-cyclic graphs (DAGs) of newly created nodes (i.e., one newly created node with an input to
+ * another newly created node) will be handled correctly.
+ */
 public interface Canonicalizable {
 
+    /**
+     * Implementations of this method can provide local optimizations like constant folding and
+     * strength reduction. Implementations should look at the properties and inputs of the current
+     * node and determine if there is a more optimal and always semantically correct replacement.<br/>
+     * The return value determines the effect that the canonicalization will have:
+     * <ul>
+     * <li>Returning an pre-existing node will replace the current node with the given one.</li>
+     * <li>Returning a newly created node (that was not yet added to the graph) will replace the
+     * current node with the given one, after adding it to the graph. If both the replacement and
+     * the replacee are anchored in control flow (fixed nodes), the replacement will be added to the
+     * control flow. It is invalid to replace a non-fixed node with a newly created fixed node
+     * (because its placement in the control flow cannot be determined without scheduling).</li>
+     * <li>Returning {@code null} will delete the current node and replace it with {@code null} at
+     * all usages. Note that it is not necessary to delete floating nodes that have no more usages
+     * this way - they will be deleted automatically.</li>
+     * </ul>
+     *
+     * @param tool provides access to runtime interfaces like {@link MetaAccessProvider}
+     */
     Node canonical(CanonicalizerTool tool);
+
+    /**
+     * This sub-interface of {@link Canonicalizable} is intended for nodes that have exactly one
+     * input. It has an additional {@link #canonical(CanonicalizerTool, Node)} method that looks at
+     * the given input instead of the current input of the node - which can be used to ask
+     * "what if this input is change to this node" - questions.
+     *
+     * @param <T> the common supertype of all inputs of this node
+     */
+    public interface Unary<T extends Node> extends Canonicalizable {
+
+        /**
+         * Similar to {@link Canonicalizable#canonical(CanonicalizerTool)}, except that
+         * implementations should act as if the current input of the node was the given one, i.e.,
+         * they should never look at the inputs via the this pointer.
+         */
+        Node canonical(CanonicalizerTool tool, T forValue);
+
+        /**
+         * Gets the current value of the input, so that calling
+         * {@link #canonical(CanonicalizerTool, Node)} with the value returned from this method
+         * should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}.
+         */
+        T getValue();
+
+        default Node canonical(CanonicalizerTool tool) {
+            return canonical(tool, getValue());
+        }
+    }
+
+    /**
+     * This sub-interface of {@link Canonicalizable} is intended for nodes that have exactly two
+     * inputs. It has an additional {@link #canonical(CanonicalizerTool, Node, Node)} method that
+     * looks at the given inputs instead of the current inputs of the node - which can be used to
+     * ask "what if this input is change to this node" - questions.
+     *
+     * @param <T> the common supertype of all inputs of this node
+     */
+    public interface Binary<T extends Node> extends Canonicalizable {
+
+        /**
+         * Similar to {@link Canonicalizable#canonical(CanonicalizerTool)}, except that
+         * implementations should act as if the current input of the node was the given one, i.e.,
+         * they should never look at the inputs via the this pointer.
+         */
+        Node canonical(CanonicalizerTool tool, T forX, T forY);
+
+        /**
+         * Gets the current value of the input, so that calling
+         * {@link #canonical(CanonicalizerTool, Node, Node)} with the value returned from this
+         * method should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}.
+         */
+        T getX();
+
+        /**
+         * Gets the current value of the input, so that calling
+         * {@link #canonical(CanonicalizerTool, Node, Node)} with the value returned from this
+         * method should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}.
+         */
+        T getY();
+
+        default Node canonical(CanonicalizerTool tool) {
+            return canonical(tool, getX(), getY());
+        }
+    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/CanonicalizerTool.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/CanonicalizerTool.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 
 public interface CanonicalizerTool {
 
@@ -35,6 +34,4 @@
     ConstantReflectionProvider getConstantReflection();
 
     boolean canonicalizeReads();
-
-    void removeIfUnused(Node node);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/DefaultCanonicalizerTool.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011, 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.graph.spi;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+
+public class DefaultCanonicalizerTool implements CanonicalizerTool {
+
+    private final Assumptions assumptions;
+    private final MetaAccessProvider metaAccess;
+    private final ConstantReflectionProvider constantReflection;
+    private final boolean canonicalizeReads;
+
+    public DefaultCanonicalizerTool(Assumptions assumptions, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean canonicalizeReads) {
+        this.assumptions = assumptions;
+        this.metaAccess = metaAccess;
+        this.constantReflection = constantReflection;
+        this.canonicalizeReads = canonicalizeReads;
+    }
+
+    public Assumptions assumptions() {
+        return assumptions;
+    }
+
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    public ConstantReflectionProvider getConstantReflection() {
+        return constantReflection;
+    }
+
+    public boolean canonicalizeReads() {
+        return canonicalizeReads;
+    }
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/SimplifierTool.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/SimplifierTool.java	Mon Jun 30 12:02:19 2014 +0200
@@ -35,4 +35,8 @@
      * Adds a node to the worklist independent of whether it has already been on the worklist.
      */
     void addToWorkList(Node node);
+
+    void addToWorkList(Iterable<? extends Node> nodes);
+
+    void removeIfUnused(Node node);
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -92,7 +92,7 @@
         final int stackFrameAlignment = 16;
         final int implicitNullCheckLimit = 4096;
         final boolean inlineObjects = true;
-        return new HotSpotTargetDescription(createArchitecture(config), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects, Kind.Int);
+        return new HotSpotTargetDescription(createArchitecture(config), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java	Mon Jun 30 12:02:19 2014 +0200
@@ -64,7 +64,7 @@
                 }
             }
         }
-        params[params.length - 1] = rbp.asValue(Kind.Long);
+        params[params.length - 1] = rbp.asValue(LIRKind.value(Kind.Long));
 
         gen.emitIncomingValues(params);
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompare.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompare.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,7 +30,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.data.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.amd64.AMD64Move.MemOp;
@@ -38,33 +37,6 @@
 
 public class AMD64HotSpotCompare {
 
-    @Opcode("NCMP")
-    public static class HotSpotCompareNarrowOp extends AMD64LIRInstruction {
-
-        @Use({REG}) protected AllocatableValue x;
-        @Use({REG, STACK}) protected AllocatableValue y;
-
-        public HotSpotCompareNarrowOp(AllocatableValue x, AllocatableValue y) {
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            if (isRegister(y)) {
-                masm.cmpl(asRegister(x), asRegister(y));
-            } else {
-                assert isStackSlot(y);
-                masm.cmpl(asRegister(x), (AMD64Address) crb.asAddress(y));
-            }
-        }
-
-        @Override
-        protected void verify() {
-            assert x.getPlatformKind() == NarrowOopStamp.NarrowOop && y.getPlatformKind() == NarrowOopStamp.NarrowOop;
-        }
-    }
-
     @Opcode("CMP")
     public static class HotSpotCompareConstantOp extends AMD64LIRInstruction {
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -43,7 +43,7 @@
      * initial LIR generation is finished. Until then, we use a placeholder variable so that LIR
      * verification is successful.
      */
-    private static final Variable PLACEHOLDER = new Variable(Kind.Long, Integer.MAX_VALUE);
+    private static final Variable PLACEHOLDER = new Variable(LIRKind.value(Kind.Long), Integer.MAX_VALUE);
 
     @Use({REG, STACK}) protected AllocatableValue savedRbp = PLACEHOLDER;
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Mon Jun 30 12:02:19 2014 +0200
@@ -56,8 +56,8 @@
         // The calling convention for the exception handler stub is (only?) defined in
         // TemplateInterpreterGenerator::generate_throw_exception()
         // in templateInterpreter_x86_64.cpp around line 1923
-        RegisterValue exception = rax.asValue(Kind.Object);
-        RegisterValue exceptionPc = rdx.asValue(word);
+        RegisterValue exception = rax.asValue(LIRKind.reference(Kind.Object));
+        RegisterValue exceptionPc = rdx.asValue(LIRKind.value(word));
         CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc);
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION));
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -26,37 +26,30 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import java.util.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.HotSpotStoreConstantOp;
-import com.oracle.graal.hotspot.data.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.NoOp;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
 import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LoadOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
-import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
-import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.gen.*;
 
 /**
@@ -92,7 +85,7 @@
 
         public SaveRbp(NoOp placeholder) {
             this.placeholder = placeholder;
-            this.reservedSlot = getResult().getFrameMap().allocateSpillSlot(Kind.Long);
+            this.reservedSlot = getResult().getFrameMap().allocateSpillSlot(LIRKind.value(Kind.Long));
             assert reservedSlot.getRawOffset() == -16 : reservedSlot.getRawOffset();
         }
 
@@ -107,10 +100,10 @@
                 dst = reservedSlot;
             } else {
                 getResult().getFrameMap().freeSpillSlot(reservedSlot);
-                dst = newVariable(Kind.Long);
+                dst = newVariable(LIRKind.value(Kind.Long));
             }
 
-            placeholder.replace(getResult().getLIR(), new MoveFromRegOp(Kind.Long, dst, rbp.asValue(Kind.Long)));
+            placeholder.replace(getResult().getLIR(), new MoveFromRegOp(Kind.Long, dst, rbp.asValue(LIRKind.value(Kind.Long))));
             return dst;
         }
     }
@@ -161,7 +154,7 @@
     public void emitReturn(Value input) {
         AllocatableValue operand = Value.ILLEGAL;
         if (input != null) {
-            operand = resultOperandFor(input.getKind());
+            operand = resultOperandFor(input.getLIRKind());
             emitMove(operand, input);
         }
         if (pollOnReturnScratchRegister == null) {
@@ -235,7 +228,7 @@
         for (int i = 0; i < savedRegisters.length; i++) {
             PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
             assert kind != Kind.Illegal;
-            StackSlot spillSlot = getResult().getFrameMap().allocateSpillSlot(kind);
+            StackSlot spillSlot = getResult().getFrameMap().allocateSpillSlot(LIRKind.value(kind));
             savedRegisterLocations[i] = spillSlot;
         }
         return emitSaveRegisters(savedRegisters, savedRegisterLocations, supportsRemove);
@@ -311,7 +304,7 @@
 
         Register thread = getProviders().getRegisters().getThreadRegister();
         append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
-        Variable result = super.emitForeignCall(linkage, null, thread.asValue(Kind.Long), trapRequest);
+        Variable result = super.emitForeignCall(linkage, null, thread.asValue(LIRKind.value(Kind.Long)), trapRequest);
         append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
 
         Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((AMD64HotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo();
@@ -326,7 +319,7 @@
 
         Register thread = getProviders().getRegisters().getThreadRegister();
         append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
-        Variable result = super.emitForeignCall(linkage, null, thread.asValue(Kind.Long));
+        Variable result = super.emitForeignCall(linkage, null, thread.asValue(LIRKind.value(Kind.Long)));
         append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
 
         Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((AMD64HotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo();
@@ -393,10 +386,10 @@
     }
 
     private void moveValueToThread(Value v, int offset) {
-        Kind wordKind = getProviders().getCodeCache().getTarget().wordKind;
+        LIRKind wordKind = LIRKind.value(getProviders().getCodeCache().getTarget().wordKind);
         RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
-        AMD64AddressValue address = new AMD64AddressValue(v.getKind(), thread, offset);
-        emitStore(v.getKind(), address, v, null);
+        AMD64AddressValue address = new AMD64AddressValue(wordKind, thread, offset);
+        emitStore(v.getLIRKind(), address, v, null);
     }
 
     @Override
@@ -417,7 +410,7 @@
         boolean hasDebugInfo = getResult().getLIR().hasDebugInfo();
         AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo);
         if (hasDebugInfo) {
-            ((AMD64HotSpotLIRGenerationResult) getResult()).setDeoptimizationRescueSlot(getResult().getFrameMap().allocateSpillSlot(Kind.Long));
+            ((AMD64HotSpotLIRGenerationResult) getResult()).setDeoptimizationRescueSlot(getResult().getFrameMap().allocateSpillSlot(LIRKind.value(Kind.Long)));
         }
 
         for (AMD64HotSpotEpilogueOp op : epilogueOps) {
@@ -441,17 +434,10 @@
         }
     }
 
-    private static Kind getMemoryKind(PlatformKind kind) {
-        if (kind == NarrowOopStamp.NarrowOop) {
-            return Kind.Int;
-        } else {
-            return (Kind) kind;
-        }
-    }
-
-    private static PlatformKind toStackKind(PlatformKind kind) {
-        if (kind instanceof Kind) {
-            return ((Kind) kind).getStackKind();
+    private static LIRKind toStackKind(LIRKind kind) {
+        if (kind.getPlatformKind() instanceof Kind) {
+            Kind stackKind = ((Kind) kind.getPlatformKind()).getStackKind();
+            return kind.changeType(stackKind);
         } else {
             return kind;
         }
@@ -466,36 +452,39 @@
     }
 
     @Override
-    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
+    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
         AMD64AddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(toStackKind(kind));
-        append(new LoadOp(getMemoryKind(kind), result, loadAddress, state));
+        append(new LoadOp((Kind) kind.getPlatformKind(), result, loadAddress, state));
         return result;
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
+    public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) {
         AMD64AddressValue storeAddress = asAddressValue(address);
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
             if (canStoreConstant(c)) {
-                append(new HotSpotStoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
+                append(new HotSpotStoreConstantOp((Kind) kind.getPlatformKind(), storeAddress, c, state));
                 return;
             }
         }
         Variable input = load(inputVal);
-        append(new StoreOp(getMemoryKind(kind), storeAddress, input, state));
+        append(new StoreOp((Kind) kind.getPlatformKind(), storeAddress, input, state));
     }
 
     @Override
     public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
-        if (pointer.getPlatformKind() == Kind.Object) {
-            Variable result = newVariable(NarrowOopStamp.NarrowOop);
+        LIRKind inputKind = pointer.getLIRKind();
+        assert inputKind.getPlatformKind() == Kind.Long || inputKind.getPlatformKind() == Kind.Object;
+        if (inputKind.isReference(0)) {
+            // oop
+            Variable result = newVariable(LIRKind.reference(Kind.Int));
             append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
             return result;
         } else {
-            assert pointer.getPlatformKind() == Kind.Long;
-            Variable result = newVariable(Kind.Int);
+            // metaspace pointer
+            Variable result = newVariable(LIRKind.value(Kind.Int));
             AllocatableValue base = Value.ILLEGAL;
             if (encoding.base != 0) {
                 base = emitMove(Constant.forLong(encoding.base));
@@ -507,13 +496,16 @@
 
     @Override
     public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
-        if (pointer.getPlatformKind() == NarrowOopStamp.NarrowOop) {
-            Variable result = newVariable(Kind.Object);
+        LIRKind inputKind = pointer.getLIRKind();
+        assert inputKind.getPlatformKind() == Kind.Int;
+        if (inputKind.isReference(0)) {
+            // oop
+            Variable result = newVariable(LIRKind.reference(Kind.Object));
             append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
             return result;
         } else {
-            assert pointer.getPlatformKind() == Kind.Int;
-            Variable result = newVariable(Kind.Long);
+            // metaspace pointer
+            Variable result = newVariable(LIRKind.value(Kind.Long));
             AllocatableValue base = Value.ILLEGAL;
             if (encoding.base != 0) {
                 base = emitMove(Constant.forLong(encoding.base));
@@ -527,115 +519,45 @@
     protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) {
         if (src instanceof Constant) {
             return new AMD64HotSpotMove.HotSpotLoadConstantOp(dst, (Constant) src);
-        } else if (dst.getPlatformKind() == NarrowOopStamp.NarrowOop) {
-            if (isRegister(src) || isStackSlot(dst)) {
-                return new MoveFromRegOp(Kind.Int, dst, src);
-            } else {
-                return new MoveToRegOp(Kind.Int, dst, src);
-            }
         } else {
             return super.createMove(dst, src);
         }
     }
 
     public Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
-        PlatformKind kind = newValue.getPlatformKind();
-        assert kind == expectedValue.getPlatformKind();
-        Kind memKind = getMemoryKind(kind);
+        LIRKind kind = newValue.getLIRKind();
+        assert kind.equals(expectedValue.getLIRKind());
+        Kind memKind = (Kind) kind.getPlatformKind();
 
         AMD64AddressValue addressValue = asAddressValue(address);
         RegisterValue raxRes = AMD64.rax.asValue(kind);
         emitMove(raxRes, expectedValue);
         append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
 
-        assert trueValue.getPlatformKind() == falseValue.getPlatformKind();
-        Variable result = newVariable(trueValue.getPlatformKind());
+        assert trueValue.getLIRKind().equals(falseValue.getLIRKind());
+        Variable result = newVariable(trueValue.getLIRKind());
         append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
         return result;
     }
 
     public Value emitAtomicReadAndAdd(Value address, Value delta) {
-        PlatformKind kind = delta.getPlatformKind();
-        Kind memKind = getMemoryKind(kind);
+        LIRKind kind = delta.getLIRKind();
+        Kind memKind = (Kind) kind.getPlatformKind();
         Variable result = newVariable(kind);
         AMD64AddressValue addressValue = asAddressValue(address);
         append(new AMD64Move.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta)));
         return result;
     }
 
-    public static Register asNarrowReg(Value value) {
-        if (value.getPlatformKind() != NarrowOopStamp.NarrowOop) {
-            throw new InternalError("needed NarrowOop got: " + value.getKind());
-        } else {
-            return asRegister(value);
-        }
-    }
-
     public Value emitAtomicReadAndWrite(Value address, Value newValue) {
-        PlatformKind kind = newValue.getPlatformKind();
-        Kind memKind = getMemoryKind(kind);
+        LIRKind kind = newValue.getLIRKind();
+        Kind memKind = (Kind) kind.getPlatformKind();
         Variable result = newVariable(kind);
         AMD64AddressValue addressValue = asAddressValue(address);
         append(new AMD64Move.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue)));
         return result;
     }
 
-    public static class CompareMemoryCompressedOp extends AMD64LIRInstruction {
-        @Alive({COMPOSITE}) protected AMD64AddressValue x;
-        @Use({CONST, REG}) protected Value y;
-        @State protected LIRFrameState state;
-
-        public CompareMemoryCompressedOp(AMD64AddressValue x, Value y, LIRFrameState state) {
-            assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops;
-            this.x = x;
-            this.y = y;
-            this.state = state;
-        }
-
-        @Override
-        protected void verify() {
-            assert y instanceof Constant || y.getPlatformKind() == NarrowOopStamp.NarrowOop;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            if (state != null) {
-                crb.recordImplicitException(masm.position(), state);
-            }
-            if (y instanceof Constant) {
-                Constant constant = (Constant) y;
-                if (constant.isNull()) {
-                    masm.cmpl(x.toAddress(), 0);
-                } else {
-                    if (y.getKind() == Kind.Object) {
-                        crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(constant), true));
-                    } else if (y.getKind() == Kind.Long) {
-                        crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(constant), true));
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere();
-                    }
-                    masm.cmpl(x.toAddress(), 0xdeaddead);
-                }
-            } else {
-                masm.cmpl(asNarrowReg(y), x.toAddress());
-            }
-        }
-    }
-
-    protected void emitCompareBranchMemoryCompressed(Value left, Value right, Condition cond, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability, LIRFrameState state) {
-        boolean mirrored = false;
-        if (left instanceof AMD64AddressValue) {
-            append(new CompareMemoryCompressedOp((AMD64AddressValue) left, right, state));
-        } else {
-            assert right instanceof AMD64AddressValue;
-            append(new CompareMemoryCompressedOp((AMD64AddressValue) right, left, state));
-            mirrored = true;
-        }
-
-        Condition finalCondition = mirrored ? cond.mirror() : cond;
-        append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
-    }
-
     public void emitNullCheck(Value address, LIRFrameState state) {
         assert address.getKind() == Kind.Object : address + " - " + address.getKind() + " not an object!";
         append(new AMD64Move.NullCheckOp(load(address), state));
@@ -645,8 +567,6 @@
     protected void emitCompareOp(PlatformKind cmpKind, Variable left, Value right) {
         if (right instanceof HotSpotConstant) {
             append(new AMD64HotSpotCompare.HotSpotCompareConstantOp(left, (Constant) right));
-        } else if (cmpKind == NarrowOopStamp.NarrowOop) {
-            append(new AMD64HotSpotCompare.HotSpotCompareNarrowOp(left, asAllocatable(right)));
         } else {
             super.emitCompareOp(cmpKind, left, right);
         }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -30,9 +30,9 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
-import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.debug.*;
@@ -63,49 +63,19 @@
             result = ((PiNode) result).getOriginalNode();
         }
         if (result instanceof CompressionNode) {
-            result = ((CompressionNode) result).getInput();
+            result = ((CompressionNode) result).getValue();
         }
         return result;
     }
 
-    private void emitCompareMemoryObject(IfNode ifNode, ValueNode valueNode, Access access, CompareNode compare) {
-        Value value;
-        // This works by embedding the compressed form for constants, so force a constant instead of
-        // respecting what operand() would return.
-        if (valueNode.isConstant()) {
-            value = valueNode.asConstant();
-        } else {
-            value = gen.load(operand(valueNode));
-        }
-        AMD64AddressValue address = makeAddress(access);
-
-        Condition cond = compare.condition();
-        Value left;
-        Value right;
-        if (access == filterCompression(compare.x())) {
-            left = value;
-            right = address;
-        } else {
-            assert access == filterCompression(compare.y());
-            left = address;
-            right = value;
-            cond = cond.mirror();
-        }
-
-        LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
-        LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
-        double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
-        getGen().emitCompareBranchMemoryCompressed(left, right, cond, trueLabel, falseLabel, trueLabelProbability, getState(access));
-    }
-
     private void emitCompareCompressedMemory(Kind kind, IfNode ifNode, ValueNode valueNode, CompressionNode compress, ConstantLocationNode location, Access access, CompareNode compare) {
         Value value = gen.load(operand(valueNode));
         AMD64AddressValue address = makeCompressedAddress(compress, location);
         Condition cond = compare.condition();
-        if (access == filterCompression(compare.x())) {
+        if (access == filterCompression(compare.getX())) {
             cond = cond.mirror();
         } else {
-            assert access == filterCompression(compare.y());
+            assert access == filterCompression(compare.getY());
         }
 
         LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
@@ -135,7 +105,7 @@
 
     @Override
     protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeMap<Value> nodeOperands) {
-        HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMap(), Kind.Long);
+        HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMap(), LIRKind.value(Kind.Long));
         return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
     }
 
@@ -154,7 +124,7 @@
                 }
             }
         }
-        params[params.length - 1] = rbp.asValue(Kind.Long);
+        params[params.length - 1] = rbp.asValue(LIRKind.value(Kind.Long));
 
         gen.emitIncomingValues(params);
 
@@ -237,38 +207,28 @@
 
     @Override
     public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
-        Kind kind = x.newValue().getKind();
-        assert kind == x.expectedValue().getKind();
-
         Value expected = gen.loadNonConst(operand(x.expectedValue()));
         Variable newVal = gen.load(operand(x.newValue()));
+        assert expected.getLIRKind().equals(newVal.getLIRKind());
 
-        int disp = 0;
-        AMD64AddressValue address;
-        Value index = operand(x.offset());
-        if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) {
-            assert !gen.getCodeCache().needsDataPatch(asConstant(index));
-            disp += (int) ValueUtil.asConstant(index).asLong();
-            address = new AMD64AddressValue(kind, gen.load(operand(x.object())), disp);
-        } else {
-            address = new AMD64AddressValue(kind, gen.load(operand(x.object())), gen.load(index), Scale.Times1, disp);
-        }
+        AMD64AddressValue address = getGen().emitAddress(operand(x.object()), 0, operand(x.offset()), 1);
 
-        RegisterValue raxLocal = AMD64.rax.asValue(kind);
+        RegisterValue raxLocal = AMD64.rax.asValue(expected.getLIRKind());
         gen.emitMove(raxLocal, expected);
-        append(new CompareAndSwapOp(kind, raxLocal, address, raxLocal, newVal));
+        append(new CompareAndSwapOp(expected.getKind(), raxLocal, address, raxLocal, newVal));
 
-        Variable result = newVariable(x.getKind());
-        gen.emitMove(result, raxLocal);
-        setResult(x, result);
+        setResult(x, gen.emitMove(raxLocal));
     }
 
     boolean canFormCompressedMemory(CompressionNode compress, ConstantLocationNode location) {
         HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig();
         if (config.useCompressedOops && compress.getEncoding().shift <= 3 && NumUtil.isInt(location.getDisplacement())) {
-            PlatformKind objectKind = compress.getInput().stamp().getPlatformKind(getGen());
-            if (objectKind == NarrowOopStamp.NarrowOop || objectKind == Kind.Int && config.narrowKlassBase == config.narrowOopBase) {
+            Stamp compressedStamp = compress.getValue().stamp();
+            if (compressedStamp instanceof NarrowOopStamp) {
                 return true;
+            } else if (compressedStamp instanceof IntegerStamp) {
+                IntegerStamp is = (IntegerStamp) compressedStamp;
+                return is.getBits() == 32 && config.narrowKlassBase == config.narrowOopBase;
             }
         }
         return false;
@@ -276,29 +236,11 @@
 
     private AMD64AddressValue makeCompressedAddress(CompressionNode compress, ConstantLocationNode location) {
         assert canFormCompressedMemory(compress, location);
-        AMD64AddressValue address = getGen().emitAddress(getGen().getProviders().getRegisters().getHeapBaseRegister().asValue(), location.getDisplacement(), operand(compress.getInput()),
+        AMD64AddressValue address = getGen().emitAddress(getGen().getProviders().getRegisters().getHeapBaseRegister().asValue(), location.getDisplacement(), operand(compress.getValue()),
                         1 << compress.getEncoding().shift);
         return address;
     }
 
-    @MatchRule("(If (ObjectEquals=compare Constant=value (Pi (Compression Read=access))))")
-    @MatchRule("(If (ObjectEquals=compare Constant=value (Pi (Compression FloatingRead=access))))")
-    @MatchRule("(If (ObjectEquals=compare (Compression value) (Pi (Compression Read=access))))")
-    @MatchRule("(If (ObjectEquals=compare (Compression value) (Pi (Compression FloatingRead=access))))")
-    @MatchRule("(If (ObjectEquals=compare Constant=value (Compression Read=access)))")
-    @MatchRule("(If (ObjectEquals=compare Constant=value (Compression FloatingRead=access)))")
-    @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression Read=access)))")
-    @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression FloatingRead=access)))")
-    public ComplexMatchResult ifCompareMemoryObject(IfNode root, CompareNode compare, ValueNode value, Access access) {
-        if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
-            return builder -> {
-                emitCompareMemoryObject(root, value, access, compare);
-                return null;
-            };
-        }
-        return null;
-    }
-
     @MatchRule("(If (IntegerEquals=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
     @MatchRule("(If (IntegerLessThan=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
     @MatchRule("(If (IntegerBelowThan=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
@@ -311,7 +253,7 @@
     @MatchRule("(If (FloatLessThan=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
     public ComplexMatchResult ifCompareCompressedMemory(IfNode root, CompareNode compare, CompressionNode compress, ValueNode value, ConstantLocationNode location, Access access) {
         if (canFormCompressedMemory(compress, location)) {
-            PlatformKind cmpKind = gen.getPlatformKind(compare.x().stamp());
+            PlatformKind cmpKind = gen.getLIRKind(compare.getX().stamp()).getPlatformKind();
             if (cmpKind instanceof Kind) {
                 Kind kind = (Kind) cmpKind;
                 return builder -> {
@@ -358,7 +300,7 @@
     @MatchRule("(FloatingRead (Pi (Compression=compress object)) ConstantLocation=location)")
     public ComplexMatchResult readCompressed(Access root, CompressionNode compress, ConstantLocationNode location) {
         if (canFormCompressedMemory(compress, location)) {
-            PlatformKind readKind = getGen().getPlatformKind(root.asNode().stamp());
+            LIRKind readKind = getGen().getLIRKind(root.asNode().stamp());
             return builder -> {
                 return getGen().emitLoad(readKind, makeCompressedAddress(compress, location), getState(root));
             };
@@ -370,7 +312,7 @@
     @MatchRule("(Write (Pi (Compression=compress object)) ConstantLocation=location value)")
     public ComplexMatchResult writeCompressed(Access root, CompressionNode compress, ConstantLocationNode location, ValueNode value) {
         if (canFormCompressedMemory(compress, location)) {
-            PlatformKind readKind = getGen().getPlatformKind(value.asNode().stamp());
+            LIRKind readKind = getGen().getLIRKind(value.asNode().stamp());
             return builder -> {
                 getGen().emitStore(readKind, makeCompressedAddress(compress, location), operand(value), getState(root));
                 return null;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Mon Jun 30 12:02:19 2014 +0200
@@ -33,7 +33,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 
 public class AMD64HotSpotRegisterConfig implements RegisterConfig {
 
@@ -70,16 +69,9 @@
             return categorized.get(kind);
         }
 
-        PlatformKind primitiveKind;
-        if (kind == NarrowOopStamp.NarrowOop) {
-            primitiveKind = Kind.Int;
-        } else {
-            primitiveKind = kind;
-        }
-
         ArrayList<Register> list = new ArrayList<>();
         for (Register reg : getAllocatableRegisters()) {
-            if (architecture.canStoreValue(reg.getRegisterCategory(), primitiveKind)) {
+            if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) {
                 list.add(reg);
             }
         }
@@ -222,14 +214,14 @@
                 case Object:
                     if (!stackOnly && currentGeneral < generalParameterRegisters.length) {
                         Register register = generalParameterRegisters[currentGeneral++];
-                        locations[i] = register.asValue(kind);
+                        locations[i] = register.asValue(target.getLIRKind(kind));
                     }
                     break;
                 case Float:
                 case Double:
                     if (!stackOnly && currentXMM < xmmParameterRegisters.length) {
                         Register register = xmmParameterRegisters[currentXMM++];
-                        locations[i] = register.asValue(kind);
+                        locations[i] = register.asValue(target.getLIRKind(kind));
                     }
                     break;
                 default:
@@ -237,13 +229,13 @@
             }
 
             if (locations[i] == null) {
-                locations[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, !type.out);
+                locations[i] = StackSlot.get(target.getLIRKind(kind.getStackKind()), currentStackOffset, !type.out);
                 currentStackOffset += Math.max(target.getSizeInBytes(kind), target.wordSize);
             }
         }
 
         Kind returnKind = returnType == null ? Kind.Void : returnType.getKind();
-        AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(returnKind.getStackKind());
+        AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(target.getLIRKind(returnKind.getStackKind()));
         return new CallingConvention(currentStackOffset, returnLocation, locations);
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -51,7 +51,7 @@
         this.state = state;
         this.config = config;
         if (isPollingPageFar(config) || ImmutableCode.getValue()) {
-            temp = tool.getLIRGeneratorTool().newVariable(tool.getLIRGeneratorTool().target().wordKind);
+            temp = tool.getLIRGeneratorTool().newVariable(LIRKind.value(tool.getLIRGeneratorTool().target().wordKind));
         } else {
             // Don't waste a register if it's unneeded
             temp = Value.ILLEGAL;
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/ForEachToGraal.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/ForEachToGraal.java	Mon Jun 30 12:02:19 2014 +0200
@@ -26,15 +26,20 @@
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.GraalInternalError;
 import com.oracle.graal.compiler.hsail.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.gpu.*;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hsail.*;
 import com.oracle.graal.java.*;
@@ -55,11 +60,54 @@
         return (HSAILHotSpotBackend) backend;
     }
 
+    ConcurrentHashMap<Class<?>, String> resolvedConsumerTargetMethods = new ConcurrentHashMap<>();
+
     /**
-     * Gets a compiled and installed kernel for the lambda called by the {@code accept(int value)}
-     * method in a class implementing {@code java.util.function.IntConsumer}.
-     * 
-     * @param intConsumerClass a class implementing {@code java.util.function.IntConsumer}
+     * Returns the name of the reduction method given a class implementing {@link IntConsumer}.
+     *
+     * @param opClass a class implementing {@link IntConsumer}.
+     * @return the name of the reduction method
+     */
+    public String getIntReduceTargetName(Class<?> opClass) {
+        String cachedMethodName = resolvedConsumerTargetMethods.get(Objects.requireNonNull(opClass));
+        if (cachedMethodName != null) {
+            return cachedMethodName;
+        } else {
+            Method acceptMethod = null;
+            for (Method m : opClass.getMethods()) {
+                if (m.getName().equals("applyAsInt")) {
+                    assert acceptMethod == null : "found more than one implementation of applyAsInt in " + opClass;
+                    acceptMethod = m;
+                }
+            }
+            // Ensure a debug configuration for this thread is initialized
+            if (DebugScope.getConfig() == null) {
+                DebugEnvironment.initialize(System.out);
+            }
+
+            HSAILHotSpotBackend backend = getHSAILBackend();
+            Providers providers = backend.getProviders();
+            StructuredGraph graph = new StructuredGraph(((HotSpotMetaAccessProvider) providers.getMetaAccess()).lookupJavaMethod(acceptMethod));
+            new GraphBuilderPhase.Instance(providers.getMetaAccess(), GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL).apply(graph);
+            NodeIterable<MethodCallTargetNode> calls = graph.getNodes(MethodCallTargetNode.class);
+            assert calls.count() == 1;
+            ResolvedJavaMethod lambdaMethod = calls.first().targetMethod();
+            Debug.log("target ... %s", lambdaMethod);
+
+            String className = lambdaMethod.getDeclaringClass().getName();
+            if (!className.equals("Ljava/lang/Integer;")) {
+                return null;
+            }
+            resolvedConsumerTargetMethods.put(opClass, lambdaMethod.getName());
+            return lambdaMethod.getName().intern();
+        }
+    }
+
+    /**
+     * Gets a compiled and installed kernel for the lambda called by the
+     * {@link IntConsumer#accept(int)} method in a class implementing {@link IntConsumer}.
+     *
+     * @param intConsumerClass a class implementing {@link IntConsumer}
      * @return a {@link HotSpotNmethod} handle to the compiled and installed kernel
      */
     private static HotSpotNmethod getCompiledLambda(Class<?> intConsumerClass) {
@@ -108,6 +156,38 @@
     }
 
     @Override
+    public Object createKernelFromHsailString(String code, String methodName) {
+        ExternalCompilationResult hsailCode = new ExternalCompilationResult();
+        try (Debug.Scope ds = Debug.scope("GeneratingKernelBinary")) {
+
+            HSAILHotSpotBackend backend = getHSAILBackend();
+            Providers providers = backend.getProviders();
+            Method integerOffloadMethod = null;
+
+            for (Method m : Integer.class.getMethods()) {
+                if (m.getName().equals(methodName)) {
+                    integerOffloadMethod = m;
+                    break;
+                }
+            }
+            if (integerOffloadMethod != null) {
+                ResolvedJavaMethod rm = ((HotSpotMetaAccessProvider) providers.getMetaAccess()).lookupJavaMethod(integerOffloadMethod);
+
+                long kernel = HSAILHotSpotBackend.generateKernel(code.getBytes(), "Integer::" + methodName);
+                if (kernel == 0) {
+                    throw new GraalInternalError("Failed to compile HSAIL kernel from String");
+                }
+                hsailCode.setEntryPoint(kernel);
+                return backend.installKernel(rm, hsailCode); // is a HotSpotNmethod
+            } else {
+                return null;
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    @Override
     public boolean dispatchKernel(Object kernel, int jobSize, Object[] args) {
         HotSpotNmethod code = (HotSpotNmethod) kernel;
         if (code != null) {
@@ -125,4 +205,258 @@
             return false;
         }
     }
+
+    /**
+     * Running with a larger global size seems to increase the performance for sum, but it might be
+     * different for other reductions so it is a knob.
+     */
+    private static final int GlobalSize = 1024 * Integer.getInteger("com.amd.sumatra.reduce.globalsize.multiple", 1);
+
+    @Override
+    public Integer offloadIntReduceImpl(Object okraKernel, int identity, int[] streamSource) {
+        // NOTE - this reduce requires local size of 64 which is the SumatraUtils default
+
+        // Handmade reduce does not support +UseCompressedOops
+        HotSpotVMConfig config = runtime().getConfig();
+        if (config.useCompressedOops == true || config.useHSAILDeoptimization == true) {
+            throw new GraalInternalError("Reduce offload not compatible with +UseCompressedOops or +UseHSAILDeoptimization");
+        }
+
+        try {
+            assert streamSource.length >= GlobalSize : "Input array length=" + streamSource.length + " smaller than requested global_size=" + GlobalSize;
+
+            int result[] = {identity};
+            Object args[] = {streamSource, result, streamSource.length};
+            args[0] = streamSource;
+
+            dispatchKernel(okraKernel, GlobalSize, args);
+
+            // kernel result is result[0].
+            return result[0];
+        } catch (Exception e) {
+            System.err.println(e);
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    @Override
+    public String getIntegerReduceIntrinsic(String reducerName) {
+
+        // Note all of these depend on group size of 256
+
+        String reduceOp = "/* Invalid */ ";
+        String atomicResultProduction = "/* Invalid */ ";
+        if (reducerName.equals("sum")) {
+            reduceOp = "add_u32 ";
+            atomicResultProduction = "atomicnoret_add_global_u32 ";
+        } else if (reducerName.equals("max")) {
+            reduceOp = "max_s32 ";
+            atomicResultProduction = "atomicnoret_max_global_s32 ";
+        } else if (reducerName.equals("min")) {
+            reduceOp = "min_s32 ";
+            atomicResultProduction = "atomicnoret_min_global_s32 ";
+        } else {
+            return "/* Invalid */ ";
+        }
+
+        // @formatter:off
+        return new String(
+                "version 0:95:$full:$large; // BRIG Object Format Version 0:4" + "\n"
+                + "" + "\n"
+                + "kernel &run(" + "\n"
+                + "	align 8 kernarg_u64 %arg_p3," + "\n"
+                + "	align 8 kernarg_u64 %arg_p4," + "\n"
+                + "	align 4 kernarg_u32 %arg_p5)" + "\n"
+                + "{" + "\n"
+                + "" + "\n"
+                + "	align 4 group_u32 %reduce_cllocal_scratch[256];" + "\n"
+                + "" + "\n"
+                + "	workitemabsid_u32 $s2, 0;" + "\n"
+                + "" + "\n"
+                + "	ld_kernarg_u32	$s1, [%arg_p5];" + "\n"
+                + "	ld_kernarg_u64	$d0, [%arg_p4];" + "\n"
+                + "	ld_kernarg_u64	$d1, [%arg_p3];" + "\n"
+                + "" + "\n"
+                + "	add_u64 $d0, $d0, 24;             // adjust over obj array headers" + "\n"
+                + "	add_u64 $d1, $d1, 24;" + "\n"
+                + "	cmp_ge_b1_s32	$c0, $s2, $s1; // if(gloId < length){" + "\n"
+                + "	cbr	$c0, @BB0_1;" + "\n"
+                + "	gridsize_u32	$s0, 0;        // s0 is globalsize" + "\n"
+                + " add_u32 $s0, $s0, $s2;         // gx += globalsize" + "\n"
+                + "	cvt_s64_s32	$d2, $s2;      // s2 is global id" + "\n"
+                + "	shl_u64	$d2, $d2, 2;" + "\n"
+                + "	add_u64	$d2, $d1, $d2;" + "\n"
+                + "	ld_global_u32	$s3, [$d2];    // load this element from input" + "\n"
+                + "	brn	@BB0_3;" + "\n"
+                + "" + "\n"
+                + "@BB0_1:" + "\n"
+                + "	mov_b32	$s0, $s2;" + "\n"                                  + "" + "\n"
+                + "@BB0_3:" + "\n"
+                + "	cmp_ge_b1_s32	$c1, $s0, $s1; // while (gx < length)" + "\n"
+                + "	cbr	$c1, @BB0_6;" + "\n"
+                + "	gridsize_u32	$s2, 0;" + "\n"
+                + "" + "\n"
+                + "@BB0_5:" + "\n"
+                + "	cvt_s64_s32	$d2, $s0;" + "\n"
+                + "	shl_u64	$d2, $d2, 2;" + "\n"
+                + "	add_u64	$d2, $d1, $d2;" + "\n"
+                + "	ld_global_u32	$s4, [$d2];" + "\n"
+                +       reduceOp + "  $s3, $s3, $s4;" + "\n"
+                + "	add_u32	$s0, $s0, $s2;" + "\n"
+                + "	cmp_lt_b1_s32	$c1, $s0, $s1;" + "\n"
+                + "	cbr	$c1, @BB0_5;" + "\n"
+                + "" + "\n"
+                + "@BB0_6:" + "\n"
+                + "	workgroupid_u32	$s0, 0;" + "\n"
+                + "	workgroupsize_u32	$s2, 0;" + "\n"
+                + "	mul_u32	$s2, $s2, $s0;" + "\n"
+                + "	sub_u32	$s2, $s1, $s2;" + "\n"
+                + "	workitemid_u32	$s1, 0;" + "\n"
+                + "	add_u32	$s4, $s1, 128;"
+                + "\n"
+                + "	cmp_lt_b1_u32	$c1, $s4, $s2;" + "\n"
+                + "	cmp_lt_b1_s32	$c2, $s1, 128;" + "\n"
+                + "	and_b1	$c1, $c2, $c1;" + "\n"
+                + "	cvt_s64_s32	$d1, $s1;" + "\n"
+                + "	shl_u64	$d1, $d1, 2;" + "\n"
+                + "	lda_group_u64	$d2, [%reduce_cllocal_scratch];" + "\n"
+                + "	add_u64	$d1, $d2, $d1;" + "\n"
+                + "	st_group_u32	$s3, [$d1];" + "\n"
+                + "	barrier_fgroup;" + "\n"
+                + "	not_b1	$c1, $c1;" + "\n"
+                + "	cbr	$c1, @BB0_8;" + "\n"
+                + "	ld_group_u32	$s3, [$d1];" + "\n"
+                + "	cvt_s64_s32	$d3, $s4;" + "\n"
+                + "	shl_u64	$d3, $d3, 2;" + "\n"
+                + "	add_u64	$d3, $d2, $d3;" + "\n"
+                + "	ld_group_u32	$s4, [$d3];" + "\n"
+                +       reduceOp + "  $s3, $s3, $s4;" + "\n"
+                + "	st_group_u32	$s3, [$d1];" + "\n"
+                + "" + "\n"
+                + "@BB0_8:" + "\n"
+                + "	add_u32	$s3, $s1, 64;" + "\n"
+                + "	cmp_lt_b1_u32	$c1, $s3, $s2;" + "\n"
+                + "	cmp_lt_b1_s32	$c2, $s1, 64;" + "\n"
+                + "	and_b1	$c1, $c2, $c1;" + "\n"
+                + "	barrier_fgroup;" + "\n"
+                + "	not_b1	$c1, $c1;" + "\n"
+                + "	cbr	$c1, @BB0_10;" + "\n"
+                + "	ld_group_u32	$s4, [$d1];" + "\n"
+                + "	cvt_s64_s32	$d3, $s3;" + "\n"
+                + "	shl_u64	$d3, $d3, 2;" + "\n"
+                + "	add_u64	$d3, $d2, $d3;" + "\n"
+                + "	ld_group_u32	$s3, [$d3];" + "\n"
+                +       reduceOp + "  $s3, $s3, $s4;"
+                + "\n"
+                + "	st_group_u32	$s3, [$d1];" + "\n"
+                + "" + "\n"
+                + "@BB0_10:" + "\n"
+                + "	add_u32	$s3, $s1, 32;" + "\n"
+                + "	cmp_lt_b1_u32	$c1, $s3, $s2;" + "\n"
+                + "	cmp_lt_b1_s32	$c2, $s1, 32;" + "\n"
+                + "	and_b1	$c1, $c2, $c1;" + "\n"
+                + "	barrier_fgroup;" + "\n"
+                + "	not_b1	$c1, $c1;" + "\n"
+                + "	cbr	$c1, @BB0_12;" + "\n"
+                + "	ld_group_u32	$s4, [$d1];" + "\n"
+                + "	cvt_s64_s32	$d3, $s3;" + "\n"
+                + "	shl_u64	$d3, $d3, 2;" + "\n"
+                + "	add_u64	$d3, $d2, $d3;" + "\n"
+                + "	ld_group_u32	$s3, [$d3];" + "\n"
+                +       reduceOp + "  $s3, $s3, $s4;" + "\n"
+                + "	st_group_u32	$s3, [$d1];" + "\n"
+                + "" + "\n"
+                + "@BB0_12:" + "\n"
+                + "	add_u32	$s3, $s1, 16;" + "\n"
+                + "	cmp_lt_b1_u32	$c1, $s3, $s2;" + "\n"
+                + "	cmp_lt_b1_s32	$c2, $s1, 16;" + "\n"
+                + "	and_b1	$c1, $c2, $c1;" + "\n"
+                + "	barrier_fgroup;" + "\n"
+                + "	not_b1	$c1, $c1;" + "\n"
+                + "	cbr	$c1, @BB0_14;" + "\n"
+                + "	ld_group_u32	$s4, [$d1];" + "\n"
+                + "	cvt_s64_s32	$d3, $s3;" + "\n"
+                + "	shl_u64	$d3, $d3, 2;" + "\n"
+                + "	add_u64	$d3, $d2, $d3;" + "\n"
+                + "	ld_group_u32	$s3, [$d3];" + "\n"
+                +       reduceOp + "  $s3, $s3, $s4;" + "\n"
+                + "	st_group_u32	$s3, [$d1];" + "\n"
+                + "" + "\n"
+                + "@BB0_14:" + "\n"
+                + "	add_u32	$s3, $s1, 8;" + "\n"
+                + "	cmp_lt_b1_u32	$c1, $s3, $s2;" + "\n"
+                + "	cmp_lt_b1_s32	$c2, $s1, 8;" + "\n"
+                + "	and_b1	$c1, $c2, $c1;" + "\n"
+                + "	barrier_fgroup;" + "\n"
+                + "	not_b1	$c1, $c1;" + "\n"
+                + "	cbr	$c1, @BB0_16;" + "\n"
+                + "	ld_group_u32	$s4, [$d1];" + "\n"
+                + "	cvt_s64_s32	$d3, $s3;" + "\n"
+                + "	shl_u64	$d3, $d3, 2;" + "\n"
+                + "	add_u64	$d3, $d2, $d3;" + "\n"
+                + "	ld_group_u32	$s3, [$d3];" + "\n"
+                +       reduceOp + "  $s3, $s3, $s4;" + "\n"
+                + "	st_group_u32	$s3, [$d1];" + "\n"
+                + "" + "\n"
+                + "@BB0_16:" + "\n"
+                + "	add_u32	$s3, $s1, 4;" + "\n"
+                + "	cmp_lt_b1_u32	$c1, $s3, $s2;" + "\n"
+                + "	cmp_lt_b1_s32	$c2, $s1, 4;" + "\n"
+                + "	and_b1	$c1, $c2, $c1;" + "\n"
+                + "	barrier_fgroup;" + "\n"
+                + "	not_b1	$c1, $c1;" + "\n"
+                + "	cbr	$c1, @BB0_18;" + "\n"
+                + "	ld_group_u32	$s4, [$d1];" + "\n"
+                + "	cvt_s64_s32	$d3, $s3;" + "\n"
+                + "	shl_u64	$d3, $d3, 2;" + "\n"
+                + "	add_u64	$d3, $d2, $d3;" + "\n"
+                + "	ld_group_u32	$s3, [$d3];" + "\n"
+                +       reduceOp + "  $s3, $s3, $s4;" + "\n"
+                + "	st_group_u32	$s3, [$d1];" + "\n"
+                + "" + "\n"
+                + "@BB0_18:" + "\n"
+                + "	add_u32	$s3, $s1, 2;" + "\n"
+                + "	cmp_lt_b1_u32	$c1, $s3, $s2;" + "\n"
+                + "	cmp_lt_b1_s32	$c2, $s1, 2;" + "\n"
+                + "	and_b1	$c1, $c2, $c1;" + "\n"
+                + "	barrier_fgroup;" + "\n"
+                + "	not_b1	$c1, $c1;" + "\n"
+                + "	cbr	$c1, @BB0_20;" + "\n"
+                + "	ld_group_u32	$s4, [$d1];" + "\n"
+                + "	cvt_s64_s32	$d3, $s3;" + "\n"
+                + "	shl_u64	$d3, $d3, 2;" + "\n"
+                + "	add_u64	$d3, $d2, $d3;" + "\n"
+                + "	ld_group_u32	$s3, [$d3];" + "\n"
+                +       reduceOp + "  $s3, $s3, $s4;" + "\n"
+                + "	st_group_u32	$s3, [$d1];" + "\n"
+                + "" + "\n"
+                + "@BB0_20:" + "\n"
+                + "	add_u32	$s3, $s1, 1;" + "\n"
+                + "	cmp_lt_b1_u32	$c1, $s3, $s2;" + "\n"
+                + "	cmp_lt_b1_s32	$c2, $s1, 1;" + "\n"
+                + "	and_b1	$c1, $c2, $c1;" + "\n"
+                + "	barrier_fgroup;" + "\n"
+                + "	not_b1	$c1, $c1;" + "\n"
+                + "	cbr	$c1, @BB0_22;" + "\n"
+                + "	ld_group_u32	$s4, [$d1];" + "\n"
+                + "	cvt_s64_s32	$d3, $s3;" + "\n"
+                + "	shl_u64	$d3, $d3, 2;" + "\n"
+                + "	add_u64	$d2, $d2, $d3;" + "\n"
+                + "	ld_group_u32	$s3, [$d2];" + "\n"
+                +       reduceOp + "  $s3, $s3, $s4;" + "\n"
+                + "	st_group_u32	$s3, [$d1];" + "\n"
+                + "" + "\n"
+                + "@BB0_22:" + "\n"
+                + "	cmp_gt_b1_u32	$c0, $s1, 0;  // s1 is local id, done if > 0" + "\n"
+                + "	cbr	$c0, @BB0_24;" + "\n"
+                + "" + "\n"
+                + "	ld_group_u32	$s2, [%reduce_cllocal_scratch];  // s2 is result[get_group_id(0)];" + "\n"
+                +       atomicResultProduction + " [$d0], $s2; // build global result from local results" + "\n"
+                + "" + "\n"
+                + "@BB0_24:" + "\n"
+                + "	ret;" + "\n"
+                + "};" + "\n");
+        //@formatter:on
+    }
 }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -66,7 +66,6 @@
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizingOp;
-import com.oracle.graal.lir.hsail.HSAILMove.AtomicReadAndAddOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 import com.oracle.graal.nodes.extended.*;
@@ -103,8 +102,10 @@
         paramTypeMap.put("HotSpotResolvedPrimitiveType<double>", "f64");
         paramTypeMap.put("HotSpotResolvedPrimitiveType<long>", "s64");
 
-        // The order of the conjunction below is important: the OkraUtil
-        // call may provision the native library required by the initialize() call
+        /*
+         * The order of the conjunction below is important: the OkraUtil call may provision the
+         * native library required by the initialize() call
+         */
         deviceInitialized = OkraUtil.okraLibExists() && initialize();
     }
 
@@ -249,7 +250,7 @@
     /**
      * Generates a GPU binary from HSAIL code.
      */
-    private static native long generateKernel(byte[] hsailCode, String name);
+    static native long generateKernel(byte[] hsailCode, String name);
 
     /**
      * Installs the {@linkplain ExternalCompilationResult#getEntryPoint() GPU binary} associated
@@ -261,8 +262,7 @@
      */
     public final HotSpotNmethod installKernel(ResolvedJavaMethod method, ExternalCompilationResult hsailCode) {
         assert hsailCode.getEntryPoint() != 0L;
-        // code below here lifted from HotSpotCodeCacheProviders.addExternalMethod
-        // used to be return getProviders().getCodeCache().addExternalMethod(method, hsailCode);
+        // Code here based on HotSpotCodeCacheProvider.addExternalMethod().
         HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) method;
         if (hsailCode.getId() == -1) {
             hsailCode.setId(javaMethod.allocateCompileId(hsailCode.getEntryBCI()));
@@ -294,6 +294,7 @@
 
         HSAILHotSpotNmethod code = new HSAILHotSpotNmethod(javaMethod, hsailCode.getName(), false, true);
         code.setOopMapArray(hsailCode.getOopMapArray());
+        code.setUsesAllocationFlag(hsailCode.getUsesAllocationFlag());
         HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(getTarget(), javaMethod, compilationResult);
         CodeInstallResult result = getRuntime().getCompilerToVM().installCode(compiled, code, null);
         if (result != CodeInstallResult.OK) {
@@ -378,20 +379,13 @@
             throw new GraalInternalError("Cannot execute GPU kernel if device is not initialized");
         }
         int[] oopMapArray = ((HSAILHotSpotNmethod) kernel).getOopMapArray();
-        Object[] oopsSaveArea;
-        if (getRuntime().getConfig().useHSAILDeoptimization) {
-            int saveAreaCounts = OopMapArrayBuilder.getSaveAreaCounts(oopMapArray);
-            int numDRegs = (saveAreaCounts >> 8) & 0xff;
-            int numStackSlots = (saveAreaCounts >> 16);
-            // pessimistically assume that any of the DRegs or stackslots could be oops
-            oopsSaveArea = new Object[maxDeoptIndex * (numDRegs + numStackSlots)];
-        } else {
-            oopsSaveArea = null;
-        }
-        return executeKernel0(kernel, jobSize, args, oopsSaveArea, donorThreadPool.get().getThreads(), HsailAllocBytesPerWorkitem.getValue(), oopMapArray);
+
+        // Pass donorThreadPoolArray if this kernel uses allocation, otherwise null
+        Thread[] donorThreadArray = ((HSAILHotSpotNmethod) kernel).getUsesAllocationFlag() ? donorThreadPool.get().getThreads() : null;
+        return executeKernel0(kernel, jobSize, args, donorThreadArray, HsailAllocBytesPerWorkitem.getValue(), oopMapArray);
     }
 
-    private static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args, Object[] oopsSave, Thread[] donorThreads, int allocBytesPerWorkitem, int[] oopMapArray)
+    private static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args, Thread[] donorThreads, int allocBytesPerWorkitem, int[] oopMapArray)
                     throws InvalidInstalledCodeException;
 
     /**
@@ -449,6 +443,7 @@
 
     static class HSAILHotSpotNmethod extends HotSpotNmethod {
         private int[] oopMapArray;
+        private boolean usesAllocation;
 
         HSAILHotSpotNmethod(HotSpotResolvedJavaMethod method, String name, boolean isDefault, boolean isExternal) {
             super(method, name, isDefault, isExternal);
@@ -461,6 +456,14 @@
         int[] getOopMapArray() {
             return oopMapArray;
         }
+
+        public void setUsesAllocationFlag(boolean val) {
+            usesAllocation = val;
+        }
+
+        public boolean getUsesAllocationFlag() {
+            return usesAllocation;
+        }
     }
 
     @Override
@@ -484,6 +487,7 @@
     public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod method) {
         assert method != null : lir + " is not associated with a method";
         Kind wordKind = getProviders().getCodeCache().getTarget().wordKind;
+        LIRKind wordLIRKind = LIRKind.value(wordKind);
 
         HotSpotVMConfig config = getRuntime().getConfig();
         boolean useHSAILDeoptimization = config.useHSAILDeoptimization;
@@ -493,19 +497,22 @@
             Debug.log("+UseHSAILSafepoints requires +UseHSAILDeoptimization");
         }
 
-        // see what graph nodes we have to see if we are using the thread register
-        // if not, we don't have to emit the code that sets that up
-        // maybe there is a better way to do this?
-        boolean usesThreadRegister = false;
+        /*
+         * See what graph nodes we have to see if we are using the thread register. If not, we don't
+         * have to emit the code that sets it up. Maybe there is a better way to do this?
+         */
+        boolean usesAllocation = false;
         search: for (AbstractBlock<?> b : lir.linearScanOrder()) {
             for (LIRInstruction op : lir.getLIRforBlock(b)) {
-                if (op instanceof AtomicReadAndAddOp) {
-                    usesThreadRegister = true;
+                if ((op instanceof HSAILMove.LoadOp) && ((HSAILMove.LoadOp) op).usesThreadRegister()) {
+                    usesAllocation = true;
                     assert useHSAILDeoptimization : "cannot use thread register if HSAIL deopt support is disabled";
                     break search;
                 }
             }
         }
+        // save usesAllocation flag in ExternalCompilationResult
+        ((ExternalCompilationResult) crb.compilationResult).setUsesAllocationFlag(usesAllocation);
 
         // Emit the prologue.
         HSAILAssembler asm = (HSAILAssembler) crb.asm;
@@ -527,8 +534,7 @@
             nonConstantParamCount++;
         }
 
-        // If this is an instance method, include mappings for the "this" parameter
-        // as the first parameter.
+        // If this is an instance method, include the "this" parameter
         if (!isStatic) {
             nonConstantParamCount++;
         }
@@ -564,8 +570,10 @@
         // Include the gid.
         System.arraycopy(paramtypes, 0, ccParamTypes, 0, nonConstantParamCount);
 
-        // Last entry is always int (its register gets used in the workitemabsid instruction)
-        // this is true even for object stream labmdas
+        /*
+         * Last entry is always int (its register gets used in the workitemabsid instruction). This
+         * is true even for object stream lambdas.
+         */
         if (sigParamCount > 0) {
             ccParamTypes[ccParamTypes.length - 1] = metaAccess.lookupJavaType(int.class);
         }
@@ -620,15 +628,14 @@
 
         if (useHSAILDeoptimization) {
             // Aliases for d16
-            RegisterValue d16_deoptInfo = HSAIL.d16.asValue(wordKind);
-            RegisterValue d16_donorThreads = d16_deoptInfo;
+            RegisterValue d16_deoptInfo = HSAIL.d16.asValue(wordLIRKind);
 
             // Aliases for d17
-            RegisterValue d17_donorThreadIndex = HSAIL.d17.asValue(wordKind);
+            RegisterValue d17_donorThreadIndex = HSAIL.d17.asValue(wordLIRKind);
             RegisterValue d17_safepointFlagAddrIndex = d17_donorThreadIndex;
 
             // Aliases for s34
-            RegisterValue s34_deoptOccurred = HSAIL.s34.asValue(Kind.Int);
+            RegisterValue s34_deoptOccurred = HSAIL.s34.asValue(LIRKind.value(Kind.Int));
             RegisterValue s34_donorThreadIndex = s34_deoptOccurred;
 
             asm.emitLoadKernelArg(d16_deoptInfo, asm.getDeoptInfoName(), "u64");
@@ -636,30 +643,29 @@
 
             if (useHSAILSafepoints) {
                 // Load address of _notice_safepoints field
-                asm.emitLoad(wordKind, d17_safepointFlagAddrIndex, new HSAILAddressValue(wordKind, d16_deoptInfo, config.hsailNoticeSafepointsOffset).toAddress());
+                asm.emitLoad(wordKind, d17_safepointFlagAddrIndex, new HSAILAddressValue(wordLIRKind, d16_deoptInfo, config.hsailNoticeSafepointsOffset).toAddress());
                 // Load int value from that field
-                asm.emitLoadAcquire(s34_deoptOccurred, new HSAILAddressValue(Kind.Int, d17_safepointFlagAddrIndex, 0).toAddress());
+                asm.emitLoadAcquire(s34_deoptOccurred, new HSAILAddressValue(wordLIRKind, d17_safepointFlagAddrIndex, 0).toAddress());
                 asm.emitCompare(Kind.Int, s34_deoptOccurred, Constant.forInt(0), "ne", false, false);
                 asm.cbr(deoptInProgressLabel);
             }
-            asm.emitLoadAcquire(s34_deoptOccurred, new HSAILAddressValue(Kind.Int, d16_deoptInfo, config.hsailDeoptOccurredOffset).toAddress());
+            asm.emitLoadAcquire(s34_deoptOccurred, new HSAILAddressValue(wordLIRKind, d16_deoptInfo, config.hsailDeoptOccurredOffset).toAddress());
             asm.emitCompare(Kind.Int, s34_deoptOccurred, Constant.forInt(0), "ne", false, false);
             asm.cbr(deoptInProgressLabel);
-            // load thread register if needed
-            if (usesThreadRegister) {
+            // load thread register if this kernel performs allocation
+            if (usesAllocation) {
+                RegisterValue threadReg = getProviders().getRegisters().getThreadRegister().asValue(wordLIRKind);
                 assert HsailDonorThreads.getValue() > 0;
-                asm.emitLoad(wordKind, d16_donorThreads, new HSAILAddressValue(wordKind, d16_deoptInfo, config.hsailDonorThreadsOffset).toAddress());
+                asm.emitLoad(wordKind, threadReg, new HSAILAddressValue(wordLIRKind, d16_deoptInfo, config.hsailCurTlabInfoOffset).toAddress());
                 if (HsailDonorThreads.getValue() != 1) {
                     asm.emitComment("// map workitem to a donor thread");
                     asm.emitString(String.format("rem_u32  $%s, %s, %d;", s34_donorThreadIndex.getRegister(), workItemReg, HsailDonorThreads.getValue()));
                     asm.emitConvert(d17_donorThreadIndex, s34_donorThreadIndex, wordKind, Kind.Int);
-                    asm.emit("mad", d16_donorThreads, d17_donorThreadIndex, Constant.forInt(8), d16_donorThreads);
+                    asm.emit("mad", threadReg, d17_donorThreadIndex, Constant.forInt(8), threadReg);
                 } else {
                     // workitem is already mapped to solitary donor thread
                 }
-                AllocatableValue threadRegValue = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
-                asm.emitComment("// $" + getProviders().getRegisters().getThreadRegister() + " will point to a donor thread for this workitem");
-                asm.emitLoad(wordKind, threadRegValue, new HSAILAddressValue(wordKind, d16_donorThreads).toAddress());
+                asm.emitComment("// $" + getProviders().getRegisters().getThreadRegister() + " will point to holder of tlab thread info for this workitem");
             }
         }
 
@@ -676,8 +682,10 @@
             boolean useCompressedOops = config.useCompressedOops;
             final int arrayElementsOffset = HotSpotGraalRuntime.getArrayBaseOffset(wordKind);
             String iterationObjArgReg = HSAIL.mapRegister(cc.getArgument(nonConstantParamCount - 1));
-            // iterationObjArgReg will be the highest $d register in use (it is the last parameter)
-            // so tempReg can be the next higher $d register
+            /*
+             * iterationObjArgReg will be the highest $d register in use (it is the last parameter)
+             * so tempReg can be the next higher $d register
+             */
             String tmpReg = "$d" + (asRegister(cc.getArgument(nonConstantParamCount - 1)).encoding() + 1);
             // Convert gid to long.
             asm.emitString("cvt_u64_s32 " + tmpReg + ", " + workItemReg + "; // Convert gid to long");
@@ -740,8 +748,10 @@
         int numDRegs = 0;
         int numStackSlotBytes = 0;
         if (useHSAILDeoptimization) {
-            // get the union of registers and stack slots needed to be saved at the infopoints
-            // while doing this compute the highest register in each category
+            /*
+             * Get the union of registers and stack slots needed to be saved at the infopoints.
+             * While doing this compute the highest register in each category.
+             */
             HSAILHotSpotRegisterConfig hsailRegConfig = (HSAILHotSpotRegisterConfig) regConfig;
             Set<Register> infoUsedRegs = new TreeSet<>();
             Set<StackSlot> infoUsedStackSlots = new HashSet<>();
@@ -800,18 +810,18 @@
             final int offsetToNumSaves = config.hsailFrameNumSRegOffset;
             final int offsetToSaveArea = config.hsailFrameHeaderSize;
 
-            AllocatableValue scratch64 = HSAIL.d16.asValue(wordKind);
-            AllocatableValue cuSaveAreaPtr = HSAIL.d17.asValue(wordKind);
-            AllocatableValue waveMathScratch1 = HSAIL.d18.asValue(wordKind);
-            AllocatableValue waveMathScratch2 = HSAIL.d19.asValue(wordKind);
+            AllocatableValue scratch64 = HSAIL.d16.asValue(wordLIRKind);
+            AllocatableValue cuSaveAreaPtr = HSAIL.d17.asValue(wordLIRKind);
+            AllocatableValue waveMathScratch1 = HSAIL.d18.asValue(wordLIRKind);
+            AllocatableValue waveMathScratch2 = HSAIL.d19.asValue(wordLIRKind);
 
-            AllocatableValue actionAndReasonReg = HSAIL.actionAndReasonReg.asValue(Kind.Int);
-            AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(Kind.Int);
-            AllocatableValue scratch32 = HSAIL.s34.asValue(Kind.Int);
-            AllocatableValue workidreg = HSAIL.s35.asValue(Kind.Int);
+            AllocatableValue actionAndReasonReg = HSAIL.actionAndReasonReg.asValue(LIRKind.value(Kind.Int));
+            AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(LIRKind.value(Kind.Int));
+            AllocatableValue scratch32 = HSAIL.s34.asValue(LIRKind.value(Kind.Int));
+            AllocatableValue workidreg = HSAIL.s35.asValue(LIRKind.value(Kind.Int));
 
-            HSAILAddress deoptNextIndexAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeoptNextIndex).toAddress();
-            HSAILAddress neverRanArrayAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToNeverRanArray).toAddress();
+            HSAILAddress deoptNextIndexAddr = new HSAILAddressValue(wordLIRKind, scratch64, offsetToDeoptNextIndex).toAddress();
+            HSAILAddress neverRanArrayAddr = new HSAILAddressValue(wordLIRKind, scratch64, offsetToNeverRanArray).toAddress();
 
             // The just-started lanes that see the deopt flag will jump here
             asm.emitString0(deoptInProgressLabel + ":\n");
@@ -819,7 +829,7 @@
             asm.emitWorkItemAbsId(workidreg);
             asm.emitConvert(waveMathScratch2, workidreg, wordKind, Kind.Int);
             asm.emit("add", waveMathScratch1, waveMathScratch1, waveMathScratch2);
-            HSAILAddress neverRanStoreAddr = new HSAILAddressValue(Kind.Byte, waveMathScratch1, 0).toAddress();
+            HSAILAddress neverRanStoreAddr = new HSAILAddressValue(wordLIRKind, waveMathScratch1, 0).toAddress();
             asm.emitStore(Kind.Byte, Constant.forInt(1), neverRanStoreAddr);
             asm.emitString("ret;");
 
@@ -827,7 +837,7 @@
             asm.emitString0(asm.getDeoptLabelName() + ":\n");
             String labelExit = asm.getDeoptLabelName() + "_Exit";
 
-            HSAILAddress deoptInfoAddr = new HSAILAddressValue(Kind.Int, scratch64, config.hsailDeoptOccurredOffset).toAddress();
+            HSAILAddress deoptInfoAddr = new HSAILAddressValue(wordLIRKind, scratch64, config.hsailDeoptOccurredOffset).toAddress();
             asm.emitLoadKernelArg(scratch64, asm.getDeoptInfoName(), "u64");
 
             // Set deopt occurred flag
@@ -836,13 +846,16 @@
 
             asm.emitComment("// Determine next deopt save slot");
             asm.emitAtomicAdd(scratch32, deoptNextIndexAddr, Constant.forInt(1));
-            // scratch32 now holds next index to use
-            // set error condition if no room in save area
+            /*
+             * scratch32 now holds next index to use set error condition if no room in save area
+             */
             asm.emitComment("// assert room to save deopt");
             asm.emitCompare(Kind.Int, scratch32, Constant.forInt(maxDeoptIndex), "lt", false, false);
             asm.cbr("@L_StoreDeopt");
-            // if assert fails, store a guaranteed negative workitemid in top level deopt occurred
-            // flag
+            /*
+             * if assert fails, store a guaranteed negative workitemid in top level deopt occurred
+             * flag
+             */
             asm.emitWorkItemAbsId(scratch32);
             asm.emit("mad", scratch32, scratch32, Constant.forInt(-1), Constant.forInt(-1));
             asm.emitStore(scratch32, deoptInfoAddr);
@@ -861,14 +874,14 @@
             // Add offset to _deopt_save_states[0]
             asm.emit("add", scratch64, cuSaveAreaPtr, Constant.forInt(offsetToDeoptSaveStates));
 
-            HSAILAddress workItemAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeoptimizationWorkItem).toAddress();
-            HSAILAddress actionReasonStoreAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeoptimizationReason).toAddress();
+            HSAILAddress workItemAddr = new HSAILAddressValue(wordLIRKind, scratch64, offsetToDeoptimizationWorkItem).toAddress();
+            HSAILAddress actionReasonStoreAddr = new HSAILAddressValue(wordLIRKind, scratch64, offsetToDeoptimizationReason).toAddress();
 
             asm.emitComment("// Get _deopt_info._first_frame");
             asm.emit("add", waveMathScratch1, scratch64, Constant.forInt(offsetToDeoptimizationFrame));
             // Now scratch64 is the _deopt_info._first_frame
-            HSAILAddress pcStoreAddr = new HSAILAddressValue(Kind.Int, waveMathScratch1, offsetToFramePc).toAddress();
-            HSAILAddress regCountsAddr = new HSAILAddressValue(Kind.Int, waveMathScratch1, offsetToNumSaves).toAddress();
+            HSAILAddress pcStoreAddr = new HSAILAddressValue(wordLIRKind, waveMathScratch1, offsetToFramePc).toAddress();
+            HSAILAddress regCountsAddr = new HSAILAddressValue(wordLIRKind, waveMathScratch1, offsetToNumSaves).toAddress();
             asm.emitComment("// store deopting workitem");
             asm.emitWorkItemAbsId(scratch32);
             asm.emitStore(Kind.Int, scratch32, workItemAddr);
@@ -880,24 +893,26 @@
             asm.emitComment("// store regCounts (" + numSRegs + " $s registers, " + numDRegs + " $d registers, " + numStackSlots + " stack slots)");
             asm.emitStore(Kind.Int, Constant.forInt(numSRegs + (numDRegs << 8) + (numStackSlots << 16)), regCountsAddr);
 
-            // loop thru the usedValues storing each of the registers that are used.
-            // we always store in a fixed location, even if some registers are skipped
+            /*
+             * Loop thru the usedValues storing each of the registers that are used. We always store
+             * in a fixed location, even if some registers are skipped.
+             */
             asm.emitComment("// store used regs");
             for (Register reg : infoUsedRegs) {
                 if (hsailRegConfig.isAllocatableSReg(reg)) {
                     // 32 bit registers
                     Kind kind = Kind.Int;
                     int ofst = offsetToSaveArea + reg.encoding * 4;
-                    HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
-                    AllocatableValue regValue = reg.asValue(kind);
+                    HSAILAddress addr = new HSAILAddressValue(wordLIRKind, waveMathScratch1, ofst).toAddress();
+                    AllocatableValue regValue = reg.asValue(LIRKind.value(kind));
                     asm.emitStore(kind, regValue, addr);
                 } else if (hsailRegConfig.isAllocatableDReg(reg)) {
                     // 64 bit registers
                     Kind kind = Kind.Long;
                     // d reg ofst starts past the 32 sregs
                     int ofst = offsetToSaveArea + (numSRegs * 4) + reg.encoding * 8;
-                    HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
-                    AllocatableValue regValue = reg.asValue(kind);
+                    HSAILAddress addr = new HSAILAddressValue(wordLIRKind, waveMathScratch1, ofst).toAddress();
+                    AllocatableValue regValue = reg.asValue(LIRKind.value(kind));
                     asm.emitStore(kind, regValue, addr);
                 } else {
                     throw GraalInternalError.unimplemented();
@@ -912,7 +927,7 @@
                     Kind kind = slot.getKind();
                     int sizeInBits = (kind.isObject() || kind.getByteCount() == 8 ? 64 : 32);
                     int ofst = offsetToSaveArea + (numSRegs * 4) + (numDRegs * 8) + HSAIL.getStackOffsetStart(slot, sizeInBits);
-                    HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
+                    HSAILAddress addr = new HSAILAddressValue(wordLIRKind, waveMathScratch1, ofst).toAddress();
                     if (sizeInBits == 64) {
                         asm.emitSpillLoad(kind, scratch64, slot);
                         asm.emitStore(kind, scratch64, addr);
@@ -961,11 +976,11 @@
         private int intsPerInfopoint;
 
         int[] build(List<Infopoint> infoList, int numSRegs, int numDRegs, int numStackSlots, HSAILHotSpotRegisterConfig hsailRegConfig) {
-            // we are told that infoList is always sorted
-            // each infoPoint can have a different oopMap
-
-            // since numStackSlots is the number of 8-byte stack slots used, it is an upper limit on
-            // the number of oop stack slots
+            /*
+             * We are told that infoList is always sorted. Each infoPoint can have a different
+             * oopMap. Since numStackSlots is the number of 8-byte stack slots used, it is an upper
+             * limit on the number of oop stack slots
+             */
             int bitsPerInfopoint = numDRegs + numStackSlots;
             int intsForBits = (bitsPerInfopoint + 31) / 32;
             int numInfopoints = infoList.size();
@@ -1045,10 +1060,6 @@
             int arrIndex = HEADERSIZE + infoIndex * intsPerInfopoint + 1 + intIndex;
             return array[arrIndex];
         }
-
-        public static int getSaveAreaCounts(int[] array) {
-            return array[SAVEAREACOUNTS_OFST];
-        }
     }
 
     private static StructuredGraph prepareHostGraph(ResolvedJavaMethod method, List<DeoptimizingOp> deopts, HotSpotProviders providers, HotSpotVMConfig config, int numSRegs, int numDRegs) {
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -72,7 +72,7 @@
         final int stackFrameAlignment = 8;
         final int implicitNullCheckLimit = 0;
         final boolean inlineObjects = true;
-        return new HotSpotTargetDescription(new HSAIL(), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects, Kind.Int);
+        return new HotSpotTargetDescription(new HSAIL(), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
     }
 
     public String getArchitecture() {
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Mon Jun 30 12:02:19 2014 +0200
@@ -33,7 +33,6 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.gen.*;
@@ -44,11 +43,13 @@
 import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCall2ArgOp;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCallNoArgOp;
 import com.oracle.graal.lir.hsail.HSAILMove.CompareAndSwapOp;
+import com.oracle.graal.lir.hsail.HSAILMove.LoadAcquireOp;
 import com.oracle.graal.lir.hsail.HSAILMove.LoadOp;
-import com.oracle.graal.lir.hsail.HSAILMove.MoveFromRegOp;
 import com.oracle.graal.lir.hsail.HSAILMove.MoveToRegOp;
 import com.oracle.graal.lir.hsail.HSAILMove.StoreConstantOp;
 import com.oracle.graal.lir.hsail.HSAILMove.StoreOp;
+import com.oracle.graal.lir.hsail.HSAILMove.StoreReleaseOp;
+import com.oracle.graal.lir.hsail.HSAILMove.WorkItemAbsIdOp;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -106,28 +107,23 @@
         }
     }
 
-    private static Kind getMemoryKind(PlatformKind kind) {
-        if (kind == NarrowOopStamp.NarrowOop) {
-            return Kind.Int;
-        } else {
-            return (Kind) kind;
-        }
+    @Override
+    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
+        HSAILAddressValue loadAddress = asAddressValue(address);
+        Variable result = newVariable(kind);
+        append(new LoadOp((Kind) kind.getPlatformKind(), result, loadAddress, state));
+        return result;
     }
 
-    @Override
-    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
+    public Variable emitLoadAcquire(LIRKind kind, Value address, LIRFrameState state) {
         HSAILAddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(kind);
-        if (kind == NarrowOopStamp.NarrowOop) {
-            append(new LoadOp(Kind.Int, result, loadAddress, state));
-        } else {
-            append(new LoadOp(getMemoryKind(kind), result, loadAddress, state));
-        }
+        append(new LoadAcquireOp((Kind) kind.getPlatformKind(), result, loadAddress, state));
         return result;
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
+    public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) {
         HSAILAddressValue storeAddress = asAddressValue(address);
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
@@ -135,38 +131,41 @@
                 c = Constant.INT_0;
             }
             if (canStoreConstant(c)) {
-                append(new StoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
+                append(new StoreConstantOp((Kind) kind.getPlatformKind(), storeAddress, c, state));
                 return;
             }
         }
         Variable input = load(inputVal);
-        if (kind == NarrowOopStamp.NarrowOop) {
-            append(new StoreOp(Kind.Int, storeAddress, input, state));
-        } else {
-            append(new StoreOp(getMemoryKind(kind), storeAddress, input, state));
-        }
+        append(new StoreOp((Kind) kind.getPlatformKind(), storeAddress, input, state));
+    }
+
+    public void emitStoreRelease(LIRKind kind, Value address, Value inputVal, LIRFrameState state) {
+        HSAILAddressValue storeAddress = asAddressValue(address);
+        // TODO: handle Constants here
+        Variable input = load(inputVal);
+        append(new StoreReleaseOp((Kind) kind.getPlatformKind(), storeAddress, input, state));
     }
 
     public Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
-        PlatformKind kind = newValue.getPlatformKind();
-        assert kind == expectedValue.getPlatformKind();
-        Kind memKind = getMemoryKind(kind);
+        LIRKind kind = newValue.getLIRKind();
+        assert kind.equals(expectedValue.getLIRKind());
+        Kind memKind = (Kind) kind.getPlatformKind();
 
         HSAILAddressValue addressValue = asAddressValue(address);
         Variable expected = emitMove(expectedValue);
         Variable casResult = newVariable(kind);
         append(new CompareAndSwapOp(memKind, casResult, addressValue, expected, asAllocatable(newValue)));
 
-        assert trueValue.getPlatformKind() == falseValue.getPlatformKind();
-        Variable nodeResult = newVariable(trueValue.getPlatformKind());
+        assert trueValue.getLIRKind().equals(falseValue.getLIRKind());
+        Variable nodeResult = newVariable(trueValue.getLIRKind());
         append(new CondMoveOp(HSAILLIRGenerator.mapKindToCompareOp(memKind), casResult, expected, nodeResult, Condition.EQ, trueValue, falseValue));
         return nodeResult;
     }
 
     @Override
     public Value emitAtomicReadAndAdd(Value address, Value delta) {
-        PlatformKind kind = delta.getPlatformKind();
-        Kind memKind = getMemoryKind(kind);
+        LIRKind kind = delta.getLIRKind();
+        Kind memKind = (Kind) kind.getPlatformKind();
         Variable result = newVariable(kind);
         HSAILAddressValue addressValue = asAddressValue(address);
         append(new HSAILMove.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta)));
@@ -175,8 +174,8 @@
 
     @Override
     public Value emitAtomicReadAndWrite(Value address, Value newValue) {
-        PlatformKind kind = newValue.getPlatformKind();
-        Kind memKind = getMemoryKind(kind);
+        LIRKind kind = newValue.getLIRKind();
+        Kind memKind = (Kind) kind.getPlatformKind();
         Variable result = newVariable(kind);
         HSAILAddressValue addressValue = asAddressValue(address);
         append(new HSAILMove.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue)));
@@ -204,13 +203,13 @@
      */
     @Override
     public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
-        Variable result = newVariable(Kind.Object);  // linkage.getDescriptor().getResultType());
+        Variable result = newVariable(LIRKind.reference(Kind.Object));  // linkage.getDescriptor().getResultType());
 
         // to make the LIRVerifier happy, we move any constants into registers
         Value[] argLocations = new Value[args.length];
         for (int i = 0; i < args.length; i++) {
             Value arg = args[i];
-            AllocatableValue loc = newVariable(arg.getKind());
+            AllocatableValue loc = newVariable(arg.getLIRKind());
             emitMove(loc, arg);
             argLocations[i] = loc;
         }
@@ -235,23 +234,13 @@
 
     @Override
     protected HSAILLIRInstruction createMove(AllocatableValue dst, Value src) {
-        if (dst.getPlatformKind() == NarrowOopStamp.NarrowOop) {
-            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(src)) {
-                return new MoveToRegOp(Kind.Int, dst, Constant.INT_0);
-            } else if (src instanceof HotSpotObjectConstant) {
-                if (HotSpotObjectConstant.isCompressed((Constant) src)) {
-                    Variable uncompressed = newVariable(Kind.Object);
-                    append(new MoveToRegOp(Kind.Object, uncompressed, src));
-                    CompressEncoding oopEncoding = config.getOopEncoding();
-                    return new HSAILMove.CompressPointer(dst, newVariable(Kind.Object), uncompressed, oopEncoding.base, oopEncoding.shift, oopEncoding.alignment, true);
-                } else {
-                    return new MoveToRegOp(Kind.Object, dst, src);
-                }
-            } else if (isRegister(src) || isStackSlot(dst)) {
-                return new MoveFromRegOp(Kind.Int, dst, src);
-            } else {
-                return new MoveToRegOp(Kind.Int, dst, src);
-            }
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(src)) {
+            return new MoveToRegOp(Kind.Int, dst, Constant.INT_0);
+        } else if (src instanceof HotSpotObjectConstant && HotSpotObjectConstant.isCompressed((Constant) src)) {
+            Variable uncompressed = newVariable(LIRKind.reference(Kind.Object));
+            append(new MoveToRegOp(Kind.Object, uncompressed, src));
+            CompressEncoding oopEncoding = config.getOopEncoding();
+            return new HSAILMove.CompressPointer(dst, newVariable(LIRKind.reference(Kind.Object)), uncompressed, oopEncoding.base, oopEncoding.shift, oopEncoding.alignment, true);
         } else {
             return super.createMove(dst, src);
         }
@@ -292,14 +281,14 @@
 
     @Override
     public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
-        Variable result = newVariable(NarrowOopStamp.NarrowOop);
-        append(new HSAILMove.CompressPointer(result, newVariable(pointer.getPlatformKind()), asAllocatable(pointer), encoding.base, encoding.shift, encoding.alignment, nonNull));
+        Variable result = newVariable(LIRKind.reference(Kind.Int));
+        append(new HSAILMove.CompressPointer(result, newVariable(pointer.getLIRKind()), asAllocatable(pointer), encoding.base, encoding.shift, encoding.alignment, nonNull));
         return result;
     }
 
     @Override
     public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
-        Variable result = newVariable(Kind.Object);
+        Variable result = newVariable(LIRKind.reference(Kind.Object));
         append(new HSAILMove.UncompressPointer(result, asAllocatable(pointer), encoding.base, encoding.shift, encoding.alignment, nonNull));
         return result;
     }
@@ -310,8 +299,14 @@
 
     public void emitNullCheck(Value address, LIRFrameState state) {
         assert address.getKind() == Kind.Object : address + " - " + address.getKind() + " not an object!";
-        Variable obj = newVariable(Kind.Object);
+        Variable obj = newVariable(LIRKind.reference(Kind.Object));
         emitMove(obj, address);
         append(new HSAILMove.NullCheckOp(obj, state));
     }
+
+    public Variable emitWorkItemAbsId() {
+        Variable result = newVariable(LIRKind.value(Kind.Int));
+        append(new WorkItemAbsIdOp(result));
+        return result;
+    }
 }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java	Mon Jun 30 12:02:19 2014 +0200
@@ -78,12 +78,12 @@
     }
 
     public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
-        Kind kind = x.newValue().getKind();
-        assert kind == x.expectedValue().getKind();
-
         Variable expected = getGen().load(operand(x.expectedValue()));
         Variable newVal = getGen().load(operand(x.newValue()));
 
+        LIRKind kind = newVal.getLIRKind();
+        assert kind.equals(expected.getLIRKind());
+
         int disp = 0;
         HSAILAddressValue address;
         Value index = operand(x.offset());
@@ -95,8 +95,8 @@
             throw GraalInternalError.shouldNotReachHere("NYI");
         }
 
-        Variable casResult = newVariable(kind);
-        append(new CompareAndSwapOp(kind, casResult, address, expected, newVal));
+        Variable casResult = gen.newVariable(kind);
+        append(new CompareAndSwapOp((Kind) kind.getPlatformKind(), casResult, address, expected, newVal));
 
         setResult(x, casResult);
     }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotRegisterConfig.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotRegisterConfig.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hsail.*;
 
 /**
@@ -107,7 +106,7 @@
 
                     if (!stackOnly && currentRegs32 < generalParameterRegisters.length) {
                         Register register = generalParameterRegisters[currentRegs32++];
-                        locations[i] = register.asValue(kind);
+                        locations[i] = register.asValue(target.getLIRKind(kind));
                     }
                     break;
                 case Long:
@@ -115,7 +114,7 @@
                 case Double:
                     if (!stackOnly && currentRegs64 < longParameterRegisters.length) {
                         Register register = longParameterRegisters[currentRegs64++];
-                        locations[i] = register.asValue(kind);
+                        locations[i] = register.asValue(target.getLIRKind(kind));
                     }
                     break;
                 default:
@@ -123,13 +122,13 @@
             }
 
             if (locations[i] == null) {
-                locations[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, !type.out);
+                locations[i] = StackSlot.get(target.getLIRKind(kind.getStackKind()), currentStackOffset, !type.out);
                 currentStackOffset += Math.max(target.getSizeInBytes(kind), target.wordSize);
             }
         }
 
         Kind returnKind = returnType == null ? Kind.Void : returnType.getKind();
-        AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(returnKind);
+        AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(target.getLIRKind(returnKind));
         return new CallingConvention(currentStackOffset, returnLocation, locations);
     }
 
@@ -145,14 +144,7 @@
 
     @Override
     public Register[] getAllocatableRegisters(PlatformKind kind) {
-        Kind primitiveKind;
-        if (kind == NarrowOopStamp.NarrowOop) {
-            primitiveKind = Kind.Int;
-        } else {
-            primitiveKind = (Kind) kind;
-        }
-
-        switch (primitiveKind) {
+        switch ((Kind) kind) {
             case Int:
             case Short:
             case Byte:
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
@@ -41,6 +42,7 @@
 
     private final Replacements host;
     private HashSet<ResolvedJavaMethod> ignoredResolvedMethods = new HashSet<>();
+    private HashMap<ResolvedJavaMethod, ResolvedJavaMethod> arrayCopyRedirectMethods = new HashMap<>();
 
     public HSAILHotSpotReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, Assumptions assumptions, TargetDescription target, Replacements host) {
         super(providers, snippetReflection, assumptions, target);
@@ -63,6 +65,28 @@
 
         // Register the ignored substitutions
         addIgnoredResolvedMethod(String.class, "equals", Object.class);
+
+        /*
+         * Register the special arraycopy snippet handling This basically ignores the sense of the
+         * CallArrayCopy flag and always directs to the snippets from UnsafeArrayCopyNode
+         */
+        redirectArraycopySnippetMethod(Kind.Byte);
+        redirectArraycopySnippetMethod(Kind.Boolean);
+        redirectArraycopySnippetMethod(Kind.Char);
+        redirectArraycopySnippetMethod(Kind.Short);
+        redirectArraycopySnippetMethod(Kind.Int);
+        redirectArraycopySnippetMethod(Kind.Long);
+        redirectArraycopySnippetMethod(Kind.Float);
+        redirectArraycopySnippetMethod(Kind.Double);
+        redirectArraycopySnippetMethod(Kind.Object);
+    }
+
+    private void redirectArraycopySnippetMethod(Kind kind) {
+        ResolvedJavaMethod foreignCallMethod = providers.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(kind, false, true));
+        ResolvedJavaMethod nonForeignCallMethod = providers.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(kind, false, false));
+        if (!foreignCallMethod.equals(nonForeignCallMethod)) {
+            arrayCopyRedirectMethods.put(foreignCallMethod, nonForeignCallMethod);
+        }
     }
 
     @Override
@@ -75,25 +99,42 @@
     public Class<? extends FixedWithNextNode> getMacroSubstitution(ResolvedJavaMethod method) {
         Class<? extends FixedWithNextNode> klass = super.getMacroSubstitution(method);
         if (klass == null) {
-            // eventually we want to only defer certain macro substitutions to the host, but for now
-            // we will do everything
+            /*
+             * Eventually we want to only defer certain macro substitutions to the host, but for now
+             * we will do everything.
+             */
             return host.getMacroSubstitution(method);
         }
         return klass;
     }
 
     @Override
-    public StructuredGraph getSnippet(ResolvedJavaMethod method) {
-        // Must work in cooperation with HSAILHotSpotLoweringProvider
-        return host.getSnippet(method);
+    public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry) {
+        /*
+         * Must work in cooperation with HSAILHotSpotLoweringProvider. Before asking for the host
+         * snippet, see if it is one of the arraycopy methods which we want to redirect to the
+         * non-foreign-call version, regardless of the sense of CallArrayCopy option
+         */
+        ResolvedJavaMethod snippetMethod = method;
+        ResolvedJavaMethod snippetRecursiveEntry = recursiveEntry;
+        ResolvedJavaMethod redirect = arrayCopyRedirectMethods.get(method);
+        if (redirect != null) {
+            snippetMethod = redirect;
+            if (recursiveEntry != null && recursiveEntry.equals(method)) {
+                snippetRecursiveEntry = redirect;
+            }
+        }
+        return host.getSnippet(snippetMethod, snippetRecursiveEntry);
     }
 
     @Override
     public StructuredGraph getMethodSubstitution(ResolvedJavaMethod original) {
         StructuredGraph m = super.getMethodSubstitution(original);
         if (m == null) {
-            // we check for a few special cases we do NOT want to defer here
-            // but basically we defer everything else to the host
+            /*
+             * We check for a few special cases we do NOT want to defer here but basically we defer
+             * everything else to the host.
+             */
             if (ignoredResolvedMethods.contains(original)) {
                 return null;
             } else {
@@ -102,5 +143,4 @@
         }
         return m;
     }
-
 }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotSafepointOp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotSafepointOp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -61,23 +61,23 @@
             masm.emitComment(" /* HSAIL safepoint bci=" + frameState.debugInfo().getBytecodePosition().getBCI() + ", frameState=" + frameState + " */");
             String afterSafepointLabel = "@LAfterSafepoint_at_pos_" + codeBufferPos;
 
-            AllocatableValue scratch64 = HSAIL.d16.asValue(Kind.Object);
-            AllocatableValue spAddrReg = HSAIL.d17.asValue(Kind.Object);
-            AllocatableValue scratch32 = HSAIL.s34.asValue(Kind.Int);
+            AllocatableValue scratch64 = HSAIL.d16.asValue(LIRKind.reference(Kind.Object));
+            AllocatableValue spAddrReg = HSAIL.d17.asValue(LIRKind.reference(Kind.Object));
+            AllocatableValue scratch32 = HSAIL.s34.asValue(LIRKind.value(Kind.Int));
             masm.emitLoadKernelArg(scratch64, masm.getDeoptInfoName(), "u64");
 
             // Build address of noticeSafepoints field
-            HSAILAddress noticeSafepointsAddr = new HSAILAddressValue(Kind.Object, scratch64, offsetToNoticeSafepoints).toAddress();
+            HSAILAddress noticeSafepointsAddr = new HSAILAddressValue(LIRKind.value(Kind.Long), scratch64, offsetToNoticeSafepoints).toAddress();
             masm.emitLoad(Kind.Object, spAddrReg, noticeSafepointsAddr);
 
             // Load int value from that field
-            HSAILAddress noticeSafepointsIntAddr = new HSAILAddressValue(Kind.Int, spAddrReg, 0).toAddress();
+            HSAILAddress noticeSafepointsIntAddr = new HSAILAddressValue(LIRKind.value(Kind.Long), spAddrReg, 0).toAddress();
             masm.emitLoadAcquire(scratch32, noticeSafepointsIntAddr);
             masm.emitCompare(Kind.Int, scratch32, Constant.forInt(0), "eq", false, false);
             masm.cbr(afterSafepointLabel);
 
-            AllocatableValue actionAndReasonReg = HSAIL.actionAndReasonReg.asValue(Kind.Int);
-            AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(Kind.Int);
+            AllocatableValue actionAndReasonReg = HSAIL.actionAndReasonReg.asValue(LIRKind.value(Kind.Int));
+            AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(LIRKind.value(Kind.Int));
             masm.emitMov(Kind.Int, actionAndReasonReg, actionAndReason);
             masm.emitMov(Kind.Int, codeBufferOffsetReg, Constant.forInt(codeBufferPos));
             masm.emitJumpToLabelName(masm.getDeoptLabelName());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILDirectLoadAcquireNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, 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.hsail.replacements;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.hotspot.hsail.*;
+import com.oracle.graal.word.*;
+
+public class HSAILDirectLoadAcquireNode extends DirectReadNode {
+
+    public HSAILDirectLoadAcquireNode(ValueNode address, Kind readKind) {
+        super(address, readKind);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        HSAILHotSpotLIRGenerator hsailgen = (HSAILHotSpotLIRGenerator) (gen.getLIRGeneratorTool());
+        LIRKind kind = hsailgen.getLIRKind(stamp());
+        Value result = hsailgen.emitLoadAcquire(kind, gen.operand(getAddress()), null);
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native long loadAcquire(long address, @ConstantNodeParameter Kind kind);
+
+    public static long loadAcquireLong(Word address) {
+        return loadAcquire(address.rawValue(), Kind.Long);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILDirectStoreReleaseNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, 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.hsail.replacements;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.hotspot.hsail.*;
+import com.oracle.graal.word.*;
+
+public class HSAILDirectStoreReleaseNode extends DirectStoreNode {
+
+    public HSAILDirectStoreReleaseNode(ValueNode address, ValueNode value, Kind kind) {
+        super(address, value, kind);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        HSAILHotSpotLIRGenerator hsailgen = (HSAILHotSpotLIRGenerator) (gen.getLIRGeneratorTool());
+        Value v = gen.operand(getValue());
+        LIRKind kind = hsailgen.getLIRKind(getValue().stamp());
+        hsailgen.emitStoreRelease(kind, gen.operand(getAddress()), v, null);
+    }
+
+    @NodeIntrinsic
+    public static native void storeRelease(long address, long value, @ConstantNodeParameter Kind kind);
+
+    public static void storeReleaseLong(Word address, long value) {
+        storeRelease(address.rawValue(), value, Kind.Long);
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILHotSpotReplacementsUtil.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILHotSpotReplacementsUtil.java	Mon Jun 30 12:02:19 2014 +0200
@@ -43,11 +43,37 @@
         hsailRegisters = registers;
     }
 
+    public static final LocationIdentity TLAB_INFO_LOCATION = new NamedLocationIdentity("TlabInfo");
+    public static final LocationIdentity TLABINFO_LASTGOODTOP_LOCATION = new NamedLocationIdentity("TlabInfoLastGoodTop");
+    public static final LocationIdentity TLABINFO_END_LOCATION = new NamedLocationIdentity("TlabInfoEnd");
+    public static final LocationIdentity TLABINFO_TOP_LOCATION = new NamedLocationIdentity("TlabInfoTop");
+    public static final LocationIdentity TLABINFO_START_LOCATION = new NamedLocationIdentity("TlabInfoStart");
+    public static final LocationIdentity TLABINFO_ALLOCINFO_LOCATION = new NamedLocationIdentity("TlabInfoAllocInfo");
+    public static final LocationIdentity TLABINFO_ORIGINALTOP_LOCATION = new NamedLocationIdentity("TlabInfoOriginalTop");
+    public static final LocationIdentity TLABINFO_DONORTHREAD_LOCATION = new NamedLocationIdentity("TlabInfoDonorThread");
+
+    public static final LocationIdentity ALLOCINFO_TLABINFOSPOOLNEXT_LOCATION = new NamedLocationIdentity("AllocInfoTlabInfosPoolNext");
+    public static final LocationIdentity ALLOCINFO_TLABINFOSPOOLEND_LOCATION = new NamedLocationIdentity("AllocInfoTlabInfosPoolEnd");
+    public static final LocationIdentity ALLOCINFO_TLABALIGNRESERVEBYTES_LOCATION = new NamedLocationIdentity("AllocInfoTlabAlignreservebytes");
+
     /**
-     * Gets the value of the thread register as a Word.
+     * Gets the value of the thread register as a Word. There is a level of indirection here. Thread
+     * register actually points to a holder for tlab info.
      */
-    public static Word thread() {
-        return registerAsWord(threadRegister(), true, false);
+    public static Word getTlabInfoPtr() {
+        Word threadRegAsWord = registerAsWord(threadRegister(), true, false);
+        return threadRegAsWord.readWord(0, TLAB_INFO_LOCATION);
+    }
+
+    public static Word getTlabInfoPtrLoadAcquire() {
+        Word threadRegAsWord = registerAsWord(threadRegister(), true, false);
+        return Word.unsigned(HSAILDirectLoadAcquireNode.loadAcquireLong(threadRegAsWord));
+    }
+
+    public static void writeTlabInfoPtrStoreRelease(Word val) {
+        // this only gets done in the waiting loop so we will always use Store Release
+        Word threadRegAsWord = registerAsWord(threadRegister(), true, false);
+        HSAILDirectStoreReleaseNode.storeReleaseLong(threadRegAsWord, val.rawValue());
     }
 
     @Fold
@@ -55,19 +81,64 @@
         return hsailRegisters.getThreadRegister();
     }
 
-    public static Word atomicGetAndAddTlabTop(Word thread, int size) {
-        return Word.unsigned(AtomicReadAndAddNode.getAndAddLong(null, thread.rawValue() + threadTlabTopOffset(), size, TLAB_TOP_LOCATION));
+    public static Word atomicGetAndAddTlabInfoTop(Word tlabInfo, int delta) {
+        return Word.unsigned(AtomicReadAndAddNode.getAndAddLong(null, tlabInfo.rawValue() + config().hsailTlabInfoTopOffset, delta, TLABINFO_TOP_LOCATION));
+    }
+
+    public static Word readTlabInfoEnd(Word tlabInfo) {
+        return tlabInfo.readWord(config().hsailTlabInfoEndOffset, TLABINFO_END_LOCATION);
+    }
+
+    public static Word readTlabInfoStart(Word tlabInfo) {
+        return tlabInfo.readWord(config().hsailTlabInfoStartOffset, TLABINFO_START_LOCATION);
+    }
+
+    public static void writeTlabInfoLastGoodTop(Word tlabInfo, Word val) {
+        tlabInfo.writeWord(config().hsailTlabInfoLastGoodTopOffset, val, TLABINFO_LASTGOODTOP_LOCATION);
+    }
+
+    public static void writeTlabInfoStart(Word tlabInfo, Word val) {
+        tlabInfo.writeWord(config().hsailTlabInfoStartOffset, val, TLABINFO_START_LOCATION);
+    }
+
+    public static void writeTlabInfoTop(Word tlabInfo, Word val) {
+        tlabInfo.writeWord(config().hsailTlabInfoTopOffset, val, TLABINFO_TOP_LOCATION);
+    }
+
+    public static void writeTlabInfoEnd(Word tlabInfo, Word val) {
+        tlabInfo.writeWord(config().hsailTlabInfoEndOffset, val, TLABINFO_END_LOCATION);
     }
 
-    public static final LocationIdentity TLAB_PFTOP_LOCATION = new NamedLocationIdentity("TlabPfTop");
+    public static Word readTlabInfoAllocInfo(Word tlabInfo) {
+        return tlabInfo.readWord(config().hsailTlabInfoAllocInfoOffset, TLABINFO_ALLOCINFO_LOCATION);
+    }
 
-    @Fold
-    public static int threadTlabPfTopOffset() {
-        return config().threadTlabPfTopOffset();
+    public static void writeTlabInfoAllocInfo(Word tlabInfo, Word val) {
+        tlabInfo.writeWord(config().hsailTlabInfoAllocInfoOffset, val, TLABINFO_ALLOCINFO_LOCATION);
+    }
+
+    public static void writeTlabInfoOriginalTop(Word tlabInfo, Word val) {
+        tlabInfo.writeWord(config().hsailTlabInfoOriginalTopOffset, val, TLABINFO_ORIGINALTOP_LOCATION);
     }
 
-    public static void writeTlabPfTop(Word thread, Word val) {
-        thread.writeWord(threadTlabPfTopOffset(), val, TLAB_PFTOP_LOCATION);
+    public static void writeTlabInfoDonorThread(Word tlabInfo, Word val) {
+        tlabInfo.writeWord(config().hsailTlabInfoDonorThreadOffset, val, TLABINFO_DONORTHREAD_LOCATION);
+    }
+
+    public static Word readTlabInfoDonorThread(Word tlabInfo) {
+        return tlabInfo.readWord(config().hsailTlabInfoDonorThreadOffset, TLABINFO_DONORTHREAD_LOCATION);
+    }
+
+    public static Word readAllocInfoTlabInfosPoolEnd(Word allocInfo) {
+        return allocInfo.readWord(config().hsailAllocInfoTlabInfosPoolEndOffset, ALLOCINFO_TLABINFOSPOOLEND_LOCATION);
+    }
+
+    public static Word readAllocInfoTlabAlignReserveBytes(Word allocInfo) {
+        return allocInfo.readWord(config().hsailAllocInfoTlabAlignReserveBytesOffset, ALLOCINFO_TLABALIGNRESERVEBYTES_LOCATION);
+    }
+
+    public static Word atomicGetAndAddAllocInfoTlabInfosPoolNext(Word allocInfo, int delta) {
+        return Word.unsigned(AtomicReadAndAddNode.getAndAddLong(null, allocInfo.rawValue() + config().hsailAllocInfoTlabInfosPoolNextOffset, delta, ALLOCINFO_TLABINFOSPOOLNEXT_LOCATION));
     }
 
 }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILNewObjectSnippets.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILNewObjectSnippets.java	Mon Jun 30 12:02:19 2014 +0200
@@ -60,6 +60,9 @@
         @Option(help = "In HSAIL allocation, allow allocation from eden as fallback if TLAB is full")
         static final OptionValue<Boolean> HsailUseEdenAllocate = new OptionValue<>(false);
 
+        @Option(help = "In HSAIL allocation, allow GPU to allocate a new tlab if TLAB is full")
+        static final OptionValue<Boolean> HsailNewTlabAllocate = new OptionValue<>(true);
+
         @Option(help = "Estimate of number of bytes allocated by each HSAIL workitem, used to size TLABs")
         static public final OptionValue<Integer> HsailAllocBytesPerWorkitem = new OptionValue<>(64);
 
@@ -67,44 +70,130 @@
     }
 
     private static final boolean hsailUseEdenAllocate = HsailUseEdenAllocate.getValue();
+    private static final boolean hsailNewTlabAllocate = HsailNewTlabAllocate.getValue();
+
+    protected static Word fillNewTlabInfoWithTlab(Word oldTlabInfo) {
+        Word allocInfo = readTlabInfoAllocInfo(oldTlabInfo);
+        Word newTlabInfo = atomicGetAndAddAllocInfoTlabInfosPoolNext(allocInfo, config().hsailTlabInfoSize);
+        Word tlabInfosPoolEnd = readAllocInfoTlabInfosPoolEnd(allocInfo);
+        if (newTlabInfo.aboveOrEqual(tlabInfosPoolEnd)) {
+            // could not get a new tlab info, mark zero and we will later deoptimize
+            return (Word.zero());
+        }
+
+        // make new size depend on old tlab size
+        Word newTlabSize = readTlabInfoEnd(oldTlabInfo).subtract(readTlabInfoStart(oldTlabInfo));
+        // try to allocate a new tlab
+        Word tlabStart = NewInstanceStub.edenAllocate(newTlabSize, false);
+        writeTlabInfoStart(newTlabInfo, tlabStart);  // write this field even if zero
+        if (tlabStart.equal(0)) {
+            // could not get a new tlab, mark zero and we will later deoptimize
+            return (Word.zero());
+        }
+        // here we have a new tlab and a tlabInfo, we can fill it in
+        writeTlabInfoTop(newTlabInfo, tlabStart);
+        writeTlabInfoOriginalTop(newTlabInfo, tlabStart);
+        // set end so that we leave space for the tlab "alignment reserve"
+        Word alignReserveBytes = readAllocInfoTlabAlignReserveBytes(allocInfo);
+        writeTlabInfoEnd(newTlabInfo, tlabStart.add(newTlabSize.subtract(alignReserveBytes)));
+        writeTlabInfoAllocInfo(newTlabInfo, allocInfo);
+        writeTlabInfoDonorThread(newTlabInfo, readTlabInfoDonorThread(oldTlabInfo));
+        return (newTlabInfo);
+    }
+
+    protected static Word allocateFromTlabSlowPath(Word fastPathTlabInfo, int size, Word fastPathTop, Word fastPathEnd) {
+        // eventually this will be a separate call, not inlined
+
+        // we come here from the fastpath allocation
+        // here we know that the tlab has overflowed (top + size > end)
+        // find out if we are the first overflower
+        Word tlabInfo = fastPathTlabInfo;
+        Word top = fastPathTop;
+        Word end = fastPathEnd;
+
+        // start a loop where we try to get a new tlab and then try to allocate from it
+        // keep doing this until we run out of tlabs or tlabInfo structures
+        // initialize result with error return value
+        Word result = Word.zero();
+        while (result.equal(Word.zero()) && tlabInfo.notEqual(Word.zero())) {
+            boolean firstOverflower = top.belowOrEqual(end);
+            if (firstOverflower) {
+                // store the last good top before overflow into last_good_top field
+                // we will move it back into top later when back in the VM
+                writeTlabInfoLastGoodTop(tlabInfo, top);
+            }
+
+            // if all this allocate tlab from gpu logic is disabled,
+            // just immediately set tlabInfo to 0 here
+            if (!hsailNewTlabAllocate) {
+                tlabInfo = Word.zero();
+            } else {
+                // loop here waiting for the first overflower to get a new tlab
+                // note that on an hsa device we must be careful how we loop in order to ensure
+                // "forward progress". For example we must not break out of the loop.
+                Word oldTlabInfo = tlabInfo;
+                do {
+                    if (firstOverflower) {
+                        // allocate new tlabInfo and new tlab to fill it, returning 0 if any
+                        // problems
+                        // this will get all spinners out of this loop.
+                        tlabInfo = fillNewTlabInfoWithTlab(oldTlabInfo);
+                        writeTlabInfoPtrStoreRelease(tlabInfo);
+                    } else {
+                        tlabInfo = getTlabInfoPtrLoadAcquire();
+                    }
+                } while (tlabInfo.equal(oldTlabInfo));
+                // when we get out of the loop if tlabInfoPtr contains 0, it means we
+                // can't get any more tlabs and will have to deoptimize
+                // otherwise, we have a valid new tlabInfo/tlab and can try to allocate again.
+                if (tlabInfo.notEqual(0)) {
+                    top = atomicGetAndAddTlabInfoTop(tlabInfo, size);
+                    end = readTlabInfoEnd(tlabInfo);
+                    Word newTop = top.add(size);
+                    if (probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
+                        result = top;
+                    }
+                }
+            }
+        } // while (result == 0) && (tlabInfo != 0))
+        return result;
+    }
+
+    protected static Object addressToFormattedObject(Word addr, @ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents,
+                    @ConstantParameter String typeContext) {
+        Object result = formatObject(hub, size, addr, prototypeMarkWord, fillContents, true, true);
+        profileAllocation("instance", size, typeContext);
+        return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
+    }
 
     @Snippet
     public static Object allocateInstanceAtomic(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter String typeContext) {
-        Word thread = thread();
         boolean haveResult = false;
         if (useTLAB()) {
-            Word top = atomicGetAndAddTlabTop(thread, size);
-            Word end = readTlabEnd(thread);
-            Word newTop = top.add(size);
-            if (probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
-                // writeTlabTop(thread, newTop) was done by the atomicGetAndAdd
-                Object result = formatObject(hub, size, top, prototypeMarkWord, fillContents, true, false, true);
-                profileAllocation("instance", size, typeContext);
-                return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
-            } else {
-                // only one overflower will be the first overflower, detectable because
-                // oldtop was still below end
-                if (top.belowOrEqual(end)) {
-                    // hack alert: store the last good top before overflow into pf_top
-                    // we will move it back into top later when back in the VM
-                    writeTlabPfTop(thread, top);
+            // inlining this manually here because it resulted in better fastpath codegen
+            Word tlabInfo = getTlabInfoPtr();
+            if (probability(FAST_PATH_PROBABILITY, tlabInfo.notEqual(0))) {
+                Word top = atomicGetAndAddTlabInfoTop(tlabInfo, size);
+                Word end = readTlabInfoEnd(tlabInfo);
+                Word newTop = top.add(size);
+                if (probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
+                    return addressToFormattedObject(top, size, hub, prototypeMarkWord, fillContents, typeContext);
+                } else {
+                    Word addr = allocateFromTlabSlowPath(tlabInfo, size, top, end);
+                    if (addr.notEqual(0)) {
+                        return addressToFormattedObject(addr, size, hub, prototypeMarkWord, fillContents, typeContext);
+                    }
                 }
-                // useless logic but see notes on deopt path below
-                haveResult = newTop.belowOrEqual(end);
             }
         }
+
+        // we could not allocate from tlab, try allocating directly from eden
         if (hsailUseEdenAllocate) {
-            // originally:
-            // result = NewInstanceStubCall.call(hub);
-
-            // we could not allocate from tlab, try allocating directly from eden
             // false for no logging
-            Word memory = NewInstanceStub.edenAllocate(Word.unsigned(size), false);
-            if (memory.notEqual(0)) {
+            Word addr = NewInstanceStub.edenAllocate(Word.unsigned(size), false);
+            if (addr.notEqual(0)) {
                 new_eden.inc();
-                Object result = formatObject(hub, size, memory, prototypeMarkWord, fillContents, true, false, true);
-                profileAllocation("instance", size, typeContext);
-                return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
+                return addressToFormattedObject(addr, size, hub, prototypeMarkWord, fillContents, typeContext);
             }
         }
         // haveResult test here helps avoid dropping earlier stores were seen to be dropped without
@@ -126,44 +215,43 @@
         return allocateArrayAtomicImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, maybeUnroll, typeContext);
     }
 
+    protected static Object addressToFormattedArray(Word addr, int allocationSize, int length, int headerSize, Word hub, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll,
+                    @ConstantParameter String typeContext) {
+        // we are not in a stub so we can set useSnippetCounters to true
+        Object result = formatArray(hub, allocationSize, length, headerSize, addr, prototypeMarkWord, fillContents, maybeUnroll, true);
+        profileAllocation("array", allocationSize, typeContext);
+        return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
+    }
+
     private static Object allocateArrayAtomicImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, boolean maybeUnroll, String typeContext) {
         int alignment = wordSize();
         int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
-        Word thread = thread();
         boolean haveResult = false;
         if (useTLAB()) {
-            Word top = atomicGetAndAddTlabTop(thread, allocationSize);
-            Word end = readTlabEnd(thread);
-            Word newTop = top.add(allocationSize);
-            if (probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
-                // writeTlabTop(thread, newTop) was done by the atomicGetAndAdd
-                newarray_loopInit.inc();
-                // we are not in a stub so we can set useSnippetCounters to true
-                Object result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, true);
-                profileAllocation("array", allocationSize, typeContext);
-                return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
-            } else {
-                // only one overflower will be the first overflower, detectable because
-                // oldtop was still below end
-                if (top.belowOrEqual(end)) {
-                    // hack alert: store the last good top before overflow into pf_top
-                    // we will move it back into top later when back in the VM
-                    writeTlabPfTop(thread, top);
+            // inlining this manually here because it resulted in better fastpath codegen
+            Word tlabInfo = getTlabInfoPtr();
+            if (probability(FAST_PATH_PROBABILITY, tlabInfo.notEqual(0))) {
+                Word top = atomicGetAndAddTlabInfoTop(tlabInfo, allocationSize);
+                Word end = readTlabInfoEnd(tlabInfo);
+                Word newTop = top.add(allocationSize);
+                if (probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
+                    return addressToFormattedArray(top, allocationSize, length, headerSize, hub, prototypeMarkWord, fillContents, maybeUnroll, typeContext);
+                } else {
+                    Word addr = allocateFromTlabSlowPath(tlabInfo, allocationSize, top, end);
+                    if (addr.notEqual(0)) {
+                        return addressToFormattedArray(addr, allocationSize, length, headerSize, hub, prototypeMarkWord, fillContents, maybeUnroll, typeContext);
+                    }
                 }
-                // useless logic but see notes on deopt path below
-                haveResult = newTop.belowOrEqual(end);
             }
         }
+
         // we could not allocate from tlab, try allocating directly from eden
         if (hsailUseEdenAllocate) {
             // false for no logging
-            Word memory = NewInstanceStub.edenAllocate(Word.unsigned(allocationSize), false);
-            if (memory.notEqual(0)) {
+            Word addr = NewInstanceStub.edenAllocate(Word.unsigned(allocationSize), false);
+            if (addr.notEqual(0)) {
                 newarray_eden.inc();
-                // we are not in a stub so we can set useSnippetCounters to true
-                Object result = formatArray(hub, allocationSize, length, headerSize, memory, prototypeMarkWord, fillContents, maybeUnroll, true);
-                profileAllocation("array", allocationSize, typeContext);
-                return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
+                return addressToFormattedArray(addr, allocationSize, length, headerSize, hub, prototypeMarkWord, fillContents, maybeUnroll, typeContext);
             }
         }
         if (!haveResult) {
@@ -225,12 +313,13 @@
 
             Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage());
             args.add("hub", hub);
-            args.add("length", newArrayNode.length());
+            ValueNode length = newArrayNode.length();
+            args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
             args.add("prototypeMarkWord", arrayType.prototypeMarkWord());
             args.addConst("headerSize", headerSize);
             args.addConst("log2ElementSize", log2ElementSize);
             args.addConst("fillContents", newArrayNode.fillContents());
-            args.addConst("maybeUnroll", newArrayNode.length().isConstant());
+            args.addConst("maybeUnroll", length.isConstant());
             args.addConst("typeContext", MetaUtil.toJavaName(arrayType, false));
 
             SnippetTemplate template = template(args);
@@ -250,6 +339,7 @@
     private static final SnippetCounter new_eden = new SnippetCounter(countersNew, "eden", "used edenAllocate");
 
     private static final SnippetCounter.Group countersNewArray = SnippetCounters.getValue() ? new SnippetCounter.Group("NewArray") : null;
-    private static final SnippetCounter newarray_loopInit = new SnippetCounter(countersNewArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop");
+    // private static final SnippetCounter newarray_loopInit = new SnippetCounter(countersNewArray,
+    // "tlabLoopInit", "TLAB alloc with zeroing in a loop");
     private static final SnippetCounter newarray_eden = new SnippetCounter(countersNewArray, "eden", "used edenAllocate");
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILWorkItemAbsIdNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, 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.hsail.replacements;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.hotspot.hsail.*;
+
+public class HSAILWorkItemAbsIdNode extends FixedWithNextNode implements LIRLowerable {
+
+    public HSAILWorkItemAbsIdNode() {
+        super(StampFactory.forKind(Kind.Int));
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        HSAILHotSpotLIRGenerator hsailgen = (HSAILHotSpotLIRGenerator) (gen.getLIRGeneratorTool());
+        Value result = hsailgen.emitWorkItemAbsId();
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native int getWorkItemAbsId();
+
+}
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -93,7 +93,7 @@
         final int stackFrameAlignment = 1;
         final int implicitNullCheckLimit = 0;
         final boolean inlineObjects = true;
-        return new HotSpotTargetDescription(createArchitecture(), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects, Kind.Int);
+        return new HotSpotTargetDescription(createArchitecture(), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
     }
 
     public String getArchitecture() {
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotRegisterConfig.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotRegisterConfig.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -110,7 +110,7 @@
         if (returnKind == Kind.Void) {
             returnLocation = Value.ILLEGAL;
         } else {
-            returnLocation = new Variable(returnKind, currentGeneral++);
+            returnLocation = new Variable(target.getLIRKind(returnKind), currentGeneral++);
         }
 
         AllocatableValue[] locations = new AllocatableValue[parameterTypes.length];
@@ -129,7 +129,7 @@
                 case Double:
                 case Object:
                     if (!stackOnly) {
-                        locations[i] = new Variable(kind, currentGeneral++);
+                        locations[i] = new Variable(target.getLIRKind(kind), currentGeneral++);
                     }
                     break;
                 default:
@@ -137,7 +137,7 @@
             }
 
             if (locations[i] == null) {
-                locations[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, !type.out);
+                locations[i] = StackSlot.get(target.getLIRKind(kind.getStackKind()), currentStackOffset, !type.out);
                 currentStackOffset += Math.max(target.getSizeInBytes(kind), target.wordSize);
             }
         }
--- a/graal/com.oracle.graal.hotspot.sourcegen/src/com/oracle/graal/hotspot/sourcegen/GenGraalRuntimeInlineHpp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sourcegen/src/com/oracle/graal/hotspot/sourcegen/GenGraalRuntimeInlineHpp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -37,6 +37,26 @@
  */
 public class GenGraalRuntimeInlineHpp {
 
+    private static final ZipFile graalJar;
+
+    static {
+        String path = null;
+        String classPath = System.getProperty("java.class.path");
+        for (String e : classPath.split(File.pathSeparator)) {
+            if (e.endsWith("graal.jar")) {
+                path = e;
+                break;
+            }
+        }
+        ZipFile zipFile = null;
+        try {
+            zipFile = new ZipFile(Objects.requireNonNull(path, "Could not find graal.jar on class path: " + classPath));
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+        graalJar = zipFile;
+    }
+
     public static void main(String[] args) {
         PrintStream out = System.out;
         try {
@@ -52,17 +72,8 @@
      * Generates code for {@code GraalRuntime::get_service_impls()}.
      */
     private static void genGetServiceImpls(PrintStream out) throws Exception {
-        String graalJar = null;
-        String classPath = System.getProperty("java.class.path");
-        for (String e : classPath.split(File.pathSeparator)) {
-            if (e.endsWith("graal.jar")) {
-                graalJar = e;
-                break;
-            }
-        }
         final List<Class<? extends Service>> services = new ArrayList<>();
-        final ZipFile zipFile = new ZipFile(new File(Objects.requireNonNull(graalJar, "Could not find graal.jar on class path: " + classPath)));
-        for (final Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements();) {
+        for (final Enumeration<? extends ZipEntry> e = graalJar.entries(); e.hasMoreElements();) {
             final ZipEntry zipEntry = e.nextElement();
             String name = zipEntry.getName();
             if (name.startsWith("META-INF/services/")) {
@@ -129,8 +140,9 @@
         }
         lengths.add("PrintFlags".length());
 
-        out.println("bool GraalRuntime::set_option(KlassHandle hotSpotOptionsClass, const char* name, int name_len, Handle name_handle, const char* value, TRAPS) {");
-        out.println("  if (value[0] == '+' || value[0] == '-') {");
+        out.println("bool GraalRuntime::set_option(KlassHandle hotSpotOptionsClass, char* name, int name_len, const char* value, TRAPS) {");
+        out.println("  bool check_only = hotSpotOptionsClass.is_null();");
+        out.println("  if (value != NULL && (value[0] == '+' || value[0] == '-')) {");
         out.println("    // boolean options");
         genMatchers(out, lengths, options, true);
         out.println("  } else {");
@@ -153,7 +165,11 @@
                 out.println("    case " + len + ":");
                 out.printf("      if (strncmp(name, \"PrintFlags\", %d) == 0) {%n", len);
                 out.println("        if (value[0] == '+') {");
-                out.println("          set_option_helper(hotSpotOptionsClass, name_handle, Handle(), '?', Handle(), 0L);");
+                out.println("          if (check_only) {");
+                out.println("            TempNewSymbol name = SymbolTable::new_symbol(\"Lcom/oracle/graal/hotspot/HotSpotOptions;\", THREAD);");
+                out.println("            hotSpotOptionsClass = SystemDictionary::resolve_or_fail(name, true, CHECK_(true));");
+                out.println("          }");
+                out.println("          set_option_helper(hotSpotOptionsClass, name, name_len, Handle(), '?', Handle(), 0L);");
                 out.println("        }");
                 out.println("        return true;");
                 out.println("      }");
@@ -167,17 +183,28 @@
                     }
                     out.printf("      if (strncmp(name, \"%s\", %d) == 0) {%n", e.getKey(), len);
                     Class<?> declaringClass = desc.getDeclaringClass();
-                    out.printf("        Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));%n", toInternalName(declaringClass), desc.getFieldName(),
-                                    toInternalName(getFieldType(desc)));
                     if (isBoolean) {
-                        out.println("        set_option_helper(hotSpotOptionsClass, name_handle, option, value[0], Handle(), 0L);");
+                        out.printf("        Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));%n", toInternalName(declaringClass), desc.getFieldName(),
+                                        toInternalName(getFieldType(desc)));
+                        out.println("        if (!check_only) {");
+                        out.println("          set_option_helper(hotSpotOptionsClass, name, name_len, option, value[0], Handle(), 0L);");
+                        out.println("        }");
                     } else if (desc.getType() == String.class) {
-                        out.println("        Handle stringValue = java_lang_String::create_from_str(value, CHECK_(true));");
-                        out.println("        set_option_helper(hotSpotOptionsClass, name_handle, option, 's', stringValue, 0L);");
+                        out.println("        check_required_value(name, name_len, value, CHECK_(true));");
+                        out.printf("        Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));%n", toInternalName(declaringClass), desc.getFieldName(),
+                                        toInternalName(getFieldType(desc)));
+                        out.println("        if (!check_only) {");
+                        out.println("          Handle stringValue = java_lang_String::create_from_str(value, CHECK_(true));");
+                        out.println("          set_option_helper(hotSpotOptionsClass, name, name_len, option, 's', stringValue, 0L);");
+                        out.println("        }");
                     } else {
                         char spec = getPrimitiveSpecChar(desc);
-                        out.println("        jlong primitiveValue = parse_primitive_option_value('" + spec + "', name_handle, value, CHECK_(true));");
-                        out.println("        set_option_helper(hotSpotOptionsClass, name_handle, option, '" + spec + "', Handle(), primitiveValue);");
+                        out.println("        jlong primitiveValue = parse_primitive_option_value('" + spec + "', name, name_len, value, CHECK_(true));");
+                        out.println("        if (!check_only) {");
+                        out.printf("          Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));%n", toInternalName(declaringClass), desc.getFieldName(),
+                                        toInternalName(getFieldType(desc)));
+                        out.println("          set_option_helper(hotSpotOptionsClass, name, name_len, option, '" + spec + "', Handle(), primitiveValue);");
+                        out.println("        }");
                     }
                     out.println("        return true;");
                     out.println("      }");
@@ -191,7 +218,14 @@
     static SortedMap<String, OptionDescriptor> getOptions() throws Exception {
         Field field = Class.forName("com.oracle.graal.hotspot.HotSpotOptionsLoader").getDeclaredField("options");
         field.setAccessible(true);
-        return (SortedMap<String, OptionDescriptor>) field.get(null);
+        SortedMap<String, OptionDescriptor> options = (SortedMap<String, OptionDescriptor>) field.get(null);
+
+        Set<Class<?>> checked = new HashSet<>();
+        for (final OptionDescriptor option : options.values()) {
+            Class<?> cls = option.getDeclaringClass();
+            OptionsVerifier.checkClass(cls, option, checked, graalJar);
+        }
+        return options;
     }
 
     private static Class<?> getFieldType(OptionDescriptor desc) throws Exception {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sourcegen/src/com/oracle/graal/hotspot/sourcegen/OptionsVerifier.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,186 @@
+/*
+ * 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.sourcegen;
+
+import static java.lang.String.*;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.zip.*;
+
+import jdk.internal.org.objectweb.asm.*;
+import jdk.internal.org.objectweb.asm.Type;
+
+import com.oracle.graal.options.*;
+
+/**
+ * A {@link ClassVisitor} that verifies a class declaring one or more {@linkplain OptionValue
+ * options} has a class initializer that only initializes the option(s). This sanity check mitigates
+ * the possibility of an option value being used before the code that sets the value (e.g., from the
+ * command line) has been executed.
+ */
+final class OptionsVerifier extends ClassVisitor {
+
+    public static void checkClass(Class<?> cls, OptionDescriptor option, Set<Class<?>> checked, ZipFile graalJar) throws IOException {
+        if (!checked.contains(cls)) {
+            checked.add(cls);
+            Class<?> superclass = cls.getSuperclass();
+            if (superclass != null && !superclass.equals(Object.class)) {
+                checkClass(superclass, option, checked, graalJar);
+            }
+
+            String classFilePath = cls.getName().replace('.', '/') + ".class";
+            ZipEntry entry = Objects.requireNonNull(graalJar.getEntry(classFilePath), "Could not find class file for " + cls.getName());
+            ClassReader cr = new ClassReader(graalJar.getInputStream(entry));
+
+            ClassVisitor cv = new OptionsVerifier(cls, option);
+            cr.accept(cv, 0);
+        }
+    }
+
+    /**
+     * The option field context of the verification.
+     */
+    private final OptionDescriptor option;
+
+    /**
+     * The class in which {@link #option} is declared or a super-class of that class. This is the
+     * class whose {@code <clinit>} method is being verified.
+     */
+    private final Class<?> cls;
+
+    /**
+     * Source file context for error reporting.
+     */
+    String sourceFile = null;
+
+    /**
+     * Line number for error reporting.
+     */
+    int lineNo = -1;
+
+    final Class<?>[] boxingTypes = {Boolean.class, Byte.class, Short.class, Character.class, Integer.class, Float.class, Long.class, Double.class};
+
+    private static Class<?> resolve(String name) {
+        try {
+            return Class.forName(name.replace('/', '.'));
+        } catch (ClassNotFoundException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    OptionsVerifier(Class<?> cls, OptionDescriptor desc) {
+        super(Opcodes.ASM5);
+        this.cls = cls;
+        this.option = desc;
+    }
+
+    @Override
+    public void visitSource(String source, String debug) {
+        this.sourceFile = source;
+    }
+
+    void verify(boolean condition, String message) {
+        if (!condition) {
+            error(message);
+        }
+    }
+
+    void error(String message) {
+        String errorMessage = format("%s:%d: Illegal code in %s.<clinit> which may be executed when %s.%s is initialized:%n%n    %s%n%n" + "The recommended solution is to move " + option.getName() +
+                        " into a separate class (e.g., %s.Options).%n", sourceFile, lineNo, cls.getSimpleName(), option.getDeclaringClass().getSimpleName(), option.getName(), message,
+                        option.getDeclaringClass().getSimpleName());
+        throw new InternalError(errorMessage);
+
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String d, String signature, String[] exceptions) {
+        if (name.equals("<clinit>")) {
+            return new MethodVisitor(Opcodes.ASM5) {
+
+                @Override
+                public void visitLineNumber(int line, Label start) {
+                    lineNo = line;
+                }
+
+                @Override
+                public void visitFieldInsn(int opcode, String owner, String fieldName, String fieldDesc) {
+                    if (opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC) {
+                        verify(resolve(owner).equals(option.getDeclaringClass()), format("store to field %s.%s", resolve(owner).getSimpleName(), fieldName));
+                        verify(opcode != Opcodes.PUTFIELD, format("store to non-static field %s.%s", resolve(owner).getSimpleName(), fieldName));
+                    }
+                }
+
+                private Executable resolveMethod(String owner, String methodName, String methodDesc) {
+                    Class<?> declaringClass = resolve(owner);
+                    if (methodName.equals("<init>")) {
+                        for (Constructor<?> c : declaringClass.getDeclaredConstructors()) {
+                            if (methodDesc.equals(Type.getConstructorDescriptor(c))) {
+                                return c;
+                            }
+                        }
+                    } else {
+                        Type[] argumentTypes = Type.getArgumentTypes(methodDesc);
+                        for (Method m : declaringClass.getDeclaredMethods()) {
+                            if (m.getName().equals(methodName)) {
+                                if (Arrays.equals(argumentTypes, Type.getArgumentTypes(m))) {
+                                    if (Type.getReturnType(methodDesc).equals(Type.getReturnType(m))) {
+                                        return m;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    throw new NoSuchMethodError(declaringClass + "." + methodName + methodDesc);
+                }
+
+                /**
+                 * Checks whether a given method is allowed to be called.
+                 */
+                private boolean checkInvokeTarget(Executable method) {
+                    Class<?> holder = method.getDeclaringClass();
+                    if (method instanceof Constructor) {
+                        if (OptionValue.class.isAssignableFrom(holder)) {
+                            return true;
+                        }
+                    } else if (Arrays.asList(boxingTypes).contains(holder)) {
+                        return method.getName().equals("valueOf");
+                    } else if (method.getDeclaringClass().equals(Class.class)) {
+                        return method.getName().equals("desiredAssertionStatus");
+                    }
+                    return false;
+                }
+
+                @Override
+                public void visitMethodInsn(int opcode, String owner, String methodName, String methodDesc, boolean itf) {
+                    Executable callee = resolveMethod(owner, methodName, methodDesc);
+                    verify(checkInvokeTarget(callee), "invocation of " + callee);
+                }
+            };
+        } else {
+            return null;
+        }
+    }
+}
\ No newline at end of file
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -42,7 +42,7 @@
         final int stackFrameAlignment = 16;
         final int implicitNullCheckLimit = 4096;
         final boolean inlineObjects = true;
-        return new HotSpotTargetDescription(createArchitecture(), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects, Kind.Int);
+        return new HotSpotTargetDescription(createArchitecture(), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
     }
 
     public HotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotBackend host) {
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Mon Jun 30 12:02:19 2014 +0200
@@ -52,10 +52,10 @@
         // The calling convention for the exception handler stub is (only?) defined in
         // TemplateInterpreterGenerator::generate_throw_exception()
         // in templateInterpreter_sparc.cpp around line 1925
-        RegisterValue outgoingException = o0.asValue(Kind.Object);
-        RegisterValue outgoingExceptionPc = o1.asValue(word);
-        RegisterValue incomingException = i0.asValue(Kind.Object);
-        RegisterValue incomingExceptionPc = i1.asValue(word);
+        RegisterValue outgoingException = o0.asValue(target.getLIRKind(Kind.Object));
+        RegisterValue outgoingExceptionPc = o1.asValue(target.getLIRKind(word));
+        RegisterValue incomingException = i0.asValue(target.getLIRKind(Kind.Object));
+        RegisterValue incomingExceptionPc = i1.asValue(LIRKind.value(word));
         CallingConvention outgoingExceptionCc = new CallingConvention(0, ILLEGAL, outgoingException, outgoingExceptionPc);
         CallingConvention incomingExceptionCc = new CallingConvention(0, ILLEGAL, incomingException, incomingExceptionPc);
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Mon Jun 30 12:02:19 2014 +0200
@@ -120,7 +120,7 @@
     public void emitReturn(Value input) {
         AllocatableValue operand = Value.ILLEGAL;
         if (input != null) {
-            operand = resultOperandFor(input.getKind());
+            operand = resultOperandFor(input.getLIRKind());
             emitMove(operand, input);
         }
         append(new SPARCHotSpotReturnOp(operand, getStub() != null));
@@ -148,9 +148,9 @@
     }
 
     private void moveValueToThread(Value v, int offset) {
-        Kind wordKind = getProviders().getCodeCache().getTarget().wordKind;
+        LIRKind wordKind = LIRKind.value(getProviders().getCodeCache().getTarget().wordKind);
         RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
-        SPARCAddressValue pendingDeoptAddress = new SPARCAddressValue(v.getKind(), thread, offset);
+        SPARCAddressValue pendingDeoptAddress = new SPARCAddressValue(wordKind, thread, offset);
         append(new StoreOp(v.getKind(), pendingDeoptAddress, emitMove(v), null));
     }
 
@@ -167,25 +167,25 @@
     }
 
     @Override
-    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
+    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
         SPARCAddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(kind);
-        append(new LoadOp((Kind) kind, result, loadAddress, state));
+        append(new LoadOp((Kind) kind.getPlatformKind(), result, loadAddress, state));
         return result;
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
+    public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) {
         SPARCAddressValue storeAddress = asAddressValue(address);
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
             if (canStoreConstant(c)) {
-                append(new StoreConstantOp((Kind) kind, storeAddress, c, state));
+                append(new StoreConstantOp((Kind) kind.getPlatformKind(), storeAddress, c, state));
                 return;
             }
         }
         Variable input = load(inputVal);
-        append(new StoreOp((Kind) kind, storeAddress, input, state));
+        append(new StoreOp((Kind) kind.getPlatformKind(), storeAddress, input, state));
     }
 
     public Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
@@ -243,7 +243,7 @@
         for (int i = 0; i < savedRegisters.length; i++) {
             PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
             assert kind != Kind.Illegal;
-            StackSlot spillSlot = getResult().getFrameMap().allocateSpillSlot(kind);
+            StackSlot spillSlot = getResult().getFrameMap().allocateSpillSlot(LIRKind.value(kind));
             savedRegisterLocations[i] = spillSlot;
         }
         return emitSaveRegisters(savedRegisters, savedRegisterLocations, false);
@@ -261,7 +261,7 @@
         Register thread = getProviders().getRegisters().getThreadRegister();
         Variable framePcVariable = load(framePc);
         Variable senderSpVariable = load(senderSp);
-        Variable scratchVariable = newVariable(getHostWordKind());
+        Variable scratchVariable = newVariable(LIRKind.value(getHostWordKind()));
         append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable));
     }
 
@@ -284,7 +284,7 @@
         Register threadRegister = getProviders().getRegisters().getThreadRegister();
         Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
         append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister));
-        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(Kind.Long), trapRequest);
+        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(Kind.Long)), trapRequest);
         append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister));
 
         return result;
@@ -297,7 +297,7 @@
         Register threadRegister = getProviders().getRegisters().getThreadRegister();
         Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
         append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister));
-        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(Kind.Long));
+        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(Kind.Long)));
         append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister));
 
         return result;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -52,7 +52,7 @@
 
     @Override
     protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeMap<Value> nodeOperands) {
-        HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMap(), Kind.Long);
+        HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMap(), LIRKind.value(Kind.Long));
         return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
     }
 
@@ -68,17 +68,17 @@
 
     @Override
     public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
-        Kind kind = x.newValue().getKind();
-        assert kind == x.expectedValue().getKind();
-
         Variable address = gen.load(operand(x.object()));
         Value offset = operand(x.offset());
         Variable cmpValue = (Variable) gen.loadNonConst(operand(x.expectedValue()));
         Variable newValue = gen.load(operand(x.newValue()));
 
+        LIRKind kind = cmpValue.getLIRKind();
+        assert kind.equals(newValue.getLIRKind());
+
         if (ValueUtil.isConstant(offset)) {
             assert !gen.getCodeCache().needsDataPatch(asConstant(offset));
-            Variable longAddress = newVariable(Kind.Long);
+            Variable longAddress = gen.newVariable(LIRKind.value(Kind.Long));
             gen.emitMove(longAddress, address);
             address = getGen().emitAdd(longAddress, asConstant(offset));
         } else {
@@ -88,10 +88,7 @@
         }
 
         append(new CompareAndSwapOp(address, cmpValue, newValue));
-
-        Variable result = newVariable(x.getKind());
-        gen.emitMove(result, newValue);
-        setResult(x, result);
+        setResult(x, gen.emitMove(newValue));
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -206,7 +206,7 @@
                 case Object:
                     if (!stackOnly && currentGeneral < generalParameterRegisters.length) {
                         Register register = generalParameterRegisters[currentGeneral++];
-                        locations[i] = register.asValue(kind);
+                        locations[i] = register.asValue(target.getLIRKind(kind));
                     }
                     break;
                 case Double:
@@ -217,13 +217,13 @@
                         }
                         Register register = fpuParameterRegisters[currentFloating];
                         currentFloating += 2; // Only every second is a double register
-                        locations[i] = register.asValue(kind);
+                        locations[i] = register.asValue(target.getLIRKind(kind));
                     }
                     break;
                 case Float:
                     if (!stackOnly && currentFloating < fpuParameterRegisters.length) {
                         Register register = fpuParameterRegisters[currentFloating++];
-                        locations[i] = register.asValue(kind);
+                        locations[i] = register.asValue(target.getLIRKind(kind));
                     }
                     break;
                 default:
@@ -231,13 +231,13 @@
             }
 
             if (locations[i] == null) {
-                locations[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, !type.out);
+                locations[i] = StackSlot.get(target.getLIRKind(kind.getStackKind()), currentStackOffset, !type.out);
                 currentStackOffset += Math.max(target.getSizeInBytes(kind), target.wordSize);
             }
         }
 
         Kind returnKind = returnType == null ? Kind.Void : returnType.getKind();
-        AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind, type).asValue(returnKind.getStackKind());
+        AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind, type).asValue(target.getLIRKind(returnKind.getStackKind()));
         return new CallingConvention(currentStackOffset, returnLocation, locations);
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -52,7 +52,7 @@
     public SPARCHotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, LIRGeneratorTool tool) {
         this.state = state;
         this.config = config;
-        temp = tool.newVariable(tool.target().wordKind);
+        temp = tool.newVariable(LIRKind.value(tool.target().wordKind));
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -692,7 +692,7 @@
             };
 
             DebugConfig debugConfig = DebugScope.getConfig();
-            DebugConfig fixedConfig = Debug.fixedConfig(false, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.output());
+            DebugConfig fixedConfig = Debug.fixedConfig(false, false, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.verifyHandlers(), debugConfig.output());
             try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
                 ReentrantNodeIterator.apply(closure, graph.start(), false);
                 new WriteBarrierVerificationPhase().apply(graph);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationQueue.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationQueue.java	Mon Jun 30 12:02:19 2014 +0200
@@ -40,6 +40,8 @@
 import com.oracle.graal.options.*;
 import com.oracle.graal.printer.*;
 
+//JaCoCo Exclude
+
 /**
  * A queue for running {@link CompilationTask}s on background compilation thread(s). The singleton
  * {@linkplain #queue() instance} is created the first time this class is accessed.
@@ -52,6 +54,10 @@
     static {
         try (InitTimer t = timer("initialize CompilationQueue")) {
 
+            // The Graal runtime needs to be initialized here to avoid
+            // issues re-entering Java code during compilation scheduling.
+            HotSpotGraalRuntime.runtime();
+
             // Must be first to ensure any options accessed by the rest of the class
             // initializer are initialized from the command line.
             HotSpotOptions.initialize();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon Jun 30 12:02:19 2014 +0200
@@ -63,6 +63,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.printer.*;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
@@ -240,6 +241,11 @@
     protected PhaseSuite<HighTierContext> getGraphBuilderSuite(HotSpotProviders providers) {
         PhaseSuite<HighTierContext> suite = providers.getSuites().getDefaultGraphBuilderSuite();
 
+        if (HotSpotGraalRuntime.runtime().getCompilerToVM().shouldDebugNonSafepoints()) {
+            // need to tweak the graph builder config
+            suite.findPhase(GraphBuilderPhase.class).set(new GraphBuilderPhase(GraphBuilderConfiguration.getInfopointDefault()));
+        }
+
         boolean osrCompilation = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
         if (osrCompilation) {
             suite = suite.copy();
@@ -490,21 +496,31 @@
     }
 
     /**
-     * Entry point for the VM to schedule a compilation for a metaspace Method.
+     * Schedules compilation of a metaspace Method.
      *
      * Called from the VM.
      */
     @SuppressWarnings("unused")
     private static void compileMetaspaceMethod(long metaspaceMethod, final int entryBCI, long ctask, final boolean blocking) {
-        final HotSpotResolvedJavaMethod method = HotSpotResolvedJavaMethod.fromMetaspace(metaspaceMethod);
         if (ctask != 0L) {
+            // Ensure a Graal runtime is initialized prior to Debug being initialized as the former
+            // may include processing command line options used by the latter.
+            Graal.getRuntime();
+
+            // Ensure a debug configuration for this thread is initialized
+            if (Debug.isEnabled() && DebugScope.getConfig() == null) {
+                DebugEnvironment.initialize(System.out);
+            }
+
             // This is on a VM CompilerThread - no user frames exist
+            final HotSpotResolvedJavaMethod method = HotSpotResolvedJavaMethod.fromMetaspace(metaspaceMethod);
             compileMethod(method, entryBCI, ctask, false);
         } else {
             // We have to use a privileged action here because compilations are
             // enqueued from user code which very likely contains unprivileged frames.
             AccessController.doPrivileged(new PrivilegedAction<Void>() {
                 public Void run() {
+                    final HotSpotResolvedJavaMethod method = HotSpotResolvedJavaMethod.fromMetaspace(metaspaceMethod);
                     compileMethod(method, entryBCI, 0L, blocking);
                     return null;
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java	Mon Jun 30 12:02:19 2014 +0200
@@ -269,4 +269,12 @@
     public boolean needsJavaFrameAnchor() {
         return canDeoptimize() || transition == Transition.LEAF_SP;
     }
+
+    public CompilationResult getStubCompilationResult(final Backend backend) {
+        return stub.getCompilationResult(backend);
+    }
+
+    public Stub getStub() {
+        return stub;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Mon Jun 30 12:02:19 2014 +0200
@@ -52,7 +52,6 @@
 import com.oracle.graal.hotspot.events.*;
 import com.oracle.graal.hotspot.logging.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.java.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.printer.*;
 import com.oracle.graal.replacements.*;
@@ -124,9 +123,9 @@
 
         TTY.initialize(Options.LogFile.getStream());
 
-        if (Log.getValue() == null && Meter.getValue() == null && Time.getValue() == null && Dump.getValue() == null) {
+        if (Log.getValue() == null && Meter.getValue() == null && Time.getValue() == null && Dump.getValue() == null && Verify.getValue() == null) {
             if (MethodFilter.getValue() != null) {
-                TTY.println("WARNING: Ignoring MethodFilter option since Log, Meter, Time and Dump options are all null");
+                TTY.println("WARNING: Ignoring MethodFilter option since Log, Meter, Time, Dump and Verify options are all null");
             }
         }
 
@@ -147,9 +146,6 @@
             }
         }
 
-        final HotSpotProviders hostProviders = hostBackend.getProviders();
-        assert VerifyOptionsPhase.checkOptions(hostProviders.getMetaAccess());
-
         // Complete initialization of backends
         try (InitTimer st = timer(hostBackend.getTarget().arch.getName(), ".completeInitialization")) {
             hostBackend.completeInitialization();
@@ -173,7 +169,7 @@
         @Option(help = "The runtime configuration to use")
         static final OptionValue<String> GraalRuntime = new OptionValue<>("");
 
-        @Option(help = "File to which logging is sent")
+        @Option(help = "File to which logging is sent.  A %p in the name will be replaced with a string identifying the process, usually the process id.")
         public static final PrintStreamOption LogFile = new PrintStreamOption();
         // @formatter:on
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRFrameState.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRFrameState.java	Mon Jun 30 12:02:19 2014 +0200
@@ -26,8 +26,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 
 /**
  * Extends {@link LIRFrameState} to handle {@link HotSpotMonitorValue}s correctly.
@@ -39,15 +39,15 @@
     }
 
     @Override
-    protected Value processValue(ValueProcedure proc, Value value) {
+    protected Value processValue(LIRInstruction inst, InstructionValueProcedure proc, Value value) {
         if (value instanceof HotSpotMonitorValue) {
             HotSpotMonitorValue monitor = (HotSpotMonitorValue) value;
             if (processed(monitor.getOwner())) {
-                monitor.setOwner(proc.doValue(monitor.getOwner(), OperandMode.ALIVE, STATE_FLAGS));
+                monitor.setOwner(proc.doValue(inst, monitor.getOwner(), OperandMode.ALIVE, STATE_FLAGS));
             }
             return value;
         } else {
-            return super.processValue(proc, value);
+            return super.processValue(inst, proc, value);
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLockStack.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLockStack.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -36,9 +36,9 @@
 
     private StackSlot[] locks;
     private final FrameMap frameMap;
-    private final Kind slotKind;
+    private final LIRKind slotKind;
 
-    public HotSpotLockStack(FrameMap frameMap, Kind slotKind) {
+    public HotSpotLockStack(FrameMap frameMap, LIRKind slotKind) {
         this.frameMap = frameMap;
         this.slotKind = slotKind;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
  * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition
  * to abstract methods from {@link LIRGenerator} and {@link NodeLIRBuilderTool}.
  */
-@MatchableNode(nodeClass = CompressionNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = CompressionNode.class, inputs = {"value"})
 public interface HotSpotNodeLIRBuilder {
 
     void emitPatchReturnAddress(ValueNode address);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Mon Jun 30 12:02:19 2014 +0200
@@ -36,6 +36,8 @@
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.common.inlining.*;
 
+//JaCoCo Exclude
+
 /**
  * Sets Graal options from the HotSpot command line. Such options are distinguished by a
  * {@code "-G:"} prefix.
@@ -200,13 +202,22 @@
     }
 
     protected static void printNoMatchMessage(String optionName) {
-        System.err.println("Could not find option " + optionName + " (use -G:+PrintFlags to see Graal options)");
-        List<OptionDescriptor> matches = fuzzyMatch(optionName);
-        if (!matches.isEmpty()) {
-            System.err.println("Did you mean one of the following?");
-            for (OptionDescriptor match : matches) {
-                boolean isBoolean = match.getType() == boolean.class;
-                System.err.println(String.format("    %s%s%s", isBoolean ? "(+/-)" : "", match.getName(), isBoolean ? "" : "=<value>"));
+        OptionDescriptor desc = options.get(optionName);
+        if (desc != null) {
+            if (desc.getType() == Boolean.class) {
+                System.err.println("Boolean option " + optionName + " must be prefixed with '+' or '-'");
+            } else {
+                System.err.println(desc.getType().getSimpleName() + " option " + optionName + " must not be prefixed with '+' or '-'");
+            }
+        } else {
+            System.err.println("Could not find option " + optionName + " (use -G:+PrintFlags to see Graal options)");
+            List<OptionDescriptor> matches = fuzzyMatch(optionName);
+            if (!matches.isEmpty()) {
+                System.err.println("Did you mean one of the following?");
+                for (OptionDescriptor match : matches) {
+                    boolean isBoolean = match.getType() == Boolean.class;
+                    System.err.println(String.format("    %s%s%s", isBoolean ? "(+/-)" : "", match.getName(), isBoolean ? "" : "=<value>"));
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,79 +28,129 @@
 import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
+import com.oracle.graal.compiler.common.*;
 
 public class HotSpotReferenceMap implements ReferenceMap, Serializable {
 
     private static final long serialVersionUID = -1052183095979496819L;
 
+    private static final int BITS_PER_WORD = 3;
+
     /**
-     * Contains 2 bits per register.
-     * <ul>
-     * <li>bit0 = 0: contains no references</li>
-     * <li>bit0 = 1, bit1 = 0: contains a wide oop</li>
-     * <li>bit0 = 1, bit1 = 1: contains a narrow oop</li>
-     * </ul>
+     * Contains 3 bits per scalar register, and n*3 bits per n-word vector register (e.g., on a
+     * 64-bit system, a 256-bit vector register requires 12 reference map bits).
+     * <p>
+     * These bits can have the following values (LSB first):
+     *
+     * <pre>
+     * 000 - contains no references
+     * 100 - contains a wide oop
+     * 110 - contains a narrow oop in the lower half
+     * 101 - contains a narrow oop in the upper half
+     * 111 - contains two narrow oops
+     * </pre>
      */
     private final BitSet registerRefMap;
 
     /**
-     * Contains 3 bits per stack slot.
-     * <ul>
-     * <li>bit0 = 0: contains no references</li>
-     * <li>bit0 = 1, bit1+2 = 0: contains a wide oop</li>
-     * <li>bit0 = 1, bit1 = 1: contains a narrow oop in the lower half</li>
-     * <li>bit0 = 1, bit2 = 1: contains a narrow oop in the upper half</li>
-     * </ul>
+     * Contains 3 bits per stack word.
+     * <p>
+     * These bits can have the following values (LSB first):
+     *
+     * <pre>
+     * 000 - contains no references
+     * 100 - contains a wide oop
+     * 110 - contains a narrow oop in the lower half
+     * 101 - contains a narrow oop in the upper half
+     * 111 - contains two narrow oops
+     * </pre>
      */
     private final BitSet frameRefMap;
 
-    private final int frameSlotSize;
+    private final TargetDescription target;
 
-    public HotSpotReferenceMap(int registerCount, int frameSlotCount, int frameSlotSize) {
+    public HotSpotReferenceMap(int registerCount, int frameSlotCount, TargetDescription target) {
         if (registerCount > 0) {
-            this.registerRefMap = new BitSet(registerCount * 2);
+            this.registerRefMap = new BitSet(registerCount * BITS_PER_WORD);
         } else {
             this.registerRefMap = null;
         }
-        this.frameRefMap = new BitSet(frameSlotCount * 3);
-        this.frameSlotSize = frameSlotSize;
+        this.frameRefMap = new BitSet(frameSlotCount * BITS_PER_WORD);
+        this.target = target;
+    }
+
+    private static void setOop(BitSet map, int startIdx, LIRKind kind) {
+        int length = kind.getPlatformKind().getVectorLength();
+        map.clear(BITS_PER_WORD * startIdx, BITS_PER_WORD * (startIdx + length) - 1);
+        for (int i = 0, idx = BITS_PER_WORD * startIdx; i < length; i++, idx += BITS_PER_WORD) {
+            if (kind.isReference(i)) {
+                map.set(idx);
+            }
+        }
     }
 
-    public void setRegister(int idx, PlatformKind kind) {
-        if (kind == Kind.Object) {
-            registerRefMap.set(2 * idx);
-        } else if (kind == NarrowOopStamp.NarrowOop) {
-            registerRefMap.set(2 * idx);
-            registerRefMap.set(2 * idx + 1);
+    private static void setNarrowOop(BitSet map, int idx, LIRKind kind) {
+        int length = kind.getPlatformKind().getVectorLength();
+        int nextIdx = idx + (length + 1) / 2;
+        map.clear(BITS_PER_WORD * idx, BITS_PER_WORD * nextIdx - 1);
+        for (int i = 0, regIdx = BITS_PER_WORD * idx; i < length; i += 2, regIdx += BITS_PER_WORD) {
+            if (kind.isReference(i)) {
+                map.set(regIdx);
+                map.set(regIdx + 1);
+            }
+            if ((i + 1) < length && kind.isReference(i + 1)) {
+                map.set(regIdx);
+                map.set(regIdx + 2);
+            }
         }
     }
 
-    public PlatformKind getRegister(int idx) {
-        int refMapIndex = idx * 2;
-        if (registerRefMap.get(refMapIndex)) {
-            if (registerRefMap.get(refMapIndex + 1)) {
-                return NarrowOopStamp.NarrowOop;
-            } else {
-                return Kind.Object;
-            }
+    public void setRegister(int idx, LIRKind kind) {
+        if (kind.isDerivedReference()) {
+            throw GraalInternalError.shouldNotReachHere("derived reference cannot be inserted in ReferenceMap");
         }
-        return null;
+
+        PlatformKind platformKind = kind.getPlatformKind();
+        int bytesPerElement = target.getSizeInBytes(platformKind) / platformKind.getVectorLength();
+
+        if (bytesPerElement == target.wordSize) {
+            setOop(registerRefMap, idx, kind);
+        } else if (bytesPerElement == target.wordSize / 2) {
+            setNarrowOop(registerRefMap, idx, kind);
+        } else {
+            assert kind.isValue() : "unsupported reference kind " + kind;
+        }
     }
 
-    public void setStackSlot(int offset, PlatformKind kind) {
-        int idx = offset / frameSlotSize;
-        if (kind == Kind.Object) {
-            assert offset % frameSlotSize == 0;
-            frameRefMap.set(3 * idx);
-        } else if (kind == NarrowOopStamp.NarrowOop) {
-            frameRefMap.set(3 * idx);
-            if (offset % frameSlotSize == 0) {
-                frameRefMap.set(3 * idx + 1);
+    public void setStackSlot(int offset, LIRKind kind) {
+        if (kind.isDerivedReference()) {
+            throw GraalInternalError.shouldNotReachHere("derived reference cannot be inserted in ReferenceMap");
+        }
+
+        PlatformKind platformKind = kind.getPlatformKind();
+        int bytesPerElement = target.getSizeInBytes(platformKind) / platformKind.getVectorLength();
+        assert offset % bytesPerElement == 0 : "unaligned value in ReferenceMap";
+
+        if (bytesPerElement == target.wordSize) {
+            setOop(frameRefMap, offset / target.wordSize, kind);
+        } else if (bytesPerElement == target.wordSize / 2) {
+            if (platformKind.getVectorLength() > 1) {
+                setNarrowOop(frameRefMap, offset / target.wordSize, kind);
             } else {
-                assert offset % frameSlotSize == frameSlotSize / 2;
-                frameRefMap.set(3 * idx + 2);
+                // in this case, offset / target.wordSize may not divide evenly
+                // so setNarrowOop won't work correctly
+                int idx = offset / target.wordSize;
+                if (kind.isReference(0)) {
+                    frameRefMap.set(BITS_PER_WORD * idx);
+                    if (offset % target.wordSize == 0) {
+                        frameRefMap.set(BITS_PER_WORD * idx + 1);
+                    } else {
+                        frameRefMap.set(BITS_PER_WORD * idx + 2);
+                    }
+                }
             }
+        } else {
+            assert kind.isValue() : "unknown reference kind " + kind;
         }
     }
 
@@ -113,14 +163,14 @@
     }
 
     public void appendRegisterMap(StringBuilder sb, RefMapFormatter formatter) {
-        for (int reg = registerRefMap.nextSetBit(0); reg >= 0; reg = registerRefMap.nextSetBit(reg + 2)) {
-            sb.append(' ').append(formatter.formatRegister(reg / 2));
+        for (int reg = registerRefMap.nextSetBit(0); reg >= 0; reg = registerRefMap.nextSetBit(reg + BITS_PER_WORD)) {
+            sb.append(' ').append(formatter.formatRegister(reg / BITS_PER_WORD));
         }
     }
 
     public void appendFrameMap(StringBuilder sb, RefMapFormatter formatter) {
-        for (int slot = frameRefMap.nextSetBit(0); slot >= 0; slot = frameRefMap.nextSetBit(slot + 3)) {
-            sb.append(' ').append(formatter.formatStackSlot(slot / 3));
+        for (int slot = frameRefMap.nextSetBit(0); slot >= 0; slot = frameRefMap.nextSetBit(slot + BITS_PER_WORD)) {
+            sb.append(' ').append(formatter.formatStackSlot(slot / BITS_PER_WORD));
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotTargetDescription.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotTargetDescription.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,28 +24,20 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 
 public class HotSpotTargetDescription extends TargetDescription {
 
-    private final PlatformKind rawNarrowOopKind;
-
-    public HotSpotTargetDescription(Architecture arch, boolean isMP, int stackAlignment, int implicitNullCheckLimit, boolean inlineObjects, PlatformKind rawNarrowOopKind) {
+    public HotSpotTargetDescription(Architecture arch, boolean isMP, int stackAlignment, int implicitNullCheckLimit, boolean inlineObjects) {
         super(arch, isMP, stackAlignment, implicitNullCheckLimit, inlineObjects);
-        this.rawNarrowOopKind = rawNarrowOopKind;
     }
 
     @Override
     public int getSizeInBytes(PlatformKind kind) {
-        if (kind == NarrowOopStamp.NarrowOop) {
-            return super.getSizeInBytes(rawNarrowOopKind);
-        } else {
-            return super.getSizeInBytes(kind);
-        }
+        return super.getSizeInBytes(kind);
     }
 
     @Override
     public ReferenceMap createReferenceMap(boolean hasRegisters, int stackSlotCount) {
-        return new HotSpotReferenceMap(hasRegisters ? arch.getRegisterReferenceMapBitCount() : 0, stackSlotCount, wordSize);
+        return new HotSpotReferenceMap(hasRegisters ? arch.getRegisterReferenceMapSize() : 0, stackSlotCount, this);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1029,9 +1029,10 @@
      */
     @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_notice_safepoints", type = "jint*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailNoticeSafepointsOffset;
     @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_occurred", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptOccurredOffset;
-    @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_never_ran_array", type = "jboolean *", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailNeverRanArrayOffset;
+    @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_never_ran_array", type = "jboolean*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailNeverRanArrayOffset;
     @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_next_index", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptNextIndexOffset;
-    @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_donor_threads", type = "JavaThread**", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDonorThreadsOffset;
+    @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_alloc_info", type = "HSAILAllocationInfo*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailAllocInfoOffset;
+    @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_cur_tlab_info", type = "HSAILTlabInfo**", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailCurTlabInfoOffset;
 
     @HotSpotVMField(name = "Hsail::HSAILKernelDeoptimization::_workitemid", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptimizationWorkItem;
     @HotSpotVMField(name = "Hsail::HSAILKernelDeoptimization::_actionAndReason", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptimizationReason;
@@ -1043,6 +1044,20 @@
     @HotSpotVMType(name = "Hsail::HSAILKernelDeoptimization", get = HotSpotVMType.Type.SIZE) @Stable public int hsailKernelDeoptimizationHeaderSize;
     @HotSpotVMType(name = "Hsail::HSAILDeoptimizationInfo", get = HotSpotVMType.Type.SIZE) @Stable public int hsailDeoptimizationInfoHeaderSize;
 
+    @HotSpotVMField(name = "HSAILAllocationInfo::_tlab_infos_pool_start", type = "HSAILTlabInfo*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailAllocInfoTlabInfosPoolStartOffset;
+    @HotSpotVMField(name = "HSAILAllocationInfo::_tlab_infos_pool_next", type = "HSAILTlabInfo*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailAllocInfoTlabInfosPoolNextOffset;
+    @HotSpotVMField(name = "HSAILAllocationInfo::_tlab_infos_pool_end", type = "HSAILTlabInfo*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailAllocInfoTlabInfosPoolEndOffset;
+    @HotSpotVMField(name = "HSAILAllocationInfo::_tlab_align_reserve_bytes", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailAllocInfoTlabAlignReserveBytesOffset;
+
+    @HotSpotVMField(name = "HSAILTlabInfo::_start", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailTlabInfoStartOffset;
+    @HotSpotVMField(name = "HSAILTlabInfo::_top", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailTlabInfoTopOffset;
+    @HotSpotVMField(name = "HSAILTlabInfo::_end", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailTlabInfoEndOffset;
+    @HotSpotVMField(name = "HSAILTlabInfo::_last_good_top", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailTlabInfoLastGoodTopOffset;
+    @HotSpotVMField(name = "HSAILTlabInfo::_original_top", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailTlabInfoOriginalTopOffset;
+    @HotSpotVMField(name = "HSAILTlabInfo::_donor_thread", type = "JavaThread*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailTlabInfoDonorThreadOffset;
+    @HotSpotVMField(name = "HSAILTlabInfo::_alloc_info", type = "HSAILAllocationInfo*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailTlabInfoAllocInfoOffset;
+    @HotSpotVMType(name = "HSAILTlabInfo", get = HotSpotVMType.Type.SIZE) @Stable public int hsailTlabInfoSize;
+
     /**
      * Mark word right shift to get identity hash code.
      */
@@ -1390,14 +1405,14 @@
     @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedArraycopy;
     @HotSpotVMField(name = "StubRoutines::_arrayof_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedArraycopy;
     @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedArraycopy;
-    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopAlignedArraycopy;
-    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopArraycopyUninit;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedArraycopyUninit;
     @HotSpotVMField(name = "StubRoutines::_arrayof_jbyte_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteAlignedDisjointArraycopy;
     @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedDisjointArraycopy;
     @HotSpotVMField(name = "StubRoutines::_arrayof_jint_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedDisjointArraycopy;
     @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedDisjointArraycopy;
-    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopDisjointArraycopy;
-    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopDisjointArraycopyUninit;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedDisjointArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedDisjointArraycopyUninit;
     @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopy;
     @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopyUninit;
     @HotSpotVMField(name = "StubRoutines::_unsafe_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long unsafeArraycopy;
@@ -1409,9 +1424,9 @@
     @HotSpotVMValue(expression = "GraalRuntime::dynamic_new_array", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dynamicNewArrayAddress;
     @HotSpotVMValue(expression = "GraalRuntime::dynamic_new_instance", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dynamicNewInstanceAddress;
     @HotSpotVMValue(expression = "GraalRuntime::thread_is_interrupted", get = HotSpotVMValue.Type.ADDRESS) @Stable public long threadIsInterruptedAddress;
-    @HotSpotVMValue(expression = "GraalRuntime::vm_message", get = HotSpotVMValue.Type.ADDRESS) @Stable public long vmMessageAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::vm_message", signature = "(unsigned char, long, long, long, long)", get = HotSpotVMValue.Type.ADDRESS) @Stable public long vmMessageAddress;
     @HotSpotVMValue(expression = "GraalRuntime::identity_hash_code", get = HotSpotVMValue.Type.ADDRESS) @Stable public long identityHashCodeAddress;
-    @HotSpotVMValue(expression = "GraalRuntime::exception_handler_for_pc", get = HotSpotVMValue.Type.ADDRESS) @Stable public long exceptionHandlerForPcAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::exception_handler_for_pc", signature = "(JavaThread*)", get = HotSpotVMValue.Type.ADDRESS) @Stable public long exceptionHandlerForPcAddress;
     @HotSpotVMValue(expression = "GraalRuntime::monitorenter", get = HotSpotVMValue.Type.ADDRESS) @Stable public long monitorenterAddress;
     @HotSpotVMValue(expression = "GraalRuntime::monitorexit", get = HotSpotVMValue.Type.ADDRESS) @Stable public long monitorexitAddress;
     @HotSpotVMValue(expression = "GraalRuntime::create_null_exception", get = HotSpotVMValue.Type.ADDRESS) @Stable public long createNullPointerExceptionAddress;
@@ -1437,9 +1452,9 @@
 
     @HotSpotVMValue(expression = "(jint) GraalCounterSize") @Stable public int graalCountersSize;
 
-    @HotSpotVMValue(expression = "Deoptimization::fetch_unroll_info", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationFetchUnrollInfo;
+    @HotSpotVMValue(expression = "Deoptimization::fetch_unroll_info", signature = "(JavaThread*)", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationFetchUnrollInfo;
     @HotSpotVMValue(expression = "Deoptimization::uncommon_trap", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationUncommonTrap;
-    @HotSpotVMValue(expression = "Deoptimization::unpack_frames", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationUnpackFrames;
+    @HotSpotVMValue(expression = "Deoptimization::unpack_frames", signature = "(JavaThread*, int)", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationUnpackFrames;
 
     @HotSpotVMConstant(name = "Deoptimization::Reason_none") @Stable public int deoptReasonNone;
     @HotSpotVMConstant(name = "Deoptimization::Reason_null_check") @Stable public int deoptReasonNullCheck;
@@ -1584,4 +1599,35 @@
             }
         }
     }
+
+    /**
+     * Returns the name of the C/C++ function that is associated (via HotSpotVMValue annotation)
+     * with the HotSpotVMConfig object's field containing {@code foreignCalltargetAddress}; returns
+     * null if no field holds the provided address.
+     *
+     * @param foreignCallTargetAddress address of foreign call target
+     * @return C/C++ symbol name or null
+     */
+    public String getCSymbol(long foreignCallTargetAddress) {
+        for (Field f : HotSpotVMConfig.class.getDeclaredFields()) {
+            if (f.isAnnotationPresent(HotSpotVMValue.class)) {
+                HotSpotVMValue annotation = f.getAnnotation(HotSpotVMValue.class);
+
+                if (annotation.get() == HotSpotVMValue.Type.ADDRESS) {
+                    try {
+                        if (foreignCallTargetAddress == f.getLong(this)) {
+                            return (annotation.expression() + annotation.signature());
+                        }
+                    } catch (IllegalArgumentException e1) {
+                        // TODO Auto-generated catch block
+                        e1.printStackTrace();
+                    } catch (IllegalAccessException e1) {
+                        // TODO Auto-generated catch block
+                        e1.printStackTrace();
+                    }
+                }
+            }
+        }
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/PrintStreamOption.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/PrintStreamOption.java	Mon Jun 30 12:02:19 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot;
 
 import java.io.*;
+import java.lang.management.*;
 
 import com.oracle.graal.options.*;
 
@@ -44,6 +45,30 @@
     private volatile PrintStream ps;
 
     /**
+     * Replace any instance of %p with a an identifying name. Try to get it from the RuntimeMXBean
+     * name.
+     * 
+     * @return the name of the file to log to
+     */
+    private String getFilename() {
+        String name = getValue();
+        if (name.contains("%p")) {
+            String runtimeName = ManagementFactory.getRuntimeMXBean().getName();
+            try {
+                int index = runtimeName.indexOf('@');
+                if (index != -1) {
+                    long pid = Long.parseLong(runtimeName.substring(0, index));
+                    runtimeName = Long.toString(pid);
+                }
+                name = name.replaceAll("%p", runtimeName);
+            } catch (NumberFormatException e) {
+
+            }
+        }
+        return name;
+    }
+
+    /**
      * Gets the print stream configured by this option.
      */
     public PrintStream getStream() {
@@ -53,7 +78,7 @@
                     if (ps == null) {
                         try {
                             final boolean enableAutoflush = true;
-                            ps = new PrintStream(new FileOutputStream(getValue()), enableAutoflush);
+                            ps = new PrintStream(new FileOutputStream(getFilename()), enableAutoflush);
                         } catch (FileNotFoundException e) {
                             throw new RuntimeException("couldn't open file: " + getValue(), e);
                         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Mon Jun 30 12:02:19 2014 +0200
@@ -87,7 +87,7 @@
      * @return the metaspace Method result or 0 is there is no unique concrete method for
      *         {@code metaspaceMethod}
      */
-    long findUniqueConcreteMethod(long metaspaceMethod);
+    long findUniqueConcreteMethod(long actualHolderMetaspaceKlass, long metaspaceMethod);
 
     /**
      * Returns the implementor for the given interface class.
@@ -359,4 +359,6 @@
     void resolveInvokeDynamic(long metaspaceConstantPool, int index);
 
     int getVtableIndexForInterface(long metaspaceKlass, long metaspaceMethod);
+
+    boolean shouldDebugNonSafepoints();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Mon Jun 30 12:02:19 2014 +0200
@@ -68,7 +68,7 @@
     public native boolean hasBalancedMonitors(long metaspaceMethod);
 
     @Override
-    public native long findUniqueConcreteMethod(long metaspaceMethod);
+    public native long findUniqueConcreteMethod(long actualHolderMetaspaceKlass, long metaspaceMethod);
 
     @Override
     public native long getKlassImplementor(long metaspaceKlass);
@@ -197,4 +197,6 @@
     public native void resolveInvokeDynamic(long metaspaceConstantPool, int index);
 
     public native int getVtableIndexForInterface(long metaspaceKlass, long metaspaceMethod);
+
+    public native boolean shouldDebugNonSafepoints();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/data/OopData.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/data/OopData.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 
 /**
  * A data item that represents an oop value.
@@ -48,7 +47,7 @@
     @Override
     public int getSize(TargetDescription target) {
         if (compressed) {
-            return target.getSizeInBytes(NarrowOopStamp.NarrowOop);
+            return target.getSizeInBytes(Kind.Int);
         } else {
             return target.getSizeInBytes(Kind.Object);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Mon Jun 30 12:02:19 2014 +0200
@@ -386,7 +386,7 @@
         ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE));
         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));
-        IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement()));
+        IntegerAddNode add = graph.unique(new IntegerAddNode(read, counter.getIncrement()));
         WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE));
 
         graph.addBeforeFixed(counter, thread);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Mon Jun 30 12:02:19 2014 +0200
@@ -49,6 +49,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.nodes.*;
 
 /**
  * HotSpot implementation of {@link LoweringProvider}.
@@ -66,6 +67,7 @@
     protected WriteBarrierSnippets.Templates writeBarrierSnippets;
     protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
     protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
+    protected AssertionSnippets.Templates assertionSnippets;
 
     public DefaultHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, TargetDescription target) {
         super(metaAccess, target);
@@ -85,6 +87,7 @@
         writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
         exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
         unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
+        assertionSnippets = new AssertionSnippets.Templates(providers, target);
         providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
     }
 
@@ -158,6 +161,8 @@
             }
         } else if (n instanceof LoadExceptionObjectNode) {
             exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool);
+        } else if (n instanceof AssertionNode) {
+            assertionSnippets.lower((AssertionNode) n, tool);
         } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
             // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
             // zero and the MIN_VALUE / -1 cases.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java	Mon Jun 30 12:02:19 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 
 /**
  * The compressed representation of the {@link Constant#NULL_OBJECT null constant}.
@@ -35,7 +34,7 @@
     public static final Constant COMPRESSED_NULL = new HotSpotCompressedNullConstant();
 
     private HotSpotCompressedNullConstant() {
-        super(NarrowOopStamp.NarrowOop);
+        super(LIRKind.reference(Kind.Int));
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Mon Jun 30 12:02:19 2014 +0200
@@ -229,6 +229,12 @@
                 return runtime.getHostProviders().getMetaAccess().lookupJavaType((Class<?>) obj);
             }
         }
+        if (constant instanceof HotSpotMetaspaceConstant) {
+            Object obj = HotSpotMetaspaceConstant.getMetaspaceObject(constant);
+            if (obj instanceof HotSpotResolvedObjectType) {
+                return (ResolvedJavaType) obj;
+            }
+        }
         return null;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,6 +28,7 @@
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
 import static com.oracle.graal.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.*;
+import static com.oracle.graal.hotspot.replacements.AssertionSnippets.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.MonitorSnippets.*;
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
@@ -64,12 +65,18 @@
         stub.getLinkage().setCompiledStub(stub);
     }
 
-    public static ForeignCallDescriptor lookupArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint) {
+    public static ForeignCallDescriptor lookupArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint, boolean uninit) {
+        if (uninit) {
+            assert kind == Kind.Object;
+            return uninitObjectArraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0];
+        }
         return arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].get(kind);
     }
 
     @SuppressWarnings("unchecked") private static final EnumMap<Kind, ForeignCallDescriptor>[][] arraycopyDescriptors = new EnumMap[2][2];
 
+    private static final ForeignCallDescriptor[][] uninitObjectArraycopyDescriptors = new ForeignCallDescriptor[2][2];
+
     static {
         // Populate the EnumMap instances
         for (int i = 0; i < arraycopyDescriptors.length; i++) {
@@ -79,19 +86,28 @@
         }
     }
 
-    private static ForeignCallDescriptor registerArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint) {
-        String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + "Arraycopy";
+    private static ForeignCallDescriptor registerArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint, boolean uninit) {
+        String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + (uninit ? "Uninit" : "") + "Arraycopy";
         ForeignCallDescriptor desc = new ForeignCallDescriptor(name, void.class, Word.class, Word.class, Word.class);
-        arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].put(kind, desc);
+        if (uninit) {
+            assert kind == Kind.Object;
+            uninitObjectArraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0] = desc;
+        } else {
+            arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].put(kind, desc);
+        }
         return desc;
     }
 
     private void registerArrayCopy(Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) {
+        registerArrayCopy(kind, routine, alignedRoutine, disjointRoutine, alignedDisjointRoutine, false);
+    }
+
+    private void registerArrayCopy(Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine, boolean uninit) {
         LocationIdentity killed = NamedLocationIdentity.getArrayLocation(kind);
-        registerForeignCall(registerArraycopyDescriptor(kind, false, false), routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
-        registerForeignCall(registerArraycopyDescriptor(kind, true, false), alignedRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
-        registerForeignCall(registerArraycopyDescriptor(kind, false, true), disjointRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
-        registerForeignCall(registerArraycopyDescriptor(kind, true, true), alignedDisjointRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+        registerForeignCall(registerArraycopyDescriptor(kind, false, false, uninit), routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+        registerForeignCall(registerArraycopyDescriptor(kind, true, false, uninit), alignedRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+        registerForeignCall(registerArraycopyDescriptor(kind, false, true, uninit), disjointRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+        registerForeignCall(registerArraycopyDescriptor(kind, true, true, uninit), alignedDisjointRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
     }
 
     public void initialize(HotSpotProviders providers, HotSpotVMConfig c) {
@@ -121,6 +137,7 @@
         registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
 
         registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(ASSERTION_VM_MESSAGE_C, c.vmMessageAddress, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 
         link(new NewInstanceStub(providers, target, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
         link(new NewArrayStub(providers, target, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, INIT_LOCATION)));
@@ -155,6 +172,12 @@
         registerArrayCopy(Kind.Float, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy);
         registerArrayCopy(Kind.Long, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
         registerArrayCopy(Kind.Double, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
-        registerArrayCopy(Kind.Object, c.oopArraycopy, c.oopArraycopy, c.oopDisjointArraycopy, c.oopDisjointArraycopy);
+        registerArrayCopy(Kind.Object, c.oopArraycopy, c.oopAlignedArraycopy, c.oopDisjointArraycopy, c.oopAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Object, c.oopArraycopyUninit, c.oopAlignedArraycopyUninit, c.oopDisjointArraycopyUninit, c.oopAlignedDisjointArraycopyUninit, true);
+    }
+
+    public HotSpotForeignCallLinkage getForeignCall(ForeignCallDescriptor descriptor) {
+        assert foreignCalls != null : descriptor;
+        return foreignCalls.get(descriptor);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Mon Jun 30 12:02:19 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
@@ -40,6 +41,8 @@
 
     IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization);
 
+    Stamp loadStamp(Stamp stamp, Kind kind);
+
     ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value);
 
     ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMonitorValue.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMonitorValue.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,7 +37,7 @@
     private final boolean eliminated;
 
     public HotSpotMonitorValue(Value owner, StackSlot slot, boolean eliminated) {
-        super(Kind.Illegal);
+        super(LIRKind.Illegal);
         this.owner = owner;
         this.slot = slot;
         this.eliminated = eliminated;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
 
 /**
  * Represents a constant non-{@code null} object reference, within the compiler and across the
@@ -79,7 +78,7 @@
     private final boolean compressed;
 
     private HotSpotObjectConstant(Object object, boolean compressed) {
-        super(compressed ? NarrowOopStamp.NarrowOop : Kind.Object);
+        super(LIRKind.reference(compressed ? Kind.Int : Kind.Object));
         this.object = object;
         this.compressed = compressed;
         assert object != null;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Mon Jun 30 12:02:19 2014 +0200
@@ -350,8 +350,8 @@
         return runtime().getCompilerToVM().getStackTraceElement(metaspaceMethod, bci);
     }
 
-    public ResolvedJavaMethod uniqueConcreteMethod() {
-        if (holder.isInterface()) {
+    public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) {
+        if (receiver.isInterface()) {
             // Cannot trust interfaces. Because of:
             // interface I { void foo(); }
             // class A { public void foo() {} }
@@ -362,7 +362,7 @@
             // seeing A.foo().
             return null;
         }
-        final long uniqueConcreteMethod = runtime().getCompilerToVM().findUniqueConcreteMethod(metaspaceMethod);
+        final long uniqueConcreteMethod = runtime().getCompilerToVM().findUniqueConcreteMethod(receiver.getMetaspaceKlass(), metaspaceMethod);
         if (uniqueConcreteMethod == 0) {
             return null;
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Mon Jun 30 12:02:19 2014 +0200
@@ -459,7 +459,26 @@
 
     @Override
     public ResolvedJavaMethod findUniqueConcreteMethod(ResolvedJavaMethod method) {
-        return ((HotSpotResolvedJavaMethod) method).uniqueConcreteMethod();
+        HotSpotResolvedJavaMethod hmethod = (HotSpotResolvedJavaMethod) method;
+        HotSpotResolvedObjectType declaredHolder = hmethod.getDeclaringClass();
+        /*
+         * Sometimes the receiver type in the graph hasn't stabilized to a subtype of declared
+         * holder, usually because of phis, so make sure that the type is related to the declared
+         * type before using it for lookup.
+         */
+        if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder)) {
+            return hmethod.uniqueConcreteMethod(declaredHolder);
+        }
+        /*
+         * The holder may be a subtype of the decaredHolder so make sure to resolve the method to
+         * the correct method for the subtype.
+         */
+        HotSpotResolvedJavaMethod newMethod = (HotSpotResolvedJavaMethod) resolveMethod(hmethod, this);
+        if (newMethod != null && !hmethod.equals(newMethod)) {
+            hmethod = newMethod;
+        }
+
+        return hmethod.uniqueConcreteMethod(this);
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -44,7 +44,7 @@
     }
 
     public static AllocatableValue emitCString(NodeLIRBuilderTool gen, String value) {
-        AllocatableValue dst = gen.getLIRGeneratorTool().newVariable(gen.getLIRGeneratorTool().target().wordKind);
+        AllocatableValue dst = gen.getLIRGeneratorTool().newVariable(LIRKind.value(gen.getLIRGeneratorTool().target().wordKind));
         gen.getLIRGeneratorTool().emitData(dst, toCString(value));
         return dst;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.replacements.*;
@@ -32,10 +31,10 @@
 
 /**
  * {@link MacroNode Macro node} for {@link Class#cast(Object)}.
- * 
+ *
  * @see ClassSubstitutions#cast(Class, Object)
  */
-public class ClassCastNode extends MacroNode implements Canonicalizable {
+public class ClassCastNode extends MacroNode implements Canonicalizable.Binary<ValueNode> {
 
     public ClassCastNode(Invoke invoke) {
         super(invoke);
@@ -49,16 +48,21 @@
         return arguments.get(1);
     }
 
+    public ValueNode getX() {
+        return getJavaClass();
+    }
+
+    public ValueNode getY() {
+        return getObject();
+    }
+
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            ValueNode object = getObject();
-            Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(javaClass.asConstant());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forJavaClass, ValueNode forObject) {
+        if (forJavaClass.isConstant()) {
+            Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(forJavaClass.asConstant());
             if (c != null && !c.isPrimitive()) {
                 HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(c);
-                CheckCastNode checkcast = graph().add(new CheckCastNode(type, object, null, false));
-                return checkcast;
+                return new CheckCastNode(type, forObject, null, false);
             }
         }
         return this;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.replacements.nodes.*;
+
+/**
+ * {@link MacroNode Macro node} for {@link Class#getClassLoader0()}.
+ *
+ * @see ClassSubstitutions#getClassLoader0(Class)
+ */
+@SuppressWarnings("javadoc")
+public class ClassGetClassLoader0Node extends MacroNode implements Canonicalizable {
+
+    public ClassGetClassLoader0Node(Invoke invoke) {
+        super(invoke);
+    }
+
+    private ValueNode getJavaClass() {
+        return arguments.get(0);
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        ValueNode javaClass = getJavaClass();
+        if (javaClass.isConstant()) {
+            Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(javaClass.asConstant());
+            if (c != null) {
+                /*
+                 * This is an intrinsic for getClassLoader0, which occurs after any security checks.
+                 * We can't call that directly so just call getClassLoader.
+                 */
+                ClassLoader classLoader = c.getClassLoader();
+                return ConstantNode.forConstant(HotSpotObjectConstant.forObject(classLoader), tool.getMetaAccess());
+            }
+        }
+        return this;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetComponentTypeNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetComponentTypeNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -51,7 +51,7 @@
             Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(javaClass.asConstant());
             if (c != null) {
                 Class<?> componentType = c.getComponentType();
-                return ConstantNode.forConstant(HotSpotObjectConstant.forObject(componentType), tool.getMetaAccess(), graph());
+                return ConstantNode.forConstant(HotSpotObjectConstant.forObject(componentType), tool.getMetaAccess());
             }
         }
         return this;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetModifiersNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetModifiersNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -31,7 +31,7 @@
 
 /**
  * {@link MacroNode Macro node} for {@link Class#getModifiers()}.
- * 
+ *
  * @see ClassSubstitutions#getModifiers(Class)
  */
 public class ClassGetModifiersNode extends MacroNode implements Canonicalizable {
@@ -50,7 +50,7 @@
         if (javaClass.isConstant()) {
             Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(javaClass.asConstant());
             if (c != null) {
-                return ConstantNode.forInt(c.getModifiers(), graph());
+                return ConstantNode.forInt(c.getModifiers());
             }
         }
         return this;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetSuperclassNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetSuperclassNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -51,7 +51,7 @@
             Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(javaClass.asConstant());
             if (c != null) {
                 Class<?> superclass = c.getSuperclass();
-                return ConstantNode.forConstant(HotSpotObjectConstant.forObject(superclass), tool.getMetaAccess(), graph());
+                return ConstantNode.forConstant(HotSpotObjectConstant.forObject(superclass), tool.getMetaAccess());
             }
         }
         return this;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsArrayNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsArrayNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -31,7 +31,7 @@
 
 /**
  * {@link MacroNode Macro node} for {@link Class#isArray()}.
- * 
+ *
  * @see ClassSubstitutions#isArray(Class)
  */
 public class ClassIsArrayNode extends MacroNode implements Canonicalizable {
@@ -50,7 +50,7 @@
         if (javaClass.isConstant()) {
             Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(javaClass.asConstant());
             if (c != null) {
-                return ConstantNode.forBoolean(c.isArray(), graph());
+                return ConstantNode.forBoolean(c.isArray());
             }
         }
         return this;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInstanceNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInstanceNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -33,7 +33,7 @@
 
 /**
  * {@link MacroNode Macro node} for {@link Class#isInstance(Object)}.
- * 
+ *
  * @see ClassSubstitutions#isInstance(Class, Object)
  */
 public class ClassIsInstanceNode extends MacroNode implements Canonicalizable {
@@ -58,15 +58,15 @@
             Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(javaClass.asConstant());
             if (c != null) {
                 if (c.isPrimitive()) {
-                    return ConstantNode.forBoolean(false, graph());
+                    return ConstantNode.forBoolean(false);
                 }
                 if (object.isConstant()) {
                     Object o = HotSpotObjectConstant.asObject(object.asConstant());
-                    return ConstantNode.forBoolean(o != null && c.isInstance(o), graph());
+                    return ConstantNode.forBoolean(o != null && c.isInstance(o));
                 }
                 HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(c);
-                InstanceOfNode instanceOf = graph().unique(new InstanceOfNode(type, object, null));
-                return graph().unique(new ConditionalNode(instanceOf, ConstantNode.forBoolean(true, graph()), ConstantNode.forBoolean(false, graph())));
+                InstanceOfNode instanceOf = new InstanceOfNode(type, object, null);
+                return new ConditionalNode(instanceOf, ConstantNode.forBoolean(true), ConstantNode.forBoolean(false));
             }
         }
         return this;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInterfaceNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInterfaceNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,7 +31,7 @@
 
 /**
  * {@link MacroNode Macro node} for {@link Class#isInterface()}.
- * 
+ *
  * @see ClassSubstitutions#isInterface(Class)
  */
 public class ClassIsInterfaceNode extends MacroNode implements Canonicalizable {
@@ -50,7 +50,7 @@
         if (javaClass.isConstant()) {
             Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(javaClass.asConstant());
             if (c != null) {
-                return ConstantNode.forBoolean(c.isInterface(), graph());
+                return ConstantNode.forBoolean(c.isInterface());
             }
         }
         return this;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsPrimitiveNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsPrimitiveNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -31,7 +31,7 @@
 
 /**
  * {@link MacroNode Macro node} for {@link Class#isPrimitive()}.
- * 
+ *
  * @see ClassSubstitutions#isPrimitive(Class)
  */
 public class ClassIsPrimitiveNode extends MacroNode implements Canonicalizable {
@@ -50,7 +50,7 @@
         if (javaClass.isConstant()) {
             Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(javaClass.asConstant());
             if (c != null) {
-                return ConstantNode.forBoolean(c.isPrimitive(), graph());
+                return ConstantNode.forBoolean(c.isPrimitive());
             }
         }
         return this;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -40,7 +40,7 @@
  * Compress or uncompress an oop or metaspace pointer.
  */
 @NodeInfo(nameTemplate = "{p#op/s}")
-public final class CompressionNode extends ConvertNode implements LIRLowerable, Canonicalizable {
+public final class CompressionNode extends ConvertNode implements LIRLowerable {
 
     private enum CompressionOp {
         Compress,
@@ -151,13 +151,13 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (getInput().isConstant()) {
-            return ConstantNode.forConstant(stamp(), evalConst(getInput().asConstant()), tool.getMetaAccess(), graph());
-        } else if (getInput() instanceof CompressionNode) {
-            CompressionNode other = (CompressionNode) getInput();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forConstant(stamp(), evalConst(forValue.asConstant()), tool.getMetaAccess());
+        } else if (forValue instanceof CompressionNode) {
+            CompressionNode other = (CompressionNode) forValue;
             if (op != other.op && encoding.equals(other.encoding)) {
-                return other.getInput();
+                return other.getValue();
             }
         }
         return this;
@@ -167,8 +167,8 @@
     public void generate(NodeLIRBuilderTool gen) {
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
         boolean nonNull;
-        if (getInput().stamp() instanceof AbstractObjectStamp) {
-            nonNull = StampTool.isObjectNonNull(getInput().stamp());
+        if (getValue().stamp() instanceof AbstractObjectStamp) {
+            nonNull = StampTool.isObjectNonNull(getValue().stamp());
         } else {
             // metaspace pointers are never null
             nonNull = true;
@@ -177,10 +177,10 @@
         Value result;
         switch (op) {
             case Compress:
-                result = hsGen.emitCompress(gen.operand(getInput()), encoding, nonNull);
+                result = hsGen.emitCompress(gen.operand(getValue()), encoding, nonNull);
                 break;
             case Uncompress:
-                result = hsGen.emitUncompress(gen.operand(getInput()), encoding, nonNull);
+                result = hsGen.emitUncompress(gen.operand(getValue()), encoding, nonNull);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -38,14 +38,17 @@
  */
 public final class CurrentJavaThreadNode extends FloatingNode implements LIRLowerable {
 
+    private LIRKind wordKind;
+
     private CurrentJavaThreadNode(Kind kind) {
         super(StampFactory.forKind(kind));
+        this.wordKind = LIRKind.value(kind);
     }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         Register rawThread = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).getProviders().getRegisters().getThreadRegister();
-        gen.setResult(this, rawThread.asValue(this.getKind()));
+        gen.setResult(this, rawThread.asValue(wordKind));
     }
 
     private static int eetopOffset() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -46,7 +46,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        AllocatableValue obj = gen.getLIRGeneratorTool().newVariable(gen.getLIRGeneratorTool().target().wordKind);
+        AllocatableValue obj = gen.getLIRGeneratorTool().newVariable(LIRKind.derivedReference(gen.getLIRGeneratorTool().target().wordKind));
         gen.getLIRGeneratorTool().emitMove(obj, gen.operand(object));
         gen.setResult(this, obj);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -71,7 +71,7 @@
         }
         Value[] args = gen.visitInvokeArguments(cc, parameters);
         Value address = lirGen.emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
-        Value entry = lirGen.emitLoad(Kind.Long, address, null);
+        Value entry = lirGen.emitLoad(LIRKind.value(Kind.Long), address, null);
         HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen;
         hsgen.emitTailcall(args, entry);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowOopStamp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowOopStamp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,22 +30,6 @@
 
 public class NarrowOopStamp extends AbstractObjectStamp {
 
-    public static final PlatformKind NarrowOop = new PlatformKind() {
-
-        public String name() {
-            return "NarrowOop";
-        }
-
-        @Override
-        public String toString() {
-            return name();
-        }
-
-        public Constant getDefaultValue() {
-            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
-        }
-    };
-
     private final CompressEncoding encoding;
 
     public NarrowOopStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull, CompressEncoding encoding) {
@@ -71,8 +55,8 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(PlatformKindTool tool) {
-        return NarrowOop;
+    public LIRKind getLIRKind(LIRKindTool tool) {
+        return LIRKind.reference(Kind.Int);
     }
 
     @Override
@@ -117,4 +101,13 @@
         }
         return super.equals(other);
     }
+
+    @Override
+    public Constant asConstant() {
+        if (alwaysNull()) {
+            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
+        } else {
+            return null;
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -45,7 +45,7 @@
     @Override
     protected boolean verify(StructuredGraph graph, PhaseContext context) {
         for (ConstantNode node : getConstantNodes(graph)) {
-            if (node.recordsUsages() || !node.gatherUsages(graph).isEmpty()) {
+            if (node.recordsUsages()) {
                 if (isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node)) {
                     throw new VerificationError("illegal object constant: " + node);
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -26,6 +26,7 @@
 import static com.oracle.graal.nodes.ConstantNode.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -61,13 +62,35 @@
         if (constant instanceof HotSpotObjectConstant && HotSpotObjectConstant.asObject(constant) instanceof Class<?>) {
             MetaAccessProvider metaAccess = context.getMetaAccess();
             ResolvedJavaType type = metaAccess.lookupJavaType((Class<?>) HotSpotObjectConstant.asObject(constant));
-            assert type instanceof HotSpotResolvedObjectType;
-
-            Constant klass = ((HotSpotResolvedObjectType) type).klass();
+            Constant klass;
+            LocationNode location;
+            if (type instanceof HotSpotResolvedObjectType) {
+                location = ConstantLocationNode.create(FINAL_LOCATION, Kind.Object, classMirrorOffset, graph);
+                klass = ((HotSpotResolvedObjectType) type).klass();
+            } else {
+                /*
+                 * Primitive classes are more difficult since they don't have a corresponding Klass*
+                 * so get them from Class.TYPE for the java box type.
+                 */
+                HotSpotResolvedPrimitiveType primitive = (HotSpotResolvedPrimitiveType) type;
+                ResolvedJavaType boxingClass = metaAccess.lookupJavaType(primitive.getKind().toBoxedJavaClass());
+                klass = ((HotSpotResolvedObjectType) boxingClass).klass();
+                HotSpotResolvedJavaField[] a = (HotSpotResolvedJavaField[]) boxingClass.getStaticFields();
+                HotSpotResolvedJavaField typeField = null;
+                for (HotSpotResolvedJavaField f : a) {
+                    if (f.getName().equals("TYPE")) {
+                        typeField = f;
+                        break;
+                    }
+                }
+                if (typeField == null) {
+                    throw new GraalInternalError("Can't find TYPE field in class");
+                }
+                location = ConstantLocationNode.create(FINAL_LOCATION, Kind.Object, typeField.offset(), graph);
+            }
             ConstantNode klassNode = ConstantNode.forConstant(klass, metaAccess, graph);
 
             Stamp stamp = StampFactory.exactNonNull(metaAccess.lookupJavaType(Class.class));
-            LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, Kind.Object, classMirrorOffset, graph);
             FloatingReadNode freadNode = graph.unique(new FloatingReadNode(klassNode, location, null, stamp));
 
             if (HotSpotObjectConstant.isCompressed(constant)) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyCallNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyCallNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+//JaCoCo Exclude
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
@@ -40,7 +41,7 @@
 import com.oracle.graal.runtime.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public final class ArrayCopyCallNode extends ArrayRangeWriteNode implements Lowerable, MemoryCheckpoint.Single {
+public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
     @Input private ValueNode src;
     @Input private ValueNode srcPos;
@@ -49,10 +50,15 @@
     @Input private ValueNode length;
 
     private Kind elementKind;
+
+    /**
+     * Aligned means that the offset of the copy is heap word aligned.
+     */
     private boolean aligned;
     private boolean disjoint;
+    private boolean uninitialized;
 
-    private ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean aligned, boolean disjoint) {
+    private ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean aligned, boolean disjoint, boolean uninitialized) {
         super(StampFactory.forVoid());
         assert elementKind != null;
         this.src = src;
@@ -63,10 +69,11 @@
         this.elementKind = elementKind;
         this.aligned = aligned;
         this.disjoint = disjoint;
+        this.uninitialized = uninitialized;
     }
 
-    private ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind) {
-        this(src, srcPos, dest, destPos, length, elementKind, false, false);
+    private ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean disjoint) {
+        this(src, srcPos, dest, destPos, length, elementKind, false, disjoint, false);
     }
 
     public ValueNode getSource() {
@@ -85,31 +92,10 @@
         return destPos;
     }
 
-    @Override
-    public ValueNode getArray() {
-        return dest;
-    }
-
-    @Override
-    public ValueNode getIndex() {
-        return destPos;
-    }
-
-    @Override
     public ValueNode getLength() {
         return length;
     }
 
-    @Override
-    public boolean isObjectArray() {
-        return elementKind == Kind.Object;
-    }
-
-    @Override
-    public boolean isInitialization() {
-        return false;
-    }
-
     public void addSnippetArguments(Arguments args) {
         args.add("src", src);
         args.add("srcPos", srcPos);
@@ -137,13 +123,13 @@
     public void lower(LoweringTool tool) {
         if (graph().getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
             updateAlignedDisjoint();
-            ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint());
+            ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint(), isUninitialized());
             StructuredGraph graph = graph();
             ValueNode srcAddr = computeBase(getSource(), getSourcePosition());
             ValueNode destAddr = computeBase(getDestination(), getDestinationPosition());
             ValueNode len = getLength();
             if (len.stamp().getStackKind() != Kind.Long) {
-                len = IntegerConvertNode.convert(len, StampFactory.forKind(Kind.Long));
+                len = IntegerConvertNode.convert(len, StampFactory.forKind(Kind.Long), graph());
             }
             ForeignCallNode call = graph.add(new ForeignCallNode(Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len));
             call.setStateAfter(stateAfter());
@@ -161,11 +147,20 @@
     }
 
     @NodeIntrinsic
-    public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind);
+    private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind, @ConstantNodeParameter boolean aligned,
+                    @ConstantNodeParameter boolean disjoint, @ConstantNodeParameter boolean uninitialized);
+
+    public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind, boolean aligned, boolean disjoint) {
+        arraycopy(src, srcPos, dest, destPos, length, elementKind, aligned, disjoint, false);
+    }
 
-    @NodeIntrinsic
-    public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind, @ConstantNodeParameter boolean aligned,
-                    @ConstantNodeParameter boolean disjoint);
+    public static void disjointArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind) {
+        arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, false);
+    }
+
+    public static void disjointUninitializedArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind) {
+        arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, true);
+    }
 
     public boolean isAligned() {
         return aligned;
@@ -175,6 +170,10 @@
         return disjoint;
     }
 
+    public boolean isUninitialized() {
+        return uninitialized;
+    }
+
     public void updateAlignedDisjoint() {
         Kind componentKind = elementKind;
         if (srcPos == destPos) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AssertionSnippets.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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.replacements;
+
+import static com.oracle.graal.hotspot.nodes.CStringNode.*;
+import static com.oracle.graal.replacements.SnippetTemplate.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
+import com.oracle.graal.replacements.SnippetTemplate.Arguments;
+import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
+import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.word.*;
+
+public class AssertionSnippets implements Snippets {
+
+    /**
+     * This call can only be used with true for the "vmError" parameter, so that it can be
+     * configured to be a leaf method.
+     */
+    public static final ForeignCallDescriptor ASSERTION_VM_MESSAGE_C = new ForeignCallDescriptor("assertionVmMessageC", void.class, boolean.class, Word.class, long.class, long.class, long.class);
+
+    @Snippet
+    public static void assertion(boolean value, @ConstantParameter String message) {
+        if (!value) {
+            vmMessageC(ASSERTION_VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L);
+        }
+    }
+
+    @Snippet
+    public static void stubAssertion(boolean value, @ConstantParameter String message) {
+        if (!value) {
+            vmMessageC(ASSERTION_VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L);
+        }
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3);
+
+    @NodeIntrinsic(StubForeignCallNode.class)
+    private static native void stubVmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3);
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo assertion = snippet(AssertionSnippets.class, "assertion");
+        private final SnippetInfo stubAssertion = snippet(AssertionSnippets.class, "stubAssertion");
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        public void lower(AssertionNode assertionNode, LoweringTool tool) {
+            StructuredGraph graph = assertionNode.graph();
+            Arguments args = new Arguments(graph.start() instanceof StubStartNode ? stubAssertion : assertion, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("value", assertionNode.value());
+            args.addConst("message", "failed runtime assertion in snippet/stub: " + assertionNode.message() + " (" + graph.method() + ")");
+
+            template(args).instantiate(providers.getMetaAccess(), assertionNode, DEFAULT_REPLACER, args);
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Mon Jun 30 12:02:19 2014 +0200
@@ -82,6 +82,9 @@
         return klass.equal(0);
     }
 
+    @MacroSubstitution(macro = ClassGetClassLoader0Node.class, isStatic = false)
+    public static native ClassLoader getClassLoader0(Class<?> thisObj);
+
     @MacroSubstitution(macro = ClassGetSuperclassNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false)
     public static Class<?> getSuperclass(final Class<?> thisObj) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Mon Jun 30 12:02:19 2014 +0200
@@ -35,6 +35,7 @@
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.Fold;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
@@ -539,7 +540,7 @@
     private static native Object verifyOopStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
 
     public static Word loadWordFromObject(Object object, int offset) {
-        assert offset != hubOffset() : "Use loadHubIntrinsic instead";
+        ReplacementsUtil.staticAssert(offset != hubOffset(), "Use loadHubIntrinsic instead of loadWordFromObject");
         return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.ANY_LOCATION);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Mon Jun 30 12:02:19 2014 +0200
@@ -223,7 +223,7 @@
         protected Arguments makeArguments(InstanceOfUsageReplacer replacer, LoweringTool tool) {
             if (replacer.instanceOf instanceof InstanceOfNode) {
                 InstanceOfNode instanceOf = (InstanceOfNode) replacer.instanceOf;
-                ValueNode object = instanceOf.object();
+                ValueNode object = instanceOf.getValue();
                 TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), tool.assumptions(), TypeCheckMinProfileHitProbability.getValue(), TypeCheckMaxHints.getValue());
                 final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type();
                 ConstantNode hub = ConstantNode.forConstant(type.klass(), providers.getMetaAccess(), instanceOf.graph());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -38,12 +38,13 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.replacements.nodes.*;
 
 /**
  * Node for invocation methods defined on the class {@link MethodHandle}.
  */
-public class MethodHandleNode extends MacroNode implements Canonicalizable {
+public class MethodHandleNode extends MacroNode implements Simplifiable {
 
     /** The method that this node is representing. */
     private final IntrinsicMethod intrinsicMethod;
@@ -81,7 +82,7 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public void simplify(SimplifierTool tool) {
         InvokeNode invoke;
         switch (intrinsicMethod) {
             case INVOKE_BASIC:
@@ -97,9 +98,11 @@
                 throw GraalInternalError.shouldNotReachHere();
         }
         if (invoke != null) {
-            return invoke;
+            FixedNode next = next();
+            replaceAtUsages(invoke);
+            GraphUtil.removeFixedWithUnusedInputs(this);
+            graph().addBeforeFixed(next, invoke);
         }
-        return this;
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Mon Jun 30 12:02:19 2014 +0200
@@ -501,7 +501,7 @@
                     graph.addAfterFixed(graph.start(), invoke);
 
                     StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod());
-                    InliningUtil.inline(invoke, inlineeGraph, false);
+                    InliningUtil.inline(invoke, inlineeGraph, false, null);
 
                     List<ReturnNode> rets = graph.getNodes(ReturnNode.class).snapshot();
                     for (ReturnNode ret : rets) {
@@ -520,7 +520,7 @@
                         inlineeGraph = template(args).copySpecializedGraph();
 
                         // inlineeGraph = replacements.getSnippet(checkCounter.getMethod());
-                        InliningUtil.inline(invoke, inlineeGraph, false);
+                        InliningUtil.inline(invoke, inlineeGraph, false, null);
                     }
                 }
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Mon Jun 30 12:02:19 2014 +0200
@@ -141,7 +141,7 @@
         if (useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
             writeTlabTop(thread, newTop);
             emitPrefetchAllocate(newTop, false);
-            result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, false, true);
+            result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, true);
         } else {
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
@@ -290,16 +290,16 @@
      * @param startOffset offset to begin zeroing. May not be word aligned.
      * @param manualUnroll maximally unroll zeroing
      */
-    private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean noAsserts, boolean useSnippetCounters) {
-        assert noAsserts || size % 8 == 0 : "unaligned object size";
+    private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) {
+        ReplacementsUtil.runtimeAssert((size & 0x7) == 0, "unaligned object size");
         int offset = startOffset;
-        if (offset % 8 != 0) {
+        if ((offset & 0x7) != 0) {
             memory.writeInt(offset, 0, INIT_LOCATION);
             offset += 4;
         }
-        assert noAsserts || offset % 8 == 0 : "unaligned";
+        ReplacementsUtil.runtimeAssert((offset & 0x7) == 0, "unaligned offset");
         if (manualUnroll && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
-            assert noAsserts || !constantSize : "size shouldn't be constant at instantiation time";
+            ReplacementsUtil.staticAssert(!constantSize, "size shouldn't be constant at instantiation time");
             // This case handles arrays of constant length. Instead of having a snippet variant for
             // each length, generate a chain of stores of maximum length. Once it's inlined the
             // break statement will trim excess stores.
@@ -337,17 +337,17 @@
      * since they can't be compiled in stubs.
      */
     public static Object formatObjectForStub(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord) {
-        return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, true, false);
+        return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, false);
     }
 
     /**
      * Formats some allocated memory with an object header and zeroes out the rest.
      */
-    protected static Object formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, boolean noAsserts, boolean useSnippetCounters) {
+    protected static Object formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, boolean useSnippetCounters) {
         Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord;
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
-            zeroMemory(size, memory, constantSize, instanceHeaderSize(), false, noAsserts, useSnippetCounters);
+            zeroMemory(size, memory, constantSize, instanceHeaderSize(), false, useSnippetCounters);
         }
         return memory.toObject();
     }
@@ -364,7 +364,7 @@
          */
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
-            zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, true, useSnippetCounters);
+            zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, useSnippetCounters);
         }
         return memory.toObject();
     }
@@ -420,13 +420,14 @@
 
             Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage());
             args.add("hub", hub);
-            args.add("length", newArrayNode.length());
+            ValueNode length = newArrayNode.length();
+            args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
             args.add("prototypeMarkWord", arrayType.prototypeMarkWord());
             args.addConst("headerSize", headerSize);
             args.addConst("log2ElementSize", log2ElementSize);
             args.addConst("fillContents", newArrayNode.fillContents());
             args.addConst("threadRegister", registers.getThreadRegister());
-            args.addConst("maybeUnroll", newArrayNode.length().isConstant());
+            args.addConst("maybeUnroll", length.isConstant());
             args.addConst("typeContext", ProfileAllocations.getValue() ? toJavaName(arrayType, false) : "");
 
             SnippetTemplate template = template(args);
@@ -445,9 +446,11 @@
         }
 
         public void lower(DynamicNewArrayNode newArrayNode, HotSpotRegistersProvider registers, LoweringTool tool) {
+            StructuredGraph graph = newArrayNode.graph();
             Arguments args = new Arguments(allocateArrayDynamic, newArrayNode.graph().getGuardsStage(), tool.getLoweringStage());
             args.add("elementType", newArrayNode.getElementType());
-            args.add("length", newArrayNode.length());
+            ValueNode length = newArrayNode.length();
+            args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
             args.addConst("fillContents", newArrayNode.fillContents());
             args.addConst("threadRegister", registers.getThreadRegister());
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -77,6 +77,7 @@
                     assert snippetGraph != null : "ObjectCloneSnippets should be installed";
                     return lowerReplacement(snippetGraph.copy(), tool);
                 }
+                assert false : "unhandled array type " + type.getComponentType().getKind();
             } else {
                 type = getConcreteType(getObject().stamp(), tool.assumptions(), tool.getMetaAccess());
                 if (type != null) {
@@ -106,7 +107,7 @@
     /*
      * Looks at the given stamp and determines if it is an exact type (or can be assumed to be an
      * exact type) and if it is a cloneable type.
-     *
+     * 
      * If yes, then the exact type is returned, otherwise it returns null.
      */
     private static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions, MetaAccessProvider metaAccess) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Mon Jun 30 12:02:19 2014 +0200
@@ -36,10 +36,14 @@
     public static final EnumMap<Kind, Method> arrayCloneMethods = new EnumMap<>(Kind.class);
 
     static {
+        arrayCloneMethods.put(Kind.Boolean, getCloneMethod("booleanArrayClone", boolean[].class));
         arrayCloneMethods.put(Kind.Byte, getCloneMethod("byteArrayClone", byte[].class));
         arrayCloneMethods.put(Kind.Char, getCloneMethod("charArrayClone", char[].class));
+        arrayCloneMethods.put(Kind.Short, getCloneMethod("shortArrayClone", short[].class));
         arrayCloneMethods.put(Kind.Int, getCloneMethod("intArrayClone", int[].class));
+        arrayCloneMethods.put(Kind.Float, getCloneMethod("floatArrayClone", float[].class));
         arrayCloneMethods.put(Kind.Long, getCloneMethod("longArrayClone", long[].class));
+        arrayCloneMethods.put(Kind.Double, getCloneMethod("doubleArrayClone", double[].class));
         arrayCloneMethods.put(Kind.Object, getCloneMethod("objectArrayClone", Object[].class));
     }
 
@@ -52,47 +56,65 @@
     }
 
     @Snippet(removeAllFrameStates = true)
+    public static boolean[] booleanArrayClone(boolean[] src) {
+        boolean[] result = (boolean[]) NewArrayNode.newUninitializedArray(Boolean.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Boolean);
+        return result;
+    }
+
+    @Snippet(removeAllFrameStates = true)
     public static byte[] byteArrayClone(byte[] src) {
-        byte[] result = new byte[src.length];
-        for (int i = 0; i < result.length; i++) {
-            result[i] = src[i];
-        }
+        byte[] result = (byte[]) NewArrayNode.newUninitializedArray(Byte.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Byte);
+        return result;
+    }
+
+    @Snippet(removeAllFrameStates = true)
+    public static short[] shortArrayClone(short[] src) {
+        short[] result = (short[]) NewArrayNode.newUninitializedArray(Short.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Short);
         return result;
     }
 
     @Snippet(removeAllFrameStates = true)
     public static char[] charArrayClone(char[] src) {
-        char[] result = new char[src.length];
-        for (int i = 0; i < result.length; i++) {
-            result[i] = src[i];
-        }
+        char[] result = (char[]) NewArrayNode.newUninitializedArray(Character.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Char);
         return result;
     }
 
     @Snippet(removeAllFrameStates = true)
     public static int[] intArrayClone(int[] src) {
-        int[] result = new int[src.length];
-        for (int i = 0; i < result.length; i++) {
-            result[i] = src[i];
-        }
+        int[] result = (int[]) NewArrayNode.newUninitializedArray(Integer.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Int);
+        return result;
+    }
+
+    @Snippet(removeAllFrameStates = true)
+    public static float[] floatArrayClone(float[] src) {
+        float[] result = (float[]) NewArrayNode.newUninitializedArray(Float.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Float);
         return result;
     }
 
     @Snippet(removeAllFrameStates = true)
     public static long[] longArrayClone(long[] src) {
-        long[] result = new long[src.length];
-        for (int i = 0; i < result.length; i++) {
-            result[i] = src[i];
-        }
+        long[] result = (long[]) NewArrayNode.newUninitializedArray(Long.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Long);
+        return result;
+    }
+
+    @Snippet(removeAllFrameStates = true)
+    public static double[] doubleArrayClone(double[] src) {
+        double[] result = (double[]) NewArrayNode.newUninitializedArray(Double.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Double);
         return result;
     }
 
     @Snippet(removeAllFrameStates = true)
     public static Object[] objectArrayClone(Object[] src) {
-        Object[] result = (Object[]) DynamicNewArrayNode.newArray(GuardingPiNode.guardingNonNull(src.getClass().getComponentType()), src.length);
-        for (int i = 0; i < result.length; i++) {
-            result[i] = src[i];
-        }
+        Object[] result = (Object[]) DynamicNewArrayNode.newUninitializedArray(GuardingPiNode.guardingNonNull(src.getClass().getComponentType()), src.length);
+        ArrayCopyCallNode.disjointUninitializedArraycopy(src, 0, result, 0, src.length, Kind.Object);
         return result;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectGetClassNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectGetClassNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -67,10 +67,18 @@
         if (usages().isEmpty()) {
             return null;
         } else {
+            ResolvedJavaType type = StampTool.typeOrNull(getObject());
             if (StampTool.isExactType(getObject())) {
-                ResolvedJavaType type = StampTool.typeOrNull(getObject());
                 Constant clazz = type.getEncoding(Representation.JavaClass);
-                return ConstantNode.forConstant(clazz, tool.getMetaAccess(), graph());
+                return ConstantNode.forConstant(clazz, tool.getMetaAccess());
+            }
+            if (type != null && tool.assumptions().useOptimisticAssumptions()) {
+                ResolvedJavaType exactType = type.findUniqueConcreteSubtype();
+                if (exactType != null) {
+                    tool.assumptions().recordConcreteSubtype(type, exactType);
+                    Constant clazz = exactType.getEncoding(Representation.JavaClass);
+                    return ConstantNode.forConstant(clazz, tool.getMetaAccess());
+                }
             }
             return this;
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -53,7 +53,7 @@
         ConstantNode callerClassNode = getCallerClassNode(tool.getMetaAccess());
 
         if (callerClassNode != null) {
-            graph().replaceFixedWithFloating(this, callerClassNode);
+            graph().replaceFixedWithFloating(this, graph().addOrUniqueWithInputs(callerClassNode));
         } else {
             InvokeNode invoke = createInvoke();
             graph().replaceFixedWithFixed(this, invoke);
@@ -64,7 +64,7 @@
     /**
      * If inlining is deep enough this method returns a {@link ConstantNode} of the caller class by
      * walking the the stack.
-     * 
+     *
      * @param metaAccess
      * @return ConstantNode of the caller class, or null
      */
@@ -94,7 +94,7 @@
                     if (!method.ignoredBySecurityStackWalk()) {
                         // We have reached the desired frame; return the holder class.
                         HotSpotResolvedObjectType callerClass = method.getDeclaringClass();
-                        return ConstantNode.forConstant(HotSpotObjectConstant.forObject(callerClass.mirror()), metaAccess, graph());
+                        return ConstantNode.forConstant(HotSpotObjectConstant.forObject(callerClass.mirror()), metaAccess);
                     }
                     break;
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Mon Jun 30 12:02:19 2014 +0200
@@ -64,6 +64,11 @@
     protected InstalledCode code;
 
     /**
+     * Compilation result from which {@link #code} was created.
+     */
+    protected CompilationResult compResult;
+
+    /**
      * The registers destroyed by this stub.
      */
     private Set<Register> destroyedRegisters;
@@ -152,7 +157,7 @@
                 CallingConvention incomingCc = linkage.getIncomingCallingConvention();
                 TargetDescription target = codeCache.getTarget();
 
-                final CompilationResult compResult = new CompilationResult();
+                compResult = new CompilationResult();
                 try (Scope s0 = Debug.scope("StubCompilation", graph, providers.getCodeCache())) {
                     Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
                     SchedulePhase schedule = emitFrontEnd(providers, target, graph, assumptions, null, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
@@ -182,6 +187,18 @@
             }
             assert code != null : "error installing stub " + this;
         }
+
         return code;
     }
+
+    /**
+     * Gets the compilation result for this stub, compiling it first if necessary, and installing it
+     * in code.
+     */
+    public synchronized CompilationResult getCompilationResult(final Backend backend) {
+        if (code == null) {
+            getCode(backend);
+        }
+        return compResult;
+    }
 }
--- a/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConfigProcessor.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConfigProcessor.java	Mon Jun 30 12:02:19 2014 +0200
@@ -52,20 +52,22 @@
      * channel for any debug messages and debugging annotation processors requires some special
      * setup.
      */
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
-    private static final String LOGFILE = new File(System.getProperty("java.io.tmpdir"), "hotspotvmconfigprocessor.log").getPath();
-
-    private static PrintWriter log;
+    private PrintWriter log;
 
     /**
-     * Logging facility for the debugging the annotation processor.
+     * Logging facility for debugging the annotation processor.
      */
 
-    private static synchronized PrintWriter getLog() {
+    private PrintWriter getLog() {
         if (log == null) {
             try {
-                log = new PrintWriter(new FileWriter(LOGFILE, true));
+                // Create the log file within the generated source directory so it's easy to find.
+                // /tmp isn't platform independent and java.io.tmpdir can map anywhere, particularly
+                // on the mac.
+                FileObject file = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", getClass().getSimpleName() + "log");
+                log = new PrintWriter(new FileWriter(file.toUri().getPath(), true));
             } catch (IOException e) {
                 // Do nothing
             }
@@ -73,7 +75,7 @@
         return log;
     }
 
-    private static synchronized void logMessage(String format, Object... args) {
+    private void logMessage(String format, Object... args) {
         if (!DEBUG) {
             return;
         }
@@ -84,7 +86,7 @@
         }
     }
 
-    private static synchronized void logException(Throwable t) {
+    private void logException(Throwable t) {
         if (!DEBUG) {
             return;
         }
@@ -104,7 +106,7 @@
             logMessage("throw for %s:\n", element);
         }
         logException(t);
-        processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 8)), element);
+        errorMessage(element, "Exception throw during processing: %s %s", t, Arrays.toString(Arrays.copyOf(t.getStackTrace(), 4)));
     }
 
     //@formatter:off
--- a/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMValue.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMValue.java	Mon Jun 30 12:02:19 2014 +0200
@@ -45,6 +45,13 @@
         VALUE
     }
 
+    /**
+     * If {@link #expression} is a C++ function name, {@link #signature} represents the signature of
+     * the function.
+     *
+     */
+    String signature() default "";
+
     Type get() default Type.VALUE;
 
     /**
--- a/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Mon Jun 30 12:02:19 2014 +0200
@@ -907,20 +907,20 @@
     switch (opcode) {
         case NOP            : /* nothing to do */ break;
         case ACONST_NULL    : frameState.apush(appendConstant(Constant.NULL_OBJECT)); break;
-        case ICONST_M1      : frameState.ipush(appendConstant(Constant.INT_MINUS_1)); break;
-        case ICONST_0       : frameState.ipush(appendConstant(Constant.INT_0)); break;
-        case ICONST_1       : frameState.ipush(appendConstant(Constant.INT_1)); break;
-        case ICONST_2       : frameState.ipush(appendConstant(Constant.INT_2)); break;
-        case ICONST_3       : frameState.ipush(appendConstant(Constant.INT_3)); break;
-        case ICONST_4       : frameState.ipush(appendConstant(Constant.INT_4)); break;
-        case ICONST_5       : frameState.ipush(appendConstant(Constant.INT_5)); break;
-        case LCONST_0       : frameState.lpush(appendConstant(Constant.LONG_0)); break;
-        case LCONST_1       : frameState.lpush(appendConstant(Constant.LONG_1)); break;
-        case FCONST_0       : frameState.fpush(appendConstant(Constant.FLOAT_0)); break;
-        case FCONST_1       : frameState.fpush(appendConstant(Constant.FLOAT_1)); break;
-        case FCONST_2       : frameState.fpush(appendConstant(Constant.FLOAT_2)); break;
-        case DCONST_0       : frameState.dpush(appendConstant(Constant.DOUBLE_0)); break;
-        case DCONST_1       : frameState.dpush(appendConstant(Constant.DOUBLE_1)); break;
+        case ICONST_M1      : // fall through
+        case ICONST_0       : // fall through
+        case ICONST_1       : // fall through
+        case ICONST_2       : // fall through
+        case ICONST_3       : // fall through
+        case ICONST_4       : // fall through
+        case ICONST_5       : frameState.ipush(appendConstant(Constant.forInt(opcode - ICONST_0))); break;
+        case LCONST_0       : // fall through
+        case LCONST_1       : frameState.lpush(appendConstant(Constant.forLong(opcode - LCONST_0))); break;
+        case FCONST_0       : // fall through
+        case FCONST_1       : // fall through
+        case FCONST_2       : frameState.fpush(appendConstant(Constant.forFloat(opcode - FCONST_0))); break;
+        case DCONST_0       : // fall through
+        case DCONST_1       : frameState.dpush(appendConstant(Constant.forDouble(opcode - DCONST_0))); break;
         case BIPUSH         : frameState.ipush(appendConstant(Constant.forInt(stream.readByte()))); break;
         case SIPUSH         : frameState.ipush(appendConstant(Constant.forInt(stream.readShort()))); break;
         case LDC            : // fall through
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Mon Jun 30 12:02:19 2014 +0200
@@ -72,6 +72,10 @@
         return new GraphBuilderConfiguration(false, false, false);
     }
 
+    public static GraphBuilderConfiguration getInfopointDefault() {
+        return new GraphBuilderConfiguration(false, false, true);
+    }
+
     public static GraphBuilderConfiguration getEagerDefault() {
         return new GraphBuilderConfiguration(true, false, false);
     }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -461,52 +461,52 @@
 
             @Override
             protected ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y) {
-                return new IntegerAddNode(StampFactory.forKind(kind), x, y);
+                return new IntegerAddNode(x, y);
             }
 
             @Override
             protected ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y) {
-                return new IntegerSubNode(StampFactory.forKind(kind), x, y);
+                return new IntegerSubNode(x, y);
             }
 
             @Override
             protected ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y) {
-                return new IntegerMulNode(StampFactory.forKind(kind), x, y);
+                return new IntegerMulNode(x, y);
             }
 
             @Override
             protected ValueNode genFloatAdd(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-                return new FloatAddNode(StampFactory.forKind(kind), x, y, isStrictFP);
+                return new FloatAddNode(x, y, isStrictFP);
             }
 
             @Override
             protected ValueNode genFloatSub(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-                return new FloatSubNode(StampFactory.forKind(kind), x, y, isStrictFP);
+                return new FloatSubNode(x, y, isStrictFP);
             }
 
             @Override
             protected ValueNode genFloatMul(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-                return new FloatMulNode(StampFactory.forKind(kind), x, y, isStrictFP);
+                return new FloatMulNode(x, y, isStrictFP);
             }
 
             @Override
             protected ValueNode genFloatDiv(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-                return new FloatDivNode(StampFactory.forKind(kind), x, y, isStrictFP);
+                return new FloatDivNode(x, y, isStrictFP);
             }
 
             @Override
             protected ValueNode genFloatRem(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-                return new FloatRemNode(StampFactory.forKind(kind), x, y, isStrictFP);
+                return new FloatRemNode(x, y, isStrictFP);
             }
 
             @Override
             protected ValueNode genIntegerDiv(Kind kind, ValueNode x, ValueNode y) {
-                return new IntegerDivNode(StampFactory.forKind(kind), x, y);
+                return new IntegerDivNode(x, y);
             }
 
             @Override
             protected ValueNode genIntegerRem(Kind kind, ValueNode x, ValueNode y) {
-                return new IntegerRemNode(StampFactory.forKind(kind), x, y);
+                return new IntegerRemNode(x, y);
             }
 
             @Override
@@ -516,32 +516,32 @@
 
             @Override
             protected ValueNode genLeftShift(Kind kind, ValueNode x, ValueNode y) {
-                return new LeftShiftNode(StampFactory.forKind(kind), x, y);
+                return new LeftShiftNode(x, y);
             }
 
             @Override
             protected ValueNode genRightShift(Kind kind, ValueNode x, ValueNode y) {
-                return new RightShiftNode(StampFactory.forKind(kind), x, y);
+                return new RightShiftNode(x, y);
             }
 
             @Override
             protected ValueNode genUnsignedRightShift(Kind kind, ValueNode x, ValueNode y) {
-                return new UnsignedRightShiftNode(StampFactory.forKind(kind), x, y);
+                return new UnsignedRightShiftNode(x, y);
             }
 
             @Override
             protected ValueNode genAnd(Kind kind, ValueNode x, ValueNode y) {
-                return new AndNode(StampFactory.forKind(kind), x, y);
+                return new AndNode(x, y);
             }
 
             @Override
             protected ValueNode genOr(Kind kind, ValueNode x, ValueNode y) {
-                return new OrNode(StampFactory.forKind(kind), x, y);
+                return new OrNode(x, y);
             }
 
             @Override
             protected ValueNode genXor(Kind kind, ValueNode x, ValueNode y) {
-                return new XorNode(StampFactory.forKind(kind), x, y);
+                return new XorNode(x, y);
             }
 
             @Override
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/VerifyOptionsPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.java;
-
-import static com.oracle.graal.api.meta.MetaUtil.*;
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.options.*;
-import com.oracle.graal.phases.*;
-
-/**
- * Verifies that a class declaring one or more {@linkplain OptionValue options} has a class
- * initializer that only initializes the option(s). This sanity check mitigates the possibility of
- * an option value being used before the code that sets the value (e.g., from the command line) has
- * been executed.
- */
-public class VerifyOptionsPhase extends Phase {
-
-    public static boolean checkOptions(MetaAccessProvider metaAccess) {
-        ServiceLoader<Options> sl = ServiceLoader.loadInstalled(Options.class);
-        Set<ResolvedJavaType> checked = new HashSet<>();
-        for (Options opts : sl) {
-            for (OptionDescriptor desc : opts) {
-                ResolvedJavaType holder = metaAccess.lookupJavaType(desc.getDeclaringClass());
-                checkType(holder, desc, metaAccess, checked);
-            }
-        }
-        return true;
-    }
-
-    private static void checkType(ResolvedJavaType type, OptionDescriptor option, MetaAccessProvider metaAccess, Set<ResolvedJavaType> checked) {
-        if (!checked.contains(type)) {
-            checked.add(type);
-            ResolvedJavaType superType = type.getSuperclass();
-            if (superType != null && !MetaUtil.isJavaLangObject(superType)) {
-                checkType(superType, option, metaAccess, checked);
-            }
-            ResolvedJavaMethod clinit = type.getClassInitializer();
-            if (clinit != null) {
-                StructuredGraph graph = new StructuredGraph(clinit);
-                new GraphBuilderPhase.Instance(metaAccess, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
-                new VerifyOptionsPhase(type, metaAccess, option).apply(graph);
-            }
-        }
-    }
-
-    private final MetaAccessProvider metaAccess;
-    private final ResolvedJavaType declaringClass;
-    private final ResolvedJavaType optionValueType;
-    private final Set<ResolvedJavaType> boxingTypes;
-    private final OptionDescriptor option;
-
-    public VerifyOptionsPhase(ResolvedJavaType declaringClass, MetaAccessProvider metaAccess, OptionDescriptor option) {
-        this.metaAccess = metaAccess;
-        this.declaringClass = declaringClass;
-        this.optionValueType = metaAccess.lookupJavaType(OptionValue.class);
-        this.option = option;
-        this.boxingTypes = new HashSet<>();
-        for (Class<?> c : new Class[]{Boolean.class, Byte.class, Short.class, Character.class, Integer.class, Float.class, Long.class, Double.class}) {
-            this.boxingTypes.add(metaAccess.lookupJavaType(c));
-        }
-    }
-
-    /**
-     * Checks whether a given method is allowed to be called.
-     */
-    private boolean checkInvokeTarget(ResolvedJavaMethod method) {
-        ResolvedJavaType holder = method.getDeclaringClass();
-        if (method.isConstructor()) {
-            if (optionValueType.isAssignableFrom(holder)) {
-                return true;
-            }
-        } else if (boxingTypes.contains(holder)) {
-            return method.getName().equals("valueOf");
-        } else if (method.getDeclaringClass().equals(metaAccess.lookupJavaType(Class.class))) {
-            return method.getName().equals("desiredAssertionStatus");
-        } else if (method.getDeclaringClass().equals(declaringClass)) {
-            return (method.getName().equals("$jacocoInit"));
-        }
-        return false;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (ValueNode node : graph.getNodes().filter(ValueNode.class)) {
-            if (node instanceof StoreFieldNode) {
-                ResolvedJavaField field = ((StoreFieldNode) node).field();
-                verify(field.getDeclaringClass().equals(declaringClass), node, "store to field " + format("%H.%n", field));
-                verify(field.isStatic(), node, "store to field " + format("%H.%n", field));
-                if (optionValueType.isAssignableFrom((ResolvedJavaType) field.getType())) {
-                    verify(field.isFinal(), node, "option field " + format("%H.%n", field) + " not final");
-                } else {
-                    verify((field.isSynthetic()), node, "store to non-synthetic field " + format("%H.%n", field));
-                }
-            } else if (node instanceof Invoke) {
-                Invoke invoke = (Invoke) node;
-                MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-                ResolvedJavaMethod targetMethod = callTarget.targetMethod();
-                verify(checkInvokeTarget(targetMethod), node, "invocation of " + format("%H.%n(%p)", targetMethod));
-            }
-        }
-    }
-
-    private void verify(boolean condition, Node node, String message) {
-        if (!condition) {
-            error(node, message);
-        }
-    }
-
-    private void error(Node node, String message) {
-        String loc = GraphUtil.approxSourceLocation(node);
-        throw new GraalInternalError(String.format("The " + option.getName() + " option is declared in " + option.getDeclaringClass() +
-                        " whose class hierarchy contains a class initializer (in %s) with a code pattern at or near %s implying an action other than initialization of an option:%n%n    %s%n%n" +
-                        "The recommended solution is to move " + option.getName() + " into a separate class (e.g., " + option.getDeclaringClass().getName() + ".Options).%n",
-                        toJavaName(declaringClass), loc, message));
-    }
-}
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,6 +44,9 @@
  */
 public class JTTTest extends GraalCompilerTest {
 
+    public static final class DummyTestClass {
+    }
+
     protected static final Set<DeoptimizationReason> EMPTY = Collections.<DeoptimizationReason> emptySet();
     /**
      * The arguments which, if non-null, will replace the Locals in the test method's graph.
@@ -64,9 +67,13 @@
             assert parameterTypes.length == args.length;
             for (int i = 0; i < args.length; i++) {
                 ParameterNode param = graph.getParameter(i);
-                Constant c = getSnippetReflection().forBoxed(parameterTypes[i].getKind(), args[i]);
-                ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph);
-                param.replaceAtUsages(replacement);
+                if (param != null) {
+                    Constant c = getSnippetReflection().forBoxed(parameterTypes[i].getKind(), args[i]);
+                    ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph);
+                    param.replaceAtUsages(replacement);
+                } else {
+                    // Parameter is not used and has been dead-code eliminated
+                }
             }
         }
         return graph;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_checkcast01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_checkcast01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,12 @@
  */
 public class BC_checkcast01 extends JTTTest {
 
+    private static class TestClass {
+    }
+
     static Object object2 = new Object();
     static Object object3 = "";
-    static Object object4 = new BC_checkcast01();
+    static Object object4 = new TestClass();
 
     public static int test(int arg) {
         Object obj;
@@ -45,7 +48,7 @@
         } else {
             obj = null;
         }
-        final BC_checkcast01 bc = (BC_checkcast01) obj;
+        final TestClass bc = (TestClass) obj;
         if (bc != null) {
             return arg;
         }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_checkcast02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_checkcast02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,12 @@
  */
 public class BC_checkcast02 extends JTTTest {
 
+    private static class TestClass {
+    }
+
     static Object[] o1 = {new Object()};
     static String[] o2 = {""};
-    static BC_checkcast02[] o3 = {new BC_checkcast02()};
+    static TestClass[] o3 = {new TestClass()};
 
     public static int test(int arg) {
         Object obj = null;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_instanceof.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_instanceof.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,12 @@
  */
 public class BC_instanceof extends JTTTest {
 
+    private static class TestClass {
+    }
+
     static Object object2 = new Object();
     static Object object3 = "";
-    static Object object4 = new BC_instanceof();
+    static Object object4 = new TestClass();
 
     public static boolean test(int arg) {
         Object obj;
@@ -45,7 +48,7 @@
         } else {
             obj = null;
         }
-        return obj instanceof BC_instanceof;
+        return obj instanceof TestClass;
     }
 
     @Test
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_invokespecial.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_invokespecial.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,17 +30,19 @@
  */
 public class BC_invokespecial extends JTTTest {
 
-    static BC_invokespecial object = new BC_invokespecial();
+    private static class TestClass {
+        @SuppressWarnings("static-method")
+        private int id(int i) {
+            return i;
+        }
+    }
+
+    static TestClass object = new TestClass();
 
     public static int test(int a) {
         return object.id(a);
     }
 
-    @SuppressWarnings("static-method")
-    private int id(int i) {
-        return i;
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_invokespecial2.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_invokespecial2.java	Mon Jun 30 12:02:19 2014 +0200
@@ -33,17 +33,19 @@
  */
 public class BC_invokespecial2 extends JTTTest {
 
-    static BC_invokespecial2 object = new BC_invokespecial2();
+    private static class TestClass {
+        @SuppressWarnings("static-method")
+        private int id(int i) {
+            return 4 + i;
+        }
+    }
+
+    static TestClass object = new TestClass();
 
     public static int test(int a) {
         return 3 + object.id(a);
     }
 
-    @SuppressWarnings("static-method")
-    private int id(int i) {
-        return 4 + i;
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_invokevirtual.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_invokevirtual.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,16 +30,18 @@
  */
 public class BC_invokevirtual extends JTTTest {
 
-    static BC_invokevirtual object = new BC_invokevirtual();
+    private static class TestClass {
+        public int id(int i) {
+            return i;
+        }
+    }
+
+    static TestClass object = new TestClass();
 
     public static int test(int a) {
         return object.id(a);
     }
 
-    public int id(int i) {
-        return i;
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_monitorenter.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_monitorenter.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,7 +30,7 @@
  */
 public class BC_monitorenter extends JTTTest {
 
-    static BC_monitorenter object = new BC_monitorenter();
+    static DummyTestClass object = new DummyTestClass();
 
     public static int test(int arg) {
         synchronized (object) {
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_monitorenter02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_monitorenter02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,7 +30,7 @@
  */
 public class BC_monitorenter02 extends JTTTest {
 
-    static BC_monitorenter02 object = new BC_monitorenter02();
+    static DummyTestClass object = new DummyTestClass();
 
     public static int test(int arg, int arg2) {
         int result = arg;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_multianewarray01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_multianewarray01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,7 +31,7 @@
 public class BC_multianewarray01 extends JTTTest {
 
     public static int test(int a) {
-        final BC_multianewarray01[][] v = new BC_multianewarray01[3][3];
+        final DummyTestClass[][] v = new DummyTestClass[3][3];
         return v != null ? a : -1;
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_multianewarray02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_multianewarray02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,7 +31,7 @@
 public class BC_multianewarray02 extends JTTTest {
 
     public static int test(int a) {
-        final BC_multianewarray02[][][][] v = new BC_multianewarray02[3][3][3][3];
+        final DummyTestClass[][][][] v = new DummyTestClass[3][3][3][3];
         return v != null ? a : -1;
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_new.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_new.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     @SuppressWarnings("unused")
     public static int test(int a) {
-        new BC_new();
+        new DummyTestClass();
         return a;
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_putfield_01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_putfield_01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,11 @@
  */
 public class BC_putfield_01 extends JTTTest {
 
-    private static BC_putfield_01 object = new BC_putfield_01();
+    private static class TestClass {
+        private int field;
+    }
 
-    private int field;
+    private static TestClass object = new TestClass();
 
     public static int test(int arg) {
         object.field = arg;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_putfield_02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_putfield_02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,11 @@
  */
 public class BC_putfield_02 extends JTTTest {
 
-    private static BC_putfield_02 object = new BC_putfield_02();
+    private static class TestClass {
+        private Object field;
+    }
 
-    private Object field;
+    private static TestClass object = new TestClass();
 
     public static Object test(Object arg) {
         object.field = arg;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_putfield_03.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_putfield_03.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,11 @@
  */
 public class BC_putfield_03 extends JTTTest {
 
-    private static BC_putfield_03 object = new BC_putfield_03();
+    private static class TestClass {
+        private volatile int field;
+    }
 
-    private volatile int field;
+    private static TestClass object = new TestClass();
 
     public static int test(int arg) {
         object.field = arg;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_putfield_04.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_putfield_04.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,11 @@
  */
 public class BC_putfield_04 extends JTTTest {
 
-    private static BC_putfield_04 object = new BC_putfield_04();
+    private static class TestClass {
+        private volatile Object field;
+    }
 
-    private volatile Object field;
+    private static TestClass object = new TestClass();
 
     public static Object test(Object arg) {
         object.field = arg;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_anewarray.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_anewarray.java	Mon Jun 30 12:02:19 2014 +0200
@@ -35,7 +35,7 @@
 
     @SuppressWarnings("unused")
     public static int test(int a) {
-        final BC_anewarray[] v = new BC_anewarray[a];
+        final DummyTestClass[] v = new DummyTestClass[a];
         if (v != null) {
             return a;
         }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static Object object2 = new Object();
     static Object object3 = "";
-    static Object object4 = new BC_checkcast();
+    static Object object4 = new DummyTestClass();
 
     public static int test(int arg) {
         Object obj = null;
@@ -45,7 +45,7 @@
         if (arg == 4) {
             obj = object4;
         }
-        final BC_checkcast bc = (BC_checkcast) obj;
+        final DummyTestClass bc = (DummyTestClass) obj;
         if (bc == null) {
             return arg;
         }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast1.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast1.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static Object object2 = new Object();
     static Object object3 = "";
-    static Object object4 = new BC_checkcast1();
+    static Object object4 = new DummyTestClass();
 
     public static int test(int arg) {
         Object obj = null;
@@ -45,7 +45,7 @@
         if (arg == 4) {
             obj = object4;
         }
-        final BC_checkcast1 bc = (BC_checkcast1) obj;
+        final DummyTestClass bc = (DummyTestClass) obj;
         if (bc == null) {
             return arg;
         }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast2.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast2.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static Object object2 = new Object();
     static Object object3 = "";
-    static Object object4 = new com.oracle.graal.jtt.except.BC_checkcast2();
+    static Object object4 = new DummyTestClass();
 
     public static int test(int arg) {
         Object obj;
@@ -45,7 +45,7 @@
         } else {
             obj = null;
         }
-        final BC_checkcast2 bc = (BC_checkcast2) obj;
+        final DummyTestClass bc = (DummyTestClass) obj;
         if (bc != null) {
             return arg;
         }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast3.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast3.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static Object[] o1 = {new Object()};
     static String[] o2 = {""};
-    static BC_checkcast3[] o3 = {new BC_checkcast3()};
+    static DummyTestClass[] o3 = {new DummyTestClass()};
 
     public static int test(int arg) {
         Object obj = null;
@@ -45,7 +45,7 @@
         if (arg == 2) {
             obj = o3;
         }
-        Object[] r = (BC_checkcast3[]) obj;
+        Object[] r = (DummyTestClass[]) obj;
         return r == null ? -1 : -1;
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast4.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast4.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static Object object2 = new Object();
     static Object object3 = "";
-    static Object object4 = new BC_checkcast4();
+    static Object object4 = new DummyTestClass();
 
     public static int test(int arg) {
         Object obj;
@@ -45,7 +45,7 @@
         } else {
             obj = null;
         }
-        final BC_checkcast4 bc = (BC_checkcast4) obj;
+        final DummyTestClass bc = (DummyTestClass) obj;
         if (bc != null) {
             return arg;
         }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast5.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast5.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static Object object2 = new Object();
     static Object object3 = "";
-    static Object object4 = new BC_checkcast5();
+    static Object object4 = new DummyTestClass();
 
     public static int test(int arg) {
         Object obj;
@@ -46,7 +46,7 @@
             obj = null;
         }
         try {
-            final BC_checkcast5 bc = (BC_checkcast5) obj;
+            final DummyTestClass bc = (DummyTestClass) obj;
             if (bc != null) {
                 return arg;
             }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast6.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_checkcast6.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static Object object2 = new Object();
     static Object object3 = "";
-    static Object object4 = new BC_checkcast6();
+    static Object object4 = new DummyTestClass();
 
     public static int test(int arg) {
         Object obj;
@@ -46,7 +46,7 @@
             obj = null;
         }
         try {
-            final BC_checkcast6 bc = (BC_checkcast6) obj;
+            final DummyTestClass bc = (DummyTestClass) obj;
             if (bc != null) {
                 return arg;
             }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_getfield.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_getfield.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,12 +30,14 @@
 
 public class BC_getfield extends JTTTest {
 
-    private static BC_getfield object = new BC_getfield();
+    private static class TestClass {
+        private int field = 13;
+    }
 
-    private int field = 13;
+    private static TestClass object = new TestClass();
 
     public static int test(int arg) {
-        final BC_getfield obj = (arg == 3) ? null : object;
+        final TestClass obj = (arg == 3) ? null : object;
         return obj.field;
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_getfield1.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_getfield1.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,11 @@
 
 public class BC_getfield1 extends JTTTest {
 
-    private int field = 13;
+    private static class TestClass {
+        private int field = 13;
+    }
 
-    public static void test(BC_getfield1 arg) {
+    public static void test(TestClass arg) {
         @SuppressWarnings("unused")
         int i = arg.field;
     }
@@ -50,7 +52,7 @@
 
     @Test
     public void run2() throws Throwable {
-        runTest("test", new BC_getfield1());
+        runTest("test", new TestClass());
     }
 
 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_invokespecial01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_invokespecial01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,21 +30,23 @@
  */
 public class BC_invokespecial01 extends JTTTest {
 
-    private static final BC_invokespecial01 obj = new BC_invokespecial01();
+    private static class TestClass {
+        @SuppressWarnings("static-method")
+        private boolean method() {
+            return true;
+        }
+    }
+
+    private static final TestClass obj = new TestClass();
 
     public static boolean test(int arg) {
-        BC_invokespecial01 object = null;
+        TestClass object = null;
         if (arg == 0) {
             object = obj;
         }
         return object.method();
     }
 
-    @SuppressWarnings("static-method")
-    private boolean method() {
-        return true;
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_invokevirtual01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_invokevirtual01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,20 +30,22 @@
  */
 public class BC_invokevirtual01 extends JTTTest {
 
-    private static final BC_invokevirtual01 obj = new BC_invokevirtual01();
+    private static class TestClass {
+        public boolean method() {
+            return true;
+        }
+    }
+
+    private static final TestClass obj = new TestClass();
 
     public static boolean test(int arg) {
-        BC_invokevirtual01 object = null;
+        TestClass object = null;
         if (arg == 0) {
             object = obj;
         }
         return object.method();
     }
 
-    public boolean method() {
-        return true;
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_invokevirtual02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_invokevirtual02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,21 +30,23 @@
  */
 public class BC_invokevirtual02 extends JTTTest {
 
-    private static final BC_invokevirtual02 obj = new BC_invokevirtual02();
+    private static class TestClass {
+        @SuppressWarnings("static-method")
+        public final boolean method() {
+            return true;
+        }
+    }
+
+    private static final TestClass obj = new TestClass();
 
     public static boolean test(int arg) {
-        BC_invokevirtual02 object = null;
+        TestClass object = null;
         if (arg == 0) {
             object = obj;
         }
         return object.method();
     }
 
-    @SuppressWarnings("static-method")
-    public final boolean method() {
-        return true;
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_monitorenter.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_monitorenter.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,7 +30,7 @@
  */
 public class BC_monitorenter extends JTTTest {
 
-    static com.oracle.graal.jtt.bytecode.BC_monitorenter object = new com.oracle.graal.jtt.bytecode.BC_monitorenter();
+    static DummyTestClass object = new DummyTestClass();
 
     public static boolean test(boolean arg) {
         final Object o = arg ? object : null;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_multianewarray.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_multianewarray.java	Mon Jun 30 12:02:19 2014 +0200
@@ -35,7 +35,7 @@
 
     @SuppressWarnings("unused")
     public static int test(int a, int b) {
-        final BC_multianewarray[][] v = new BC_multianewarray[a][b];
+        final DummyTestClass[][] v = new DummyTestClass[a][b];
         if (v != null) {
             return a;
         }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_putfield.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_putfield.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,12 +30,14 @@
 
 public class BC_putfield extends JTTTest {
 
-    private static BC_putfield object = new BC_putfield();
+    private static class TestClass {
+        private int field;
+    }
 
-    private int field;
+    private static TestClass object = new TestClass();
 
     public static int test(int arg) {
-        final BC_putfield obj = arg == 3 ? null : object;
+        final TestClass obj = arg == 3 ? null : object;
         obj.field = arg;
         return obj.field;
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NASE_2.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NASE_2.java	Mon Jun 30 12:02:19 2014 +0200
@@ -36,7 +36,7 @@
     @SuppressWarnings("unused")
     public static int test(int a) {
         try {
-            Catch_NASE_2[] v = new Catch_NASE_2[a];
+            DummyTestClass[] v = new DummyTestClass[a];
             if (v != null) {
                 return v.length;
             }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,21 @@
  */
 public class Except_Synchronized01 extends JTTTest {
 
-    static final Except_Synchronized01 object = new Except_Synchronized01();
+    private static class TestClass {
+        final int x = 1;
 
-    final int x = 1;
+        @SuppressWarnings("all")
+        public synchronized int test2(int i) throws Exception {
+            try {
+                TestClass object = null;
+                return object.x;
+            } catch (NullPointerException e) {
+                return 2;
+            }
+        }
+    }
+
+    static final TestClass object = new TestClass();
 
     public static int test(int i) throws Exception {
         if (i == 0) {
@@ -41,16 +53,6 @@
         return object.test2(i);
     }
 
-    @SuppressWarnings("all")
-    public synchronized int test2(int i) throws Exception {
-        try {
-            Except_Synchronized01 object = null;
-            return object.x;
-        } catch (NullPointerException e) {
-            return 2;
-        }
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,24 @@
 
 public class Except_Synchronized02 extends JTTTest {
 
-    static final Except_Synchronized02 object = new Except_Synchronized02();
+    private static class TestClass {
+
+        final int x = 1;
 
-    final int x = 1;
+        @SuppressWarnings("all")
+        public synchronized int test2(int i) throws Exception {
+            while (true) {
+                try {
+                    TestClass object = null;
+                    return object.x;
+                } catch (NullPointerException e) {
+                    return 2;
+                }
+            }
+        }
+    }
+
+    static final TestClass object = new TestClass();
 
     public static int test(int i) throws Exception {
         if (i == 0) {
@@ -41,18 +56,6 @@
         return object.test2(i);
     }
 
-    @SuppressWarnings("all")
-    public synchronized int test2(int i) throws Exception {
-        while (true) {
-            try {
-                Except_Synchronized02 object = null;
-                return object.x;
-            } catch (NullPointerException e) {
-                return 2;
-            }
-        }
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized03.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized03.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,25 @@
  */
 public class Except_Synchronized03 extends JTTTest {
 
-    static final Except_Synchronized03 object = new Except_Synchronized03();
+    private static class TestClass {
+        int x = 1;
 
-    int x = 1;
+        @SuppressWarnings("all")
+        public synchronized int test2(int i) throws Exception {
+            while (true) {
+                try {
+                    synchronized (this) {
+                        TestClass object = null;
+                        return object.x;
+                    }
+                } catch (NullPointerException e) {
+                    return 2;
+                }
+            }
+        }
+    }
+
+    static final TestClass object = new TestClass();
 
     public static int test(int i) throws Exception {
         if (i == 0) {
@@ -41,20 +57,6 @@
         return object.test2(i);
     }
 
-    @SuppressWarnings("all")
-    public synchronized int test2(int i) throws Exception {
-        while (true) {
-            try {
-                synchronized (this) {
-                    Except_Synchronized03 object = null;
-                    return object.x;
-                }
-            } catch (NullPointerException e) {
-                return 2;
-            }
-        }
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized04.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized04.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,9 +30,24 @@
 
 public class Except_Synchronized04 extends JTTTest {
 
-    static final Except_Synchronized04 object = new Except_Synchronized04();
+    private static class TestClass {
+
+        final int x = 1;
 
-    final int x = 1;
+        @SuppressWarnings("all")
+        public int test2(int i) throws Exception {
+            try {
+                synchronized (Except_Synchronized04.class) {
+                    TestClass object = null;
+                    return object.x;
+                }
+            } catch (NullPointerException e) {
+                return 2;
+            }
+        }
+    }
+
+    static final TestClass object = new TestClass();
 
     public static int test(int i) throws Exception {
         if (i == 0) {
@@ -41,18 +56,6 @@
         return object.test2(i);
     }
 
-    @SuppressWarnings("all")
-    public int test2(int i) throws Exception {
-        try {
-            synchronized (Except_Synchronized04.class) {
-                Except_Synchronized04 object = null;
-                return object.x;
-            }
-        } catch (NullPointerException e) {
-            return 2;
-        }
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/StackTrace_CCE_00.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/StackTrace_CCE_00.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static Object object2 = new Object();
     static Object object3 = "";
-    static Object object4 = new StackTrace_CCE_00();
+    static Object object4 = new DummyTestClass();
 
     public static int test(int arg) {
         Object obj = null;
@@ -46,7 +46,7 @@
             obj = object4;
         }
         try {
-            final StackTrace_CCE_00 bc = (StackTrace_CCE_00) obj;
+            final DummyTestClass bc = (DummyTestClass) obj;
             if (bc == null) {
                 return arg;
             }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized04.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized04.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,7 +30,14 @@
 
 public class Throw_Synchronized04 extends JTTTest {
 
-    static final Throw_Synchronized04 object = new Throw_Synchronized04();
+    private static class TestClass {
+        @SuppressWarnings("unused")
+        public synchronized boolean test2(int i) throws Exception {
+            throw new Exception();
+        }
+    }
+
+    static final TestClass object = new TestClass();
 
     public static boolean test(int i) throws Exception {
         if (i == 0) {
@@ -39,11 +46,6 @@
         return object.test2(i);
     }
 
-    @SuppressWarnings("unused")
-    public synchronized boolean test2(int i) throws Exception {
-        throw new Exception();
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized05.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized05.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,7 +30,19 @@
 
 public class Throw_Synchronized05 extends JTTTest {
 
-    static final Throw_Synchronized05 object = new Throw_Synchronized05();
+    private static class TestClass {
+        @SuppressWarnings("unused")
+        public synchronized boolean test2(int i) throws Exception {
+            try {
+                throw new Exception();
+            } catch (Exception e) {
+                // do nothing and then rethrow
+                throw e;
+            }
+        }
+    }
+
+    static final TestClass object = new TestClass();
 
     public static boolean test(int i) throws Exception {
         if (i == 0) {
@@ -39,16 +51,6 @@
         return object.test2(i);
     }
 
-    @SuppressWarnings("unused")
-    public synchronized boolean test2(int i) throws Exception {
-        try {
-            throw new Exception();
-        } catch (Exception e) {
-            // do nothing and then rethrow
-            throw e;
-        }
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,25 +32,27 @@
  */
 public class HP_field02 extends JTTTest {
 
-    public int a;
-    public int b;
-    public int c;
+    private static class TestClass {
+        public int a;
+        public int b;
+        public int c;
 
-    public static int test(int count) {
-        return new HP_field02().run(count);
+        public int run(int count) {
+            for (int i = 0; i <= count; i++) {
+                if (i > 5) {
+                    a += i;
+                } else if (i > 7) {
+                    b += i;
+                } else {
+                    c += i;
+                }
+            }
+            return a + b + c;
+        }
     }
 
-    public int run(int count) {
-        for (int i = 0; i <= count; i++) {
-            if (i > 5) {
-                a += i;
-            } else if (i > 7) {
-                b += i;
-            } else {
-                c += i;
-            }
-        }
-        return a + b + c;
+    public static int test(int count) {
+        return new TestClass().run(count);
     }
 
     @Test
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,29 +31,31 @@
  */
 public class HP_field04 extends JTTTest {
 
-    public byte b;
-    public char c;
-    public short s;
-    public int i;
-    public long l;
-    public float f;
-    public double d;
+    private static class TestClass {
+        public byte b;
+        public char c;
+        public short s;
+        public int i;
+        public long l;
+        public float f;
+        public double d;
 
-    public static int test(int count) {
-        return new HP_field04().run(count);
+        public int run(int count) {
+            for (int x = 0; x <= count; x++) {
+                b += x;
+                c += x;
+                s += x;
+                i += x;
+                l += x;
+                f += x;
+                d += x;
+            }
+            return (int) (b + c + s + i + l + f + d);
+        }
     }
 
-    public int run(int count) {
-        for (int x = 0; x <= count; x++) {
-            b += x;
-            c += x;
-            s += x;
-            i += x;
-            l += x;
-            f += x;
-            d += x;
-        }
-        return (int) (b + c + s + i + l + f + d);
+    public static int test(int count) {
+        return new TestClass().run(count);
     }
 
     @Test
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_idea.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_idea.java	Mon Jun 30 12:02:19 2014 +0200
@@ -60,7 +60,7 @@
 
     /*
      * buildTestData
-     * 
+     *
      * Builds the data used for the test -- each time the test is run.
      */
 
@@ -115,7 +115,7 @@
 
     /*
      * calcEncryptKey
-     * 
+     *
      * Builds the 52 16-bit encryption subkeys Z[] from the user key and stores in 32-bit int array.
      * The routing corrects an error in the source code in the Schnier book. Basically, the sense of
      * the 7- and 9-bit shifts are reversed. It still works reversed, but would encrypted code would
@@ -169,7 +169,7 @@
 
     /*
      * calcDecryptKey
-     * 
+     *
      * Builds the 52 16-bit encryption subkeys DK[] from the encryption- subkeys Z[]. DK[] is a
      * 32-bit int array holding 16-bit values as unsigned.
      */
@@ -216,7 +216,7 @@
 
     /*
      * cipher_idea
-     * 
+     *
      * IDEA encryption/decryption algorithm. It processes plaintext in 64-bit blocks, one at a time,
      * breaking the block into four 16-bit unsigned subblocks. It goes through eight rounds of
      * processing using 6 new subkeys each time, plus four for last step. The source text is in
@@ -359,7 +359,7 @@
 
     /*
      * mul
-     * 
+     *
      * Performs multiplication, modulo (2**16)+1. This code is structured on the assumption that
      * untaken branches are cheaper than taken branches, and that the compiler doesn't schedule
      * branches. Java: Must work with 32-bit int and one 64-bit long to keep 16-bit values and their
@@ -369,7 +369,7 @@
      * zero whenever the result would zero, be 2**16. And if one of the multiplicands is 0, the
      * result is not zero, but (2**16) + 1 minus the other multiplicand (sort of an additive inverse
      * mod 0x10001).
-     * 
+     *
      * NOTE: The java conversion of this routine works correctly, but is half the speed of using
      * Java's modulus division function (%) on the multiplication with a 16-bit masking of the
      * result--running in the Symantec Caje IDE. So it's not called for now; the test uses Java %
@@ -380,7 +380,7 @@
      * private int mul(int a, int b) throws ArithmeticException { long p; // Large enough to catch
      * 16-bit multiply // without hitting sign bit. if (a != 0) { if (b != 0) { p = (long) a * b; b
      * = (int) p & 0xFFFF; // Lower 16 bits. a = (int) p >>> 16; // Upper 16 bits.
-     * 
+     *
      * return (b - a + (b < a ? 1 : 0) & 0xFFFF); } else return ((1 - a) & 0xFFFF); // If b = 0,
      * then same as // 0x10001 - a. } else // If a = 0, then return return((1 - b) & 0xFFFF); //
      * same as 0x10001 - b. }
@@ -388,15 +388,14 @@
 
     /*
      * inv
-     * 
+     *
      * Compute multiplicative inverse of x, modulo (2**16)+1 using extended Euclid's GCD (greatest
      * common divisor) algorithm. It is unrolled twice to avoid swapping the meaning of the
      * registers. And some subtracts are changed to adds. Java: Though it uses signed 32-bit ints,
      * the interpretation of the bits within is strictly unsigned 16-bit.
      */
 
-    @SuppressWarnings("static-method")
-    private int inv(int x) {
+    public int inv(int x) {
         int x2 = x;
         int t0, t1;
         int q, y;
@@ -440,7 +439,7 @@
 
     /*
      * freeTestData
-     * 
+     *
      * Nulls arrays and forces garbage collection to free up memory.
      */
 
@@ -462,4 +461,8 @@
         runTest("test");
     }
 
+    @Test
+    public void runInv() {
+        runTest("inv", 724);
+    }
 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -34,13 +34,15 @@
  */
 public class UnsafeAccess01 extends JTTTest {
 
-    @SuppressWarnings("unused") private int field = 42;
+    private static class TestClass {
+        @SuppressWarnings("unused") private int field = 42;
+    }
 
     public static int test() throws SecurityException, NoSuchFieldException {
         final Unsafe unsafe = getUnsafe();
 
-        final UnsafeAccess01 object = new UnsafeAccess01();
-        final Field field = UnsafeAccess01.class.getDeclaredField("field");
+        final TestClass object = new TestClass();
+        final Field field = TestClass.class.getDeclaredField("field");
         final long offset = unsafe.objectFieldOffset(field);
         final int value = unsafe.getInt(object, offset);
         return value;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static final String string = "";
     static final Object object = new Object();
-    static final Class_cast01 thisObject = new Class_cast01();
+    static final DummyTestClass thisObject = new DummyTestClass();
 
     public static int test(int i) {
         if (i == 0) {
@@ -51,7 +51,7 @@
             }
         }
         if (i == 3) {
-            if (Class_cast01.class.cast(object) == null) {
+            if (DummyTestClass.class.cast(object) == null) {
                 return -1;
             }
         }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static final String string = "";
     static final Object object = new Object();
-    static final Class_cast02 thisObject = new Class_cast02();
+    static final DummyTestClass thisObject = new DummyTestClass();
 
     public static int test(int i) {
         if (i == 0) {
@@ -51,7 +51,7 @@
             }
         }
         if (i == 3) {
-            if (Class_cast02.class.cast(null) == null) {
+            if (DummyTestClass.class.cast(null) == null) {
                 return -1;
             }
         }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_isInstance01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_isInstance01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static final String string = "";
     static final Object obj = new Object();
-    static final Class_isInstance01 thisObject = new Class_isInstance01();
+    static final DummyTestClass thisObject = new DummyTestClass();
 
     public static boolean test(int i) {
         Object object = null;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_isInstance02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_isInstance02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static final String string = "";
     static final Object obj = new Object();
-    static final Class_isInstance02 thisObject = new Class_isInstance02();
+    static final DummyTestClass thisObject = new DummyTestClass();
 
     public static boolean test(int i) {
         Object object = null;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_isInstance03.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_isInstance03.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static final String string = "";
     static final Object obj = new Object();
-    static final Class_isInstance03 thisObject = new Class_isInstance03();
+    static final DummyTestClass thisObject = new DummyTestClass();
 
     public static boolean test(int i) {
         Object object = null;
@@ -45,7 +45,7 @@
         if (i == 2) {
             object = thisObject;
         }
-        return Class_isInstance03.class.isInstance(object);
+        return DummyTestClass.class.isInstance(object);
     }
 
     @Test
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_isInstance06.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_isInstance06.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,12 +28,15 @@
 
 import com.oracle.graal.jtt.*;
 
-public final class Class_isInstance06 extends JTTTest implements Cloneable {
+public final class Class_isInstance06 extends JTTTest {
+
+    private static class TestClass implements Cloneable {
+    }
 
     static final String string = "";
     static final Object obj = new Object();
     static final String[] sarray = {};
-    static final Object thisObject = new Class_isInstance06();
+    static final Object thisObject = new TestClass();
 
     public static boolean test(int i) {
         Object object = null;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_isInstance07.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_isInstance07.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,12 +28,12 @@
 
 import com.oracle.graal.jtt.*;
 
-public final class Class_isInstance07 extends JTTTest implements Cloneable {
+public final class Class_isInstance07 extends JTTTest {
 
     static final String string = "";
     static final Object obj = new Object();
     static final String[] sarray = {};
-    static final Object thisObject = new Class_isInstance07();
+    static final Object thisObject = new DummyTestClass();
 
     public static boolean test(int i, Class<?> c) {
         Object object = null;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_clone01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_clone01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,17 +30,19 @@
 
 public class Object_clone01 extends JTTTest {
 
-    static final Object_clone01 field = new Object_clone01();
+    private static class TestClass {
+        @SuppressWarnings("unused")
+        private boolean tryClone(int i) throws CloneNotSupportedException {
+            return this == this.clone();
+        }
+    }
+
+    static final TestClass field = new TestClass();
 
     public static boolean test(int i) throws CloneNotSupportedException {
         return field.tryClone(i);
     }
 
-    @SuppressWarnings("unused")
-    private boolean tryClone(int i) throws CloneNotSupportedException {
-        return this == this.clone();
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_clone02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_clone02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,19 +28,21 @@
 
 import com.oracle.graal.jtt.*;
 
-public class Object_clone02 extends JTTTest implements Cloneable {
+public class Object_clone02 extends JTTTest {
 
-    static final Object_clone02 field = new Object_clone02();
+    private static class TestClass implements Cloneable {
+        @SuppressWarnings("unused")
+        private boolean tryClone(int i) throws CloneNotSupportedException {
+            return this == this.clone();
+        }
+    }
+
+    static final TestClass field = new TestClass();
 
     public static boolean test(int i) throws CloneNotSupportedException {
         return field.tryClone(i);
     }
 
-    @SuppressWarnings("unused")
-    private boolean tryClone(int i) throws CloneNotSupportedException {
-        return this == this.clone();
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_equals01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_equals01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,7 +30,7 @@
 
 public final class Object_equals01 extends JTTTest {
 
-    public static Object_equals01 field = new Object_equals01();
+    public static DummyTestClass field = new DummyTestClass();
 
     public static boolean test(int i) {
         final Object obj1 = new Object();
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,7 +32,7 @@
 
     static final Object object = new Object();
     static final Object string = new String();
-    static final Object_getClass01 thisObject = new Object_getClass01();
+    static final DummyTestClass thisObject = new DummyTestClass();
 
     public static String test(int i) {
         if (i == 0) {
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,6 +30,13 @@
 
 public class Object_toString01 extends JTTTest {
 
+    private static class TestClass {
+        @Override
+        public String toString() {
+            return string;
+        }
+    }
+
     static final String string = "Object_toString01";
     static final Object object = new Object();
 
@@ -38,16 +45,11 @@
             return object.toString() != null;
         }
         if (i == 1) {
-            return new Object_toString01().toString() == string;
+            return new TestClass().toString() == string;
         }
         return false;
     }
 
-    @Override
-    public String toString() {
-        return string;
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -33,7 +33,14 @@
 
 public class Object_toString02 extends JTTTest {
 
-    static final Object obj = new Object_toString02();
+    private static class TestClass {
+        @Override
+        public String toString() {
+            return "XYZ";
+        }
+    }
+
+    static final Object obj = new TestClass();
 
     public static String test(int i) {
         Object object = null;
@@ -47,11 +54,6 @@
         return object.toString();
     }
 
-    @Override
-    public String toString() {
-        return "XYZ";
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/Loop16.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/Loop16.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,30 +32,32 @@
  */
 public class Loop16 extends JTTTest {
 
-    public int a;
-    public int b;
-    public int c;
+    private static class TestClass {
+        public int a;
+        public int b;
+        public int c;
 
-    public static int test(int count) {
-        return new Loop16().run(count);
+        public int run(int count) {
+            l1: for (int i = 0; i <= count; i++) {
+                if (i > 5) {
+                    for (int j = 0; j < i; j++) {
+                        a += i;
+                        if (a > 500) {
+                            break l1;
+                        }
+                    }
+                } else if (i > 7) {
+                    b += i;
+                } else {
+                    c += i;
+                }
+            }
+            return a + b + c;
+        }
     }
 
-    public int run(int count) {
-        l1: for (int i = 0; i <= count; i++) {
-            if (i > 5) {
-                for (int j = 0; j < i; j++) {
-                    a += i;
-                    if (a > 500) {
-                        break l1;
-                    }
-                }
-            } else if (i > 7) {
-                b += i;
-            } else {
-                c += i;
-            }
-        }
-        return a + b + c;
+    public static int test(int count) {
+        return new TestClass().run(count);
     }
 
     @Test
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,11 +44,11 @@
     }
 
     static void oneOperandStackSlot() {
-        new StrangeFrames();
+        new DummyTestClass();
     }
 
     static void twoOperandStackSlots() {
-        two(new StrangeFrames(), new StrangeFrames());
+        two(new DummyTestClass(), new DummyTestClass());
     }
 
     static void oneLocalSlot() {
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -33,13 +33,62 @@
 @SuppressWarnings("unused")
 public class Conditional01 extends JTTTest {
 
+    private static class TestClass {
+        private int nextPC;
+        private int pc;
+        private boolean aC;
+        private boolean aH;
+        private boolean aN;
+        private boolean aZ;
+        private boolean aV;
+        private boolean aS;
+        private int cyclesConsumed;
+        private int[] sram = new int[RAM_SIZE];
+
+        public void visit(CPC i) {
+            nextPC = pc + 2;
+            int tmp0 = getRegisterByte(i.r1);
+            int tmp1 = getRegisterByte(i.r2);
+            int tmp2 = bit(aC);
+            int tmp3 = tmp0 - tmp1 - tmp2;
+            boolean tmp4 = ((tmp0 & 128) != 0);
+            boolean tmp5 = ((tmp1 & 128) != 0);
+            boolean tmp6 = ((tmp3 & 128) != 0);
+            boolean tmp7 = ((tmp0 & 8) != 0);
+            boolean tmp8 = ((tmp1 & 8) != 0);
+            boolean tmp9 = ((tmp3 & 8) != 0);
+            aH = !tmp7 && tmp8 || tmp8 && tmp9 || tmp9 && !tmp7;
+            aC = !tmp4 && tmp5 || tmp5 && tmp6 || tmp6 && !tmp4;
+            aN = tmp6;
+            aZ = low(tmp3) == 0 && aZ;
+            aV = tmp4 && !tmp5 && !tmp6 || !tmp4 && tmp5 && tmp6;
+            aS = (aN != aV);
+            cyclesConsumed++;
+        }
+
+        public int getRegisterByte(Register r1) {
+            if ((r1.val % 10) == 0) {
+                return sram[r1.num];
+            }
+            return r1.val;
+        }
+
+        public int low(int tmp3) {
+            return tmp3 & 0x01;
+        }
+
+        public int bit(boolean c2) {
+            return c2 ? 1 : 0;
+        }
+    }
+
     private static final int RAM_SIZE = 0x100;
     private static final int init = new Random().nextInt();
     private static final int init1 = new Register().val;
     private static final Register init2 = new CPC().r1;
 
     public static int test(int arg) {
-        Conditional01 c = new Conditional01();
+        TestClass c = new TestClass();
         Random rnd = new Random();
         for (int i = 0; i < arg; i++) {
             CPC i2 = new CPC();
@@ -71,53 +120,6 @@
 
     }
 
-    private int nextPC;
-    private int pc;
-    private boolean aC;
-    private boolean aH;
-    private boolean aN;
-    private boolean aZ;
-    private boolean aV;
-    private boolean aS;
-    private int cyclesConsumed;
-    private int[] sram = new int[RAM_SIZE];
-
-    public void visit(CPC i) {
-        nextPC = pc + 2;
-        int tmp0 = getRegisterByte(i.r1);
-        int tmp1 = getRegisterByte(i.r2);
-        int tmp2 = bit(aC);
-        int tmp3 = tmp0 - tmp1 - tmp2;
-        boolean tmp4 = ((tmp0 & 128) != 0);
-        boolean tmp5 = ((tmp1 & 128) != 0);
-        boolean tmp6 = ((tmp3 & 128) != 0);
-        boolean tmp7 = ((tmp0 & 8) != 0);
-        boolean tmp8 = ((tmp1 & 8) != 0);
-        boolean tmp9 = ((tmp3 & 8) != 0);
-        aH = !tmp7 && tmp8 || tmp8 && tmp9 || tmp9 && !tmp7;
-        aC = !tmp4 && tmp5 || tmp5 && tmp6 || tmp6 && !tmp4;
-        aN = tmp6;
-        aZ = low(tmp3) == 0 && aZ;
-        aV = tmp4 && !tmp5 && !tmp6 || !tmp4 && tmp5 && tmp6;
-        aS = (aN != aV);
-        cyclesConsumed++;
-    }
-
-    public int getRegisterByte(Register r1) {
-        if ((r1.val % 10) == 0) {
-            return sram[r1.num];
-        }
-        return r1.val;
-    }
-
-    public int low(int tmp3) {
-        return tmp3 & 0x01;
-    }
-
-    public int bit(boolean c2) {
-        return c2 ? 1 : 0;
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Fold_Cast01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Fold_Cast01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,20 +31,22 @@
  */
 public class Fold_Cast01 extends JTTTest {
 
-    static final Object object = new Fold_Cast01();
+    private static class TestClass {
+        int field = 9;
+    }
 
-    int field = 9;
+    static final Object object = new TestClass();
 
     public static int test(int arg) {
         if (arg == 0) {
-            return ((Fold_Cast01) object).field;
+            return ((TestClass) object).field;
         }
         if (arg == 1) {
-            Object obj = new Fold_Cast01();
-            return ((Fold_Cast01) obj).field;
+            Object obj = new TestClass();
+            return ((TestClass) obj).field;
         }
         if (arg == 2) {
-            return ((Fold_Cast01) null).field;
+            return ((TestClass) null).field;
         }
         return 0;
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Fold_InstanceOf01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Fold_InstanceOf01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,18 +31,18 @@
  */
 public class Fold_InstanceOf01 extends JTTTest {
 
-    static final Object object = new Fold_InstanceOf01();
+    static final Object object = new DummyTestClass();
 
     public static boolean test(int arg) {
         if (arg == 0) {
-            return object instanceof Fold_InstanceOf01;
+            return object instanceof DummyTestClass;
         }
         if (arg == 1) {
-            Object obj = new Fold_InstanceOf01();
-            return obj instanceof Fold_InstanceOf01;
+            Object obj = new DummyTestClass();
+            return obj instanceof DummyTestClass;
         }
         if (arg == 2) {
-            return null instanceof Fold_InstanceOf01;
+            return null instanceof DummyTestClass;
         }
         return false;
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/LLE_01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/LLE_01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -33,10 +33,12 @@
  */
 public class LLE_01 extends JTTTest {
 
-    int field1;
+    private static class TestClass {
+        int field1;
+    }
 
     public static int test() {
-        LLE_01 o = new LLE_01();
+        TestClass o = new TestClass();
         o.field1 = 1;
         o.field1 = 0;
         return o.field1;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/List_reorder_bug.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/List_reorder_bug.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,6 +31,38 @@
 @SuppressWarnings("unused")
 public class List_reorder_bug extends JTTTest {
 
+    private static class TestClass {
+        String s;
+
+        private void print(String s2) {
+            this.s = s2;
+        }
+
+        private void match(Object a, int src, int id, int seq) {
+            print("match: " + src + ", " + id);
+            List item = list;
+            List itemPrev = null;
+            while (item != null) {
+                if (item.id == id) {
+                    if (item.bool) {
+                        outcall(item.id);
+                    }
+                    if (itemPrev != null) {
+                        itemPrev.next = item.next;
+                    } else {
+                        list = item.next;
+                    }
+
+                    item.next = null;
+                    return;
+                }
+
+                itemPrev = item;
+                item = item.next;
+            }
+        }
+    }
+
     static class List {
 
         List(int id) {
@@ -47,46 +79,16 @@
     public static boolean test(int i) {
         list = new List(5);
         list.next = new List(6);
-        new List_reorder_bug().match(new Object(), 27, 6, 0);
+        new TestClass().match(new Object(), 27, 6, 0);
         return list.next == null;
     }
 
-    private void match(Object a, int src, int id, int seq) {
-        print("match: " + src + ", " + id);
-        List item = list;
-        List itemPrev = null;
-        while (item != null) {
-            if (item.id == id) {
-                if (item.bool) {
-                    outcall(item.id);
-                }
-                if (itemPrev != null) {
-                    itemPrev.next = item.next;
-                } else {
-                    list = item.next;
-                }
-
-                item.next = null;
-                return;
-            }
-
-            itemPrev = item;
-            item = item.next;
-        }
-    }
-
     static int globalId;
 
     private static void outcall(int id) {
         globalId = id;
     }
 
-    String s;
-
-    private void print(String s2) {
-        this.s = s2;
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,13 +31,15 @@
  */
 public class NCE_01 extends JTTTest {
 
-    public static NCE_01 object = new NCE_01();
+    private static class TestClass {
+        int field1 = 22;
+        int field2 = 23;
+    }
 
-    int field1 = 22;
-    int field2 = 23;
+    public static TestClass object = new TestClass();
 
     public static int test() {
-        NCE_01 o = object;
+        TestClass o = object;
         int i = o.field1;
         // expected null check elimination here
         return o.field2 + i;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,13 +31,15 @@
  */
 public class NCE_02 extends JTTTest {
 
-    public static NCE_02 object = new NCE_02();
+    public static class TestClass {
+        int field1;
+        int field2 = 23;
+    }
 
-    int field1;
-    int field2 = 23;
+    public static TestClass object = new TestClass();
 
     public static int test() {
-        NCE_02 o = object;
+        TestClass o = object;
         o.field1 = 11;
         // expect non-null
         o.field1 = 22;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_03.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_03.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,14 +31,16 @@
  */
 public class NCE_03 extends JTTTest {
 
-    private static boolean cond = true;
-    public static NCE_03 object = new NCE_03();
+    public static class TestClass {
+        int field1;
+        int field2 = 23;
+    }
 
-    int field1;
-    int field2 = 23;
+    private static boolean cond = true;
+    public static TestClass object = new TestClass();
 
     public static int test() {
-        NCE_03 o = object;
+        TestClass o = object;
         o.field1 = 11;
         if (cond) {
             // expect non-null
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_04.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_04.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,14 +31,16 @@
  */
 public class NCE_04 extends JTTTest {
 
-    private static boolean cond = true;
-    public static NCE_04 object = new NCE_04();
+    public static class TestClass {
+        int field1;
+        int field2 = 23;
+    }
 
-    int field1;
-    int field2 = 23;
+    private static boolean cond = true;
+    public static TestClass object = new TestClass();
 
     public static int test() {
-        NCE_04 o = object;
+        TestClass o = object;
         if (cond) {
             o.field1 = 22;
         } else {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NestedLoop_EA.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.jtt.optimize;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.jtt.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.virtual.phases.ea.*;
+
+public class NestedLoop_EA extends JTTTest {
+
+    @Override
+    protected Suites createSuites() {
+        Suites suites = super.createSuites();
+        ListIterator<BasePhase<? super HighTierContext>> position = suites.getHighTier().findPhase(PartialEscapePhase.class);
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!GraalOptions.ImmutableCode.getValue());
+        // incremental canonicalizer of PEA is missing some important canonicalization (TODO?)
+        position.add(canonicalizer);
+        position.add(new PartialEscapePhase(true, canonicalizer));
+        return suites;
+    }
+
+    static class Frame {
+        Object objects[] = new Object[10];
+    }
+
+    final static int RESULT_SLOT = 0;
+    final static int K_SLOT = 1;
+    final static int I_SLOT = 2;
+    final static int ARG_SLOT = 3;
+    final static int STACK_BASE = 4;
+
+    static class Pointer {
+        public int sp = STACK_BASE;
+    }
+
+    public static int simpleLoop(int arg) {
+        Frame f = new Frame();
+        Pointer p = new Pointer();
+        f.objects[ARG_SLOT] = arg;
+        f.objects[RESULT_SLOT] = 0;
+        f.objects[K_SLOT] = 0;
+        for (; (int) f.objects[K_SLOT] < (int) f.objects[ARG_SLOT];) {
+
+            f.objects[RESULT_SLOT] = (int) f.objects[RESULT_SLOT] + 5;
+
+            f.objects[++p.sp] = f.objects[K_SLOT];
+            f.objects[++p.sp] = 1;
+            int result = (int) f.objects[p.sp] + (int) f.objects[p.sp - 1];
+            p.sp--;
+            f.objects[p.sp] = result;
+            f.objects[K_SLOT] = (int) f.objects[p.sp];
+            p.sp--;
+        }
+        return (int) f.objects[RESULT_SLOT];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("simpleLoop", 5);
+    }
+
+    public static int nestedLoop(int arg) {
+        Frame f = new Frame();
+        Pointer p = new Pointer();
+        f.objects[ARG_SLOT] = arg;
+        f.objects[RESULT_SLOT] = 0;
+        f.objects[K_SLOT] = 0;
+        for (; (int) f.objects[K_SLOT] < (int) f.objects[ARG_SLOT];) {
+
+            f.objects[I_SLOT] = 0;
+            for (; (int) f.objects[I_SLOT] < (int) f.objects[ARG_SLOT];) {
+                f.objects[RESULT_SLOT] = (int) f.objects[RESULT_SLOT] + 5;
+
+                f.objects[++p.sp] = f.objects[I_SLOT];
+                f.objects[++p.sp] = 1;
+                int result = (int) f.objects[p.sp] + (int) f.objects[p.sp - 1];
+                p.sp--;
+                f.objects[p.sp] = result;
+                f.objects[I_SLOT] = (int) f.objects[p.sp];
+                p.sp--;
+            }
+
+            f.objects[++p.sp] = f.objects[K_SLOT];
+            f.objects[++p.sp] = 1;
+            int result = (int) f.objects[p.sp] + (int) f.objects[p.sp - 1];
+            p.sp--;
+            f.objects[p.sp] = result;
+            f.objects[K_SLOT] = (int) f.objects[p.sp];
+            p.sp--;
+        }
+        return (int) f.objects[RESULT_SLOT];
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("nestedLoop", 5);
+    }
+
+    @Override
+    protected boolean checkHighTierGraph(StructuredGraph graph) {
+        assert graph.getNodes().filter(CommitAllocationNode.class).count() == 0 : "all allocations should be virtualized";
+        return true;
+    }
+}
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_Cast01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_Cast01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,9 +31,11 @@
  */
 public class VN_Cast01 extends JTTTest {
 
-    static final Object object = new VN_Cast01();
+    private static class TestClass {
+        int field = 9;
+    }
 
-    int field = 9;
+    static final Object object = new TestClass();
 
     public static int test(int arg) {
         if (arg == 0) {
@@ -50,23 +52,23 @@
 
     private static int test1() {
         Object o = object;
-        VN_Cast01 a = (VN_Cast01) o;
-        VN_Cast01 b = (VN_Cast01) o;
+        TestClass a = (TestClass) o;
+        TestClass b = (TestClass) o;
         return a.field + b.field;
     }
 
     private static int test2() {
-        Object obj = new VN_Cast01();
-        VN_Cast01 a = (VN_Cast01) obj;
-        VN_Cast01 b = (VN_Cast01) obj;
+        Object obj = new TestClass();
+        TestClass a = (TestClass) obj;
+        TestClass b = (TestClass) obj;
         return a.field + b.field;
     }
 
     @SuppressWarnings("all")
     private static int test3() {
         Object o = null;
-        VN_Cast01 a = (VN_Cast01) o;
-        VN_Cast01 b = (VN_Cast01) o;
+        TestClass a = (TestClass) o;
+        TestClass b = (TestClass) o;
         return a.field + b.field;
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_Cast02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_Cast02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,10 +31,12 @@
  */
 public class VN_Cast02 extends JTTTest {
 
+    private static class TestClass {
+        int field = 9;
+    }
+
     private static boolean cond = true;
-    static final Object object = new VN_Cast02();
-
-    int field = 9;
+    static final Object object = new TestClass();
 
     public static int test(int arg) {
         if (arg == 0) {
@@ -51,19 +53,19 @@
 
     private static int test1() {
         Object o = object;
-        VN_Cast02 a = (VN_Cast02) o;
+        TestClass a = (TestClass) o;
         if (cond) {
-            VN_Cast02 b = (VN_Cast02) o;
+            TestClass b = (TestClass) o;
             return a.field + b.field;
         }
         return 0;
     }
 
     private static int test2() {
-        Object obj = new VN_Cast02();
-        VN_Cast02 a = (VN_Cast02) obj;
+        Object obj = new TestClass();
+        TestClass a = (TestClass) obj;
         if (cond) {
-            VN_Cast02 b = (VN_Cast02) obj;
+            TestClass b = (TestClass) obj;
             return a.field + b.field;
         }
         return 0;
@@ -72,9 +74,9 @@
     @SuppressWarnings("all")
     private static int test3() {
         Object o = null;
-        VN_Cast02 a = (VN_Cast02) o;
+        TestClass a = (TestClass) o;
         if (cond) {
-            VN_Cast02 b = (VN_Cast02) o;
+            TestClass b = (TestClass) o;
             return a.field + b.field;
         }
         return 0;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_Field01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_Field01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,9 +31,11 @@
  */
 public class VN_Field01 extends JTTTest {
 
-    static final VN_Field01 object = new VN_Field01();
+    private static class TestClass {
+        int field = 9;
+    }
 
-    int field = 9;
+    static final TestClass object = new TestClass();
 
     public static int test(int arg) {
         if (arg == 0) {
@@ -49,20 +51,20 @@
     }
 
     private static int test1() {
-        VN_Field01 a = object;
+        TestClass a = object;
         return a.field + a.field;
     }
 
     private static int test2() {
-        VN_Field01 a = object;
-        VN_Field01 b = object;
+        TestClass a = object;
+        TestClass b = object;
         return a.field + b.field;
     }
 
     @SuppressWarnings("all")
     private static int test3() {
-        VN_Field01 a = null;
-        VN_Field01 b = null;
+        TestClass a = null;
+        TestClass b = null;
         return a.field + b.field;
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_Field02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_Field02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,10 +31,12 @@
  */
 public class VN_Field02 extends JTTTest {
 
+    private static class TestClass {
+        int field = 9;
+    }
+
     private static boolean cond = true;
-    static final VN_Field02 object = new VN_Field02();
-
-    int field = 9;
+    static final TestClass object = new TestClass();
 
     public static int test(int arg) {
         if (arg == 0) {
@@ -50,7 +52,7 @@
     }
 
     private static int test1() {
-        VN_Field02 a = object;
+        TestClass a = object;
         int c = a.field;
         if (cond) {
             return c + a.field;
@@ -59,9 +61,9 @@
     }
 
     private static int test2() {
-        VN_Field02 a = object;
+        TestClass a = object;
         if (cond) {
-            VN_Field02 b = object;
+            TestClass b = object;
             return a.field + b.field;
         }
         return 0;
@@ -69,9 +71,9 @@
 
     @SuppressWarnings("all")
     private static int test3() {
-        VN_Field02 a = null;
+        TestClass a = null;
         if (cond) {
-            VN_Field02 b = null;
+            TestClass b = null;
             return a.field + b.field;
         }
         return 0;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,7 +31,7 @@
  */
 public class VN_InstanceOf01 extends JTTTest {
 
-    static final Object object = new VN_InstanceOf01();
+    static final Object object = new DummyTestClass();
 
     public static boolean test(int arg) {
         if (arg == 0) {
@@ -48,21 +48,21 @@
     }
 
     private static boolean foo1() {
-        boolean a = object instanceof VN_InstanceOf01;
-        boolean b = object instanceof VN_InstanceOf01;
+        boolean a = object instanceof DummyTestClass;
+        boolean b = object instanceof DummyTestClass;
         return a | b;
     }
 
     private static boolean foo2() {
-        Object obj = new VN_InstanceOf01();
-        boolean a = obj instanceof VN_InstanceOf01;
-        boolean b = obj instanceof VN_InstanceOf01;
+        Object obj = new DummyTestClass();
+        boolean a = obj instanceof DummyTestClass;
+        boolean b = obj instanceof DummyTestClass;
         return a | b;
     }
 
     private static boolean foo3() {
-        boolean a = null instanceof VN_InstanceOf01;
-        boolean b = null instanceof VN_InstanceOf01;
+        boolean a = null instanceof DummyTestClass;
+        boolean b = null instanceof DummyTestClass;
         return a | b;
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -33,7 +33,7 @@
 
     private static boolean cond = true;
 
-    static final Object object = new VN_InstanceOf02();
+    static final Object object = new DummyTestClass();
 
     public static boolean test(int arg) {
         if (arg == 0) {
@@ -50,28 +50,28 @@
     }
 
     private static boolean foo1() {
-        boolean a = object instanceof VN_InstanceOf02;
+        boolean a = object instanceof DummyTestClass;
         if (cond) {
-            boolean b = object instanceof VN_InstanceOf02;
+            boolean b = object instanceof DummyTestClass;
             return a | b;
         }
         return false;
     }
 
     private static boolean foo2() {
-        Object obj = new VN_InstanceOf02();
-        boolean a = obj instanceof VN_InstanceOf02;
+        Object obj = new DummyTestClass();
+        boolean a = obj instanceof DummyTestClass;
         if (cond) {
-            boolean b = obj instanceof VN_InstanceOf02;
+            boolean b = obj instanceof DummyTestClass;
             return a | b;
         }
         return false;
     }
 
     private static boolean foo3() {
-        boolean a = null instanceof VN_InstanceOf02;
+        boolean a = null instanceof DummyTestClass;
         if (cond) {
-            boolean b = null instanceof VN_InstanceOf02;
+            boolean b = null instanceof DummyTestClass;
             return a | b;
         }
         return false;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf03.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf03.java	Mon Jun 30 12:02:19 2014 +0200
@@ -33,17 +33,17 @@
 
     private static boolean cond = true;
 
-    static final Object object = new VN_InstanceOf03();
+    static final Object object = new DummyTestClass();
 
     public static boolean test() {
         return foo();
     }
 
     private static boolean foo() {
-        Object obj = new VN_InstanceOf03();
-        boolean a = obj instanceof VN_InstanceOf03;
+        Object obj = new DummyTestClass();
+        boolean a = obj instanceof DummyTestClass;
         if (cond) {
-            boolean b = obj instanceof VN_InstanceOf03;
+            boolean b = obj instanceof DummyTestClass;
             return a | b;
         }
         return false;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,34 +30,36 @@
  */
 public class Field_get02 extends JTTTest {
 
-    private static final Field_get02 object = new Field_get02();
+    public static class TestClass {
+        public final byte byteField = 11;
+        public final short shortField = 12;
+        public final char charField = 13;
+        public final int intField = 14;
+        public final long longField = 15;
+        public final float floatField = 16;
+        public final double doubleField = 17;
+        public final boolean booleanField = true;
+    }
 
-    public final byte byteField = 11;
-    public final short shortField = 12;
-    public final char charField = 13;
-    public final int intField = 14;
-    public final long longField = 15;
-    public final float floatField = 16;
-    public final double doubleField = 17;
-    public final boolean booleanField = true;
+    private static final TestClass object = new TestClass();
 
     public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException {
         if (arg == 0) {
-            return Field_get02.class.getField("byteField").get(object).equals(object.byteField);
+            return TestClass.class.getField("byteField").get(object).equals(object.byteField);
         } else if (arg == 1) {
-            return Field_get02.class.getField("shortField").get(object).equals(object.shortField);
+            return TestClass.class.getField("shortField").get(object).equals(object.shortField);
         } else if (arg == 2) {
-            return Field_get02.class.getField("charField").get(object).equals(object.charField);
+            return TestClass.class.getField("charField").get(object).equals(object.charField);
         } else if (arg == 3) {
-            return Field_get02.class.getField("intField").get(object).equals(object.intField);
+            return TestClass.class.getField("intField").get(object).equals(object.intField);
         } else if (arg == 4) {
-            return Field_get02.class.getField("longField").get(object).equals(object.longField);
+            return TestClass.class.getField("longField").get(object).equals(object.longField);
         } else if (arg == 5) {
-            return Field_get02.class.getField("floatField").get(object).equals(object.floatField);
+            return TestClass.class.getField("floatField").get(object).equals(object.floatField);
         } else if (arg == 6) {
-            return Field_get02.class.getField("doubleField").get(object).equals(object.doubleField);
+            return TestClass.class.getField("doubleField").get(object).equals(object.doubleField);
         } else if (arg == 7) {
-            return Field_get02.class.getField("booleanField").get(object).equals(object.booleanField);
+            return TestClass.class.getField("booleanField").get(object).equals(object.booleanField);
         }
         return false;
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java	Mon Jun 30 12:02:19 2014 +0200
@@ -43,29 +43,31 @@
 
     static {
         try {
-            ByteField = Field_get03.class.getField("byteField");
-            ShortField = Field_get03.class.getField("shortField");
-            CharField = Field_get03.class.getField("charField");
-            IntField = Field_get03.class.getField("intField");
-            LongField = Field_get03.class.getField("longField");
-            FloatField = Field_get03.class.getField("floatField");
-            DoubleField = Field_get03.class.getField("doubleField");
-            BooleanField = Field_get03.class.getField("booleanField");
+            ByteField = TestClass.class.getField("byteField");
+            ShortField = TestClass.class.getField("shortField");
+            CharField = TestClass.class.getField("charField");
+            IntField = TestClass.class.getField("intField");
+            LongField = TestClass.class.getField("longField");
+            FloatField = TestClass.class.getField("floatField");
+            DoubleField = TestClass.class.getField("doubleField");
+            BooleanField = TestClass.class.getField("booleanField");
         } catch (SecurityException | NoSuchFieldException e) {
             throw new RuntimeException(e);
         }
     }
 
-    private static final Field_get03 object = new Field_get03();
+    private static class TestClass {
+        public final byte byteField = 11;
+        public final short shortField = 12;
+        public final char charField = 13;
+        public final int intField = 14;
+        public final long longField = 15;
+        public final float floatField = 16;
+        public final double doubleField = 17;
+        public final boolean booleanField = true;
+    }
 
-    public final byte byteField = 11;
-    public final short shortField = 12;
-    public final char charField = 13;
-    public final int intField = 14;
-    public final long longField = 15;
-    public final float floatField = 16;
-    public final double doubleField = 17;
-    public final boolean booleanField = true;
+    private static final TestClass object = new TestClass();
 
     public static boolean test(int arg) throws IllegalAccessException {
         if (arg == 0) {
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,34 +30,36 @@
  */
 public class Field_get04 extends JTTTest {
 
-    private static final Field_get04 object = new Field_get04();
+    private static class TestClass {
+        public final byte byteField = 11;
+        public final short shortField = 12;
+        public final char charField = 13;
+        public final int intField = 14;
+        public final long longField = 15;
+        public final float floatField = 16;
+        public final double doubleField = 17;
+        public final boolean booleanField = true;
+    }
 
-    public final byte byteField = 11;
-    public final short shortField = 12;
-    public final char charField = 13;
-    public final int intField = 14;
-    public final long longField = 15;
-    public final float floatField = 16;
-    public final double doubleField = 17;
-    public final boolean booleanField = true;
+    private static final TestClass object = new TestClass();
 
     public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException {
         if (arg == 0) {
-            return Field_get04.class.getField("byteField").getByte(object) == object.byteField;
+            return TestClass.class.getField("byteField").getByte(object) == object.byteField;
         } else if (arg == 1) {
-            return Field_get04.class.getField("shortField").getShort(object) == object.shortField;
+            return TestClass.class.getField("shortField").getShort(object) == object.shortField;
         } else if (arg == 2) {
-            return Field_get04.class.getField("charField").getChar(object) == object.charField;
+            return TestClass.class.getField("charField").getChar(object) == object.charField;
         } else if (arg == 3) {
-            return Field_get04.class.getField("intField").getInt(object) == object.intField;
+            return TestClass.class.getField("intField").getInt(object) == object.intField;
         } else if (arg == 4) {
-            return Field_get04.class.getField("longField").getLong(object) == object.longField;
+            return TestClass.class.getField("longField").getLong(object) == object.longField;
         } else if (arg == 5) {
-            return Field_get04.class.getField("floatField").getFloat(object) == object.floatField;
+            return TestClass.class.getField("floatField").getFloat(object) == object.floatField;
         } else if (arg == 6) {
-            return Field_get04.class.getField("doubleField").getDouble(object) == object.doubleField;
+            return TestClass.class.getField("doubleField").getDouble(object) == object.doubleField;
         } else if (arg == 7) {
-            return Field_get04.class.getField("booleanField").getBoolean(object) == object.booleanField;
+            return TestClass.class.getField("booleanField").getBoolean(object) == object.booleanField;
         }
         return false;
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,41 +30,43 @@
  */
 public class Field_set02 extends JTTTest {
 
-    private static final Field_set02 object = new Field_set02();
+    private static class TestClass {
+        public byte byteField;
+        public short shortField;
+        public char charField;
+        public int intField;
+        public long longField;
+        public float floatField;
+        public double doubleField;
+        public boolean booleanField;
+    }
 
-    public byte byteField;
-    public short shortField;
-    public char charField;
-    public int intField;
-    public long longField;
-    public float floatField;
-    public double doubleField;
-    public boolean booleanField;
+    private static final TestClass object = new TestClass();
 
     public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException {
         if (arg == 0) {
-            Field_set02.class.getField("byteField").set(object, Byte.valueOf((byte) 11));
+            TestClass.class.getField("byteField").set(object, Byte.valueOf((byte) 11));
             return object.byteField == 11;
         } else if (arg == 1) {
-            Field_set02.class.getField("shortField").set(object, Short.valueOf((short) 12));
+            TestClass.class.getField("shortField").set(object, Short.valueOf((short) 12));
             return object.shortField == 12;
         } else if (arg == 2) {
-            Field_set02.class.getField("charField").set(object, Character.valueOf((char) 13));
+            TestClass.class.getField("charField").set(object, Character.valueOf((char) 13));
             return object.charField == 13;
         } else if (arg == 3) {
-            Field_set02.class.getField("intField").set(object, Integer.valueOf(14));
+            TestClass.class.getField("intField").set(object, Integer.valueOf(14));
             return object.intField == 14;
         } else if (arg == 4) {
-            Field_set02.class.getField("longField").set(object, Long.valueOf(15L));
+            TestClass.class.getField("longField").set(object, Long.valueOf(15L));
             return object.longField == 15;
         } else if (arg == 5) {
-            Field_set02.class.getField("floatField").set(object, Float.valueOf(16));
+            TestClass.class.getField("floatField").set(object, Float.valueOf(16));
             return object.floatField == 16;
         } else if (arg == 6) {
-            Field_set02.class.getField("doubleField").set(object, Double.valueOf(17));
+            TestClass.class.getField("doubleField").set(object, Double.valueOf(17));
             return object.doubleField == 17;
         } else if (arg == 7) {
-            Field_set02.class.getField("booleanField").set(object, true);
+            TestClass.class.getField("booleanField").set(object, true);
             return object.booleanField == true;
         }
         return false;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,41 +30,43 @@
  */
 public class Field_set03 extends JTTTest {
 
-    private static final Field_set03 object = new Field_set03();
+    private static class TestClass {
+        public byte byteField;
+        public short shortField;
+        public char charField;
+        public int intField;
+        public long longField;
+        public float floatField;
+        public double doubleField;
+        public boolean booleanField;
+    }
 
-    public byte byteField;
-    public short shortField;
-    public char charField;
-    public int intField;
-    public long longField;
-    public float floatField;
-    public double doubleField;
-    public boolean booleanField;
+    private static final TestClass object = new TestClass();
 
     public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException {
         if (arg == 0) {
-            Field_set03.class.getField("byteField").setByte(object, (byte) 11);
+            TestClass.class.getField("byteField").setByte(object, (byte) 11);
             return object.byteField == 11;
         } else if (arg == 1) {
-            Field_set03.class.getField("shortField").setShort(object, (short) 12);
+            TestClass.class.getField("shortField").setShort(object, (short) 12);
             return object.shortField == 12;
         } else if (arg == 2) {
-            Field_set03.class.getField("charField").setChar(object, (char) 13);
+            TestClass.class.getField("charField").setChar(object, (char) 13);
             return object.charField == 13;
         } else if (arg == 3) {
-            Field_set03.class.getField("intField").setInt(object, 14);
+            TestClass.class.getField("intField").setInt(object, 14);
             return object.intField == 14;
         } else if (arg == 4) {
-            Field_set03.class.getField("longField").setLong(object, 15L);
+            TestClass.class.getField("longField").setLong(object, 15L);
             return object.longField == 15;
         } else if (arg == 5) {
-            Field_set03.class.getField("floatField").setFloat(object, 16);
+            TestClass.class.getField("floatField").setFloat(object, 16);
             return object.floatField == 16;
         } else if (arg == 6) {
-            Field_set03.class.getField("doubleField").setDouble(object, 17);
+            TestClass.class.getField("doubleField").setDouble(object, 17);
             return object.doubleField == 17;
         } else if (arg == 7) {
-            Field_set03.class.getField("booleanField").setBoolean(object, true);
+            TestClass.class.getField("booleanField").setBoolean(object, true);
             return object.booleanField == true;
         }
         return false;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,6 +32,12 @@
  */
 public class Invoke_except01 extends JTTTest {
 
+    public static class TestClass {
+        public static int method(int[] arg) {
+            return arg.length;
+        }
+    }
+
     public static int test(int arg) throws IllegalAccessException, InvocationTargetException {
         Object[] args;
         if (arg == 0) {
@@ -45,7 +51,7 @@
         } else {
             args = null;
         }
-        for (Method m : Invoke_except01.class.getDeclaredMethods()) {
+        for (Method m : TestClass.class.getDeclaredMethods()) {
             if ("method".equals(m.getName())) {
                 return (Integer) m.invoke(null, args);
             }
@@ -53,10 +59,6 @@
         return 42;
     }
 
-    public static int method(int[] arg) {
-        return arg.length;
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,19 +32,21 @@
  */
 public class Invoke_main01 extends JTTTest {
 
+    public static class TestClass {
+        public static void main(String[] args) {
+            field = args[0];
+        }
+    }
+
     static String field;
 
     public static String test(String input) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
         field = null;
         final String[] args = {input};
-        Invoke_main01.class.getMethod("main", String[].class).invoke(null, new Object[]{args});
+        TestClass.class.getMethod("main", String[].class).invoke(null, new Object[]{args});
         return field;
     }
 
-    public static void main(String[] args) {
-        field = args[0];
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", "test1");
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,19 +32,21 @@
  */
 public class Invoke_main02 extends JTTTest {
 
+    public static class TestClass {
+        public static void main(String[] args) {
+            field = args[0];
+        }
+    }
+
     static String field;
 
     public static String test(String input) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
         field = null;
         final String[] args = {input};
-        Invoke_main02.class.getDeclaredMethod("main", String[].class).invoke(null, new Object[]{args});
+        TestClass.class.getDeclaredMethod("main", String[].class).invoke(null, new Object[]{args});
         return field;
     }
 
-    public static void main(String[] args) {
-        field = args[0];
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", "test1");
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,12 +32,18 @@
  */
 public class Invoke_main03 extends JTTTest {
 
+    public static class TestClass {
+        public static void main(String[] args) {
+            field = args[0];
+        }
+    }
+
     static String field;
 
     public static String test(String input) throws IllegalAccessException, InvocationTargetException {
         field = null;
         final String[] args = {input};
-        for (Method m : Invoke_main03.class.getDeclaredMethods()) {
+        for (Method m : TestClass.class.getDeclaredMethods()) {
             if ("main".equals(m.getName())) {
                 m.invoke(null, new Object[]{args});
             }
@@ -45,10 +51,6 @@
         return field;
     }
 
-    public static void main(String[] args) {
-        field = args[0];
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", "test1");
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,17 +28,35 @@
 
 import com.oracle.graal.jtt.*;
 
-public final class Monitor_contended01 extends JTTTest implements Runnable {
+public final class Monitor_contended01 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        boolean started = false;
+        boolean acquired = false;
+
+        public void run() {
+            // signal that we have started up so first thread will release lock
+            synchronized (cond) {
+                started = true;
+                cond.notifyAll();
+            }
+            synchronized (obj) {
+
+            }
+            // signal that we have successfully acquired and released the monitor
+            synchronized (cond) {
+                acquired = true;
+                cond.notifyAll();
+            }
+        }
+    }
 
     static final Object cond = new Object();
     static final Object obj = new Object();
 
-    boolean started = false;
-    boolean acquired = false;
-
     public static boolean test() throws InterruptedException {
         // test contention for monitor
-        final Monitor_contended01 object = new Monitor_contended01();
+        final TestClass object = new TestClass();
         synchronized (obj) {
             new Thread(object).start();
             // wait for other thread to startup and contend
@@ -56,22 +74,6 @@
         return object.acquired;
     }
 
-    public void run() {
-        // signal that we have started up so first thread will release lock
-        synchronized (cond) {
-            started = true;
-            cond.notifyAll();
-        }
-        synchronized (obj) {
-
-        }
-        // signal that we have successfully acquired and released the monitor
-        synchronized (cond) {
-            acquired = true;
-            cond.notifyAll();
-        }
-    }
-
     @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,7 +28,19 @@
 
 import com.oracle.graal.jtt.*;
 
-public class Object_wait01 extends JTTTest implements Runnable {
+public class Object_wait01 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        public void run() {
+            int i = 0;
+            while (i++ < 1000000 && !done) {
+                synchronized (object) {
+                    count++;
+                    object.notifyAll();
+                }
+            }
+        }
+    }
 
     static volatile int count = 0;
     static volatile boolean done;
@@ -37,7 +49,7 @@
     public static boolean test(int i) throws InterruptedException {
         count = 0;
         done = false;
-        new Thread(new Object_wait01()).start();
+        new Thread(new TestClass()).start();
         synchronized (object) {
             while (count < i) {
                 object.wait();
@@ -45,17 +57,6 @@
             done = true;
             return count >= i;
         }
-
-    }
-
-    public void run() {
-        int i = 0;
-        while (i++ < 1000000 && !done) {
-            synchronized (object) {
-                count++;
-                object.notifyAll();
-            }
-        }
     }
 
     @Test(timeout = 20000)
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,7 +28,21 @@
 
 import com.oracle.graal.jtt.*;
 
-public class Object_wait02 extends JTTTest implements Runnable {
+public class Object_wait02 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        public void run() {
+            try {
+                Thread.sleep(sleep);
+            } catch (InterruptedException ex) {
+
+            }
+            synchronized (object) {
+                done = true;
+                object.notifyAll();
+            }
+        }
+    }
 
     static volatile boolean done;
     static final Object object = new Object();
@@ -37,7 +51,7 @@
     public static boolean test(int i) throws InterruptedException {
         done = false;
         sleep = i * 200;
-        new Thread(new Object_wait02()).start();
+        new Thread(new TestClass()).start();
         synchronized (object) {
             while (!done) {
                 object.wait(200);
@@ -46,18 +60,6 @@
         return done;
     }
 
-    public void run() {
-        try {
-            Thread.sleep(sleep);
-        } catch (InterruptedException ex) {
-
-        }
-        synchronized (object) {
-            done = true;
-            object.notifyAll();
-        }
-    }
-
     @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,7 +28,21 @@
 
 import com.oracle.graal.jtt.*;
 
-public class Object_wait03 extends JTTTest implements Runnable {
+public class Object_wait03 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        public void run() {
+            try {
+                Thread.sleep(sleep);
+            } catch (InterruptedException ex) {
+
+            }
+            synchronized (object) {
+                done = true;
+                object.notifyAll();
+            }
+        }
+    }
 
     static volatile boolean done;
     static final Object object = new Object();
@@ -38,7 +52,7 @@
         done = false;
         sleep = i * 200;
         synchronized (object) {
-            new Thread(new Object_wait03()).start();
+            new Thread(new TestClass()).start();
             dowait();
         }
         return done;
@@ -52,18 +66,6 @@
         }
     }
 
-    public void run() {
-        try {
-            Thread.sleep(sleep);
-        } catch (InterruptedException ex) {
-
-        }
-        synchronized (object) {
-            done = true;
-            object.notifyAll();
-        }
-    }
-
     @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,7 +28,21 @@
 
 import com.oracle.graal.jtt.*;
 
-public class Object_wait04 extends JTTTest implements Runnable {
+public class Object_wait04 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        public void run() {
+            try {
+                Thread.sleep(sleep);
+            } catch (InterruptedException ex) {
+
+            }
+            synchronized (object) {
+                done = true;
+                object.notifyAll();
+            }
+        }
+    }
 
     static volatile boolean done;
     static final Object object = new Object();
@@ -38,7 +52,7 @@
         done = false;
         sleep = i * 50;
         synchronized (object) {
-            new Thread(new Object_wait04()).start();
+            new Thread(new TestClass()).start();
             dowait(i);
         }
         return done;
@@ -56,18 +70,6 @@
         }
     }
 
-    public void run() {
-        try {
-            Thread.sleep(sleep);
-        } catch (InterruptedException ex) {
-
-        }
-        synchronized (object) {
-            done = true;
-            object.notifyAll();
-        }
-    }
-
     @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,22 +28,24 @@
 
 import com.oracle.graal.jtt.*;
 
-public class Thread_join01 extends JTTTest implements Runnable {
+public class Thread_join01 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        public void run() {
+            cont = false;
+        }
+    }
 
     static volatile boolean cont;
 
     public static boolean test() throws InterruptedException {
         cont = true;
-        final Thread thread = new Thread(new Thread_join01());
+        final Thread thread = new Thread(new TestClass());
         thread.start();
         thread.join();
         return cont;
     }
 
-    public void run() {
-        cont = false;
-    }
-
     @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,26 +31,28 @@
 
 import com.oracle.graal.jtt.*;
 
-public class Thread_join02 extends JTTTest implements Runnable {
+public class Thread_join02 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        public void run() {
+            try {
+                Thread.sleep(200);
+            } catch (InterruptedException ex) {
+            }
+            cont = false;
+        }
+    }
 
     static volatile boolean cont;
 
     public static boolean test() throws InterruptedException {
         cont = true;
-        final Thread thread = new Thread(new Thread_join02());
+        final Thread thread = new Thread(new TestClass());
         thread.start();
         thread.join();
         return cont;
     }
 
-    public void run() {
-        try {
-            Thread.sleep(200);
-        } catch (InterruptedException ex) {
-        }
-        cont = false;
-    }
-
     @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,23 +31,25 @@
 
 import com.oracle.graal.jtt.*;
 
-public class Thread_join03 extends JTTTest implements Runnable {
+public class Thread_join03 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        public void run() {
+            cont = false;
+        }
+    }
 
     static volatile boolean cont;
 
     public static boolean test() throws InterruptedException {
         cont = true;
-        final Thread thread = new Thread(new Thread_join03());
+        final Thread thread = new Thread(new TestClass());
         thread.start();
         Thread.sleep(200);
         thread.join();
         return cont;
     }
 
-    public void run() {
-        cont = false;
-    }
-
     @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,9 +28,15 @@
 
 import com.oracle.graal.jtt.*;
 
-public class Thread_new02 extends JTTTest implements Runnable {
+public class Thread_new02 extends JTTTest {
 
-    static final Thread_new02 thisObject = new Thread_new02();
+    private static class TestClass implements Runnable {
+        public void run() {
+            // do nothing.
+        }
+    }
+
+    static final TestClass thisObject = new TestClass();
 
     public static boolean test(int i) {
         if (i == 0) {
@@ -48,10 +54,6 @@
         return false;
     }
 
-    public void run() {
-        // do nothing.
-    }
-
     @Test
     public void run0() throws Throwable {
         runTest("test", 0);
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -41,11 +41,11 @@
     protected final Scale scale;
     protected final int displacement;
 
-    public AMD64AddressValue(PlatformKind kind, AllocatableValue base, int displacement) {
+    public AMD64AddressValue(LIRKind kind, AllocatableValue base, int displacement) {
         this(kind, base, Value.ILLEGAL, Scale.Times1, displacement);
     }
 
-    public AMD64AddressValue(PlatformKind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) {
+    public AMD64AddressValue(LIRKind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) {
         super(kind);
         this.base = base;
         this.index = index;
@@ -93,13 +93,13 @@
     public boolean equals(Object obj) {
         if (obj instanceof AMD64AddressValue) {
             AMD64AddressValue addr = (AMD64AddressValue) obj;
-            return getPlatformKind() == addr.getPlatformKind() && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index);
+            return getLIRKind().equals(addr.getLIRKind()) && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index);
         }
         return false;
     }
 
     @Override
     public int hashCode() {
-        return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ getPlatformKind().hashCode();
+        return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ getLIRKind().hashCode();
     }
 }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -351,7 +351,7 @@
         @Use({REG, STACK}) public AllocatableValue y;
 
         public MulHighOp(AMD64Arithmetic opcode, AllocatableValue y) {
-            PlatformKind kind = y.getPlatformKind();
+            LIRKind kind = y.getLIRKind();
 
             this.opcode = opcode;
             this.x = AMD64.rax.asValue(kind);
@@ -411,8 +411,8 @@
 
         public DivRemOp(AMD64Arithmetic opcode, AllocatableValue x, AllocatableValue y, LIRFrameState state) {
             this.opcode = opcode;
-            this.divResult = AMD64.rax.asValue(x.getPlatformKind());
-            this.remResult = AMD64.rdx.asValue(x.getPlatformKind());
+            this.divResult = AMD64.rax.asValue(x.getLIRKind());
+            this.remResult = AMD64.rdx.asValue(x.getLIRKind());
             this.x = x;
             this.y = y;
             this.state = state;
@@ -446,7 +446,7 @@
         public FPDivRemOp(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
             this.opcode = opcode;
             this.result = result;
-            this.raxTemp = AMD64.rax.asValue(Kind.Int);
+            this.raxTemp = AMD64.rax.asValue(LIRKind.value(Kind.Int));
             this.x = x;
             this.y = y;
         }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -75,15 +75,15 @@
         this.lengthValue = length;
 
         // Allocate some temporaries.
-        this.temp1 = tool.newVariable(tool.target().wordKind);
-        this.temp2 = tool.newVariable(tool.target().wordKind);
-        this.temp3 = tool.newVariable(tool.target().wordKind);
-        this.temp4 = tool.newVariable(tool.target().wordKind);
+        this.temp1 = tool.newVariable(LIRKind.derivedReference(tool.target().wordKind));
+        this.temp2 = tool.newVariable(LIRKind.derivedReference(tool.target().wordKind));
+        this.temp3 = tool.newVariable(LIRKind.value(tool.target().wordKind));
+        this.temp4 = tool.newVariable(LIRKind.value(tool.target().wordKind));
 
         // We only need the vector temporaries if we generate SSE code.
         if (supportsSSE41(tool.target())) {
-            this.vectorTemp1 = tool.newVariable(Kind.Double);
-            this.vectorTemp2 = tool.newVariable(Kind.Double);
+            this.vectorTemp1 = tool.newVariable(LIRKind.value(Kind.Double));
+            this.vectorTemp2 = tool.newVariable(LIRKind.value(Kind.Double));
         } else {
             this.vectorTemp1 = Value.ILLEGAL;
             this.vectorTemp2 = Value.ILLEGAL;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -141,7 +141,7 @@
              * The register allocator does not support virtual registers that are used at the call
              * site, so use a fixed register.
              */
-            callTemp = AMD64.rax.asValue(Kind.Long);
+            callTemp = AMD64.rax.asValue(LIRKind.value(Kind.Long));
             assert ValueUtil.differentRegisters(parameters, callTemp);
         }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -157,9 +157,8 @@
                             break;
                         case Object:
                             assert condition == Condition.EQ || condition == Condition.NE;
-                            Register temp = asObjectReg(scratch);
-                            AMD64Move.move(crb, masm, temp.asValue(Kind.Object), keyConstants[index]);
-                            masm.cmpptr(keyRegister, temp);
+                            AMD64Move.move(crb, masm, scratch, keyConstants[index]);
+                            masm.cmpptr(keyRegister, asObjectReg(scratch));
                             break;
                         default:
                             throw new GraalInternalError("switch only supported for int, long and object");
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java	Mon Jun 30 12:02:19 2014 +0200
@@ -98,7 +98,7 @@
     }
 
     @Override
-    protected StackSlot allocateNewSpillSlot(PlatformKind kind, int additionalOffset) {
+    protected StackSlot allocateNewSpillSlot(LIRKind kind, int additionalOffset) {
         return StackSlot.get(kind, -spillSize + additionalOffset, true);
     }
 }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -55,7 +55,7 @@
     }
 
     protected void restoreRegister(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register register, StackSlot input) {
-        RegisterValue result = register.asValue(input.getKind());
+        RegisterValue result = register.asValue(input.getLIRKind());
         AMD64Move.move(crb, masm, result, input);
     }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -54,7 +54,7 @@
     protected final boolean supportsRemove;
 
     /**
-     * 
+     *
      * @param savedRegisters the registers saved by this operation which may be subject to
      *            {@linkplain #remove(Set) pruning}
      * @param slots the slots to which the registers are saved
@@ -67,7 +67,7 @@
     }
 
     protected void saveRegister(CompilationResultBuilder crb, AMD64MacroAssembler masm, StackSlot result, Register register) {
-        RegisterValue input = register.asValue(result.getKind());
+        RegisterValue input = register.asValue(result.getLIRKind());
         AMD64Move.move(crb, masm, result, input);
     }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -59,7 +59,7 @@
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
         for (int i = 0; i < zappedRegisters.length; i++) {
             if (zappedRegisters[i] != null) {
-                RegisterValue registerValue = zappedRegisters[i].asValue(zapValues[i].getPlatformKind());
+                RegisterValue registerValue = zappedRegisters[i].asValue(zapValues[i].getLIRKind());
                 AMD64Move.move(crb, masm, registerValue, zapValues[i]);
             }
         }
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILAddressValue.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILAddressValue.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,23 +42,23 @@
 
     /**
      * Creates an {@link HSAILAddressValue} with given base register and no displacement.
-     * 
+     *
      * @param kind the kind of the value being addressed
      * @param base the base register
      */
-    public HSAILAddressValue(Kind kind, AllocatableValue base) {
+    public HSAILAddressValue(LIRKind kind, AllocatableValue base) {
         this(kind, base, 0);
     }
 
     /**
      * Creates an {@link HSAILAddressValue} with given base register and a displacement. This is the
      * most general constructor.
-     * 
+     *
      * @param kind the kind of the value being addressed
      * @param base the base register
      * @param displacement the displacement
      */
-    public HSAILAddressValue(Kind kind, AllocatableValue base, long displacement) {
+    public HSAILAddressValue(LIRKind kind, AllocatableValue base, long displacement) {
         super(kind);
         this.base = base;
         this.displacement = displacement;
@@ -92,7 +92,7 @@
     public boolean equals(Object obj) {
         if (obj instanceof HSAILAddressValue) {
             HSAILAddressValue addr = (HSAILAddressValue) obj;
-            return getKind() == addr.getKind() && displacement == addr.displacement && base.equals(addr.base);
+            return getLIRKind().equals(addr.getLIRKind()) && displacement == addr.displacement && base.equals(addr.base);
         }
         return false;
     }
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -177,8 +177,8 @@
 
             masm.emitComment("/* HSAIL Deoptimization pos=" + codeBufferPos + ", bci=" + frameState.debugInfo().getBytecodePosition().getBCI() + ", frameState=" + frameState + " */");
 
-            AllocatableValue actionAndReasonReg = HSAIL.actionAndReasonReg.asValue(Kind.Int);
-            AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(Kind.Int);
+            AllocatableValue actionAndReasonReg = HSAIL.actionAndReasonReg.asValue(LIRKind.value(Kind.Int));
+            AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(LIRKind.value(Kind.Int));
             masm.emitMov(Kind.Int, actionAndReasonReg, actionAndReason);
             masm.emitMov(Kind.Int, codeBufferOffsetReg, Constant.forInt(codeBufferPos));
             masm.emitJumpToLabelName(masm.getDeoptLabelName());
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILFrameMap.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILFrameMap.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -28,9 +28,9 @@
 
 /**
  * HSAIL specific frame map.
- * 
+ *
  * This is the format of a HSAIL stack frame:
- * 
+ *
  * <pre>
  * TODO stack frame layout
  * </pre>
@@ -66,7 +66,7 @@
     }
 
     @Override
-    protected StackSlot allocateNewSpillSlot(PlatformKind kind, int additionalOffset) {
+    protected StackSlot allocateNewSpillSlot(LIRKind kind, int additionalOffset) {
         return StackSlot.get(kind, -spillSize + additionalOffset, true);
     }
 }
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Mon Jun 30 12:02:19 2014 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.hsail.*;
 
 /**
  * Implementation of move instructions.
@@ -167,6 +168,25 @@
             HSAILAddress addr = address.toAddress();
             masm.emitLoad(kind, result, addr);
         }
+
+        public boolean usesThreadRegister() {
+            return (address.toAddress().getBase().equals(HSAIL.threadRegister));
+        }
+    }
+
+    /**
+     * A LoadOp that uses the HSAIL ld_acq instruction
+     */
+    public static class LoadAcquireOp extends LoadOp {
+        public LoadAcquireOp(Kind kind, AllocatableValue result, HSAILAddressValue address, LIRFrameState state) {
+            super(kind, result, address, state);
+        }
+
+        @Override
+        public void emitMemAccess(HSAILAssembler masm) {
+            HSAILAddress addr = address.toAddress();
+            masm.emitLoadAcquire(result, addr);
+        }
     }
 
     public static class StoreOp extends MemOp {
@@ -186,6 +206,22 @@
         }
     }
 
+    /**
+     * A StoreOp that uses the HSAIL st_rel instruction
+     */
+    public static class StoreReleaseOp extends StoreOp {
+        public StoreReleaseOp(Kind kind, HSAILAddressValue address, AllocatableValue input, LIRFrameState state) {
+            super(kind, address, input, state);
+        }
+
+        @Override
+        public void emitMemAccess(HSAILAssembler masm) {
+            assert isRegister(input);
+            HSAILAddress addr = address.toAddress();
+            masm.emitStoreRelease(input, addr);
+        }
+    }
+
     public static class StoreConstantOp extends MemOp {
 
         protected final Constant input;
@@ -465,4 +501,18 @@
         }
     }
 
+    public static class WorkItemAbsIdOp extends HSAILLIRInstruction {
+
+        @Def({REG}) protected AllocatableValue result;
+
+        public WorkItemAbsIdOp(AllocatableValue result) {
+            this.result = result;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
+            masm.emitWorkItemAbsId(result);
+        }
+    }
+
 }
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -43,23 +43,23 @@
 
     /**
      * Creates an {@link PTXAddressValue} with given base register and no displacement.
-     * 
+     *
      * @param kind the kind of the value being addressed
      * @param base the base register
      */
-    public PTXAddressValue(PlatformKind kind, AllocatableValue base) {
+    public PTXAddressValue(LIRKind kind, AllocatableValue base) {
         this(kind, base, 0);
     }
 
     /**
      * Creates an {@link PTXAddressValue} with given base register and a displacement. This is the
      * most general constructor.
-     * 
+     *
      * @param kind the kind of the value being addressed
      * @param base the base register
      * @param displacement the displacement
      */
-    public PTXAddressValue(PlatformKind kind, AllocatableValue base, long displacement) {
+    public PTXAddressValue(LIRKind kind, AllocatableValue base, long displacement) {
         super(kind);
         this.base = base;
         this.displacement = displacement;
@@ -94,13 +94,13 @@
     public boolean equals(Object obj) {
         if (obj instanceof PTXAddressValue) {
             PTXAddressValue addr = (PTXAddressValue) obj;
-            return getPlatformKind() == addr.getPlatformKind() && displacement == addr.displacement && base.equals(addr.base);
+            return getLIRKind().equals(addr.getLIRKind()) && displacement == addr.displacement && base.equals(addr.base);
         }
         return false;
     }
 
     @Override
     public int hashCode() {
-        return base.hashCode() ^ ((int) displacement << 4) ^ getPlatformKind().hashCode();
+        return base.hashCode() ^ ((int) displacement << 4) ^ getLIRKind().hashCode();
     }
 }
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXFrameMap.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXFrameMap.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -28,9 +28,9 @@
 
 /**
  * PTX specific frame map.
- * 
+ *
  * This is the format of a PTX stack frame:
- * 
+ *
  * <pre>
  * TODO stack frame layout
  * </pre>
@@ -66,7 +66,7 @@
     }
 
     @Override
-    protected StackSlot allocateNewSpillSlot(PlatformKind kind, int additionalOffset) {
+    protected StackSlot allocateNewSpillSlot(LIRKind kind, int additionalOffset) {
         return StackSlot.get(kind, -spillSize + additionalOffset, true);
     }
 }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -39,11 +39,11 @@
     @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index;
     protected final int displacement;
 
-    public SPARCAddressValue(PlatformKind kind, AllocatableValue base, int displacement) {
+    public SPARCAddressValue(LIRKind kind, AllocatableValue base, int displacement) {
         this(kind, base, Value.ILLEGAL, displacement);
     }
 
-    public SPARCAddressValue(PlatformKind kind, AllocatableValue base, AllocatableValue index, int displacement) {
+    public SPARCAddressValue(LIRKind kind, AllocatableValue base, AllocatableValue index, int displacement) {
         super(kind);
         assert isIllegal(index) || displacement == 0;
         this.base = base;
@@ -94,13 +94,13 @@
     public boolean equals(Object obj) {
         if (obj instanceof SPARCAddressValue) {
             SPARCAddressValue addr = (SPARCAddressValue) obj;
-            return getPlatformKind() == addr.getPlatformKind() && displacement == addr.displacement && base.equals(addr.base) && index.equals(addr.index);
+            return getLIRKind().equals(addr.getLIRKind()) && displacement == addr.displacement && base.equals(addr.base) && index.equals(addr.index);
         }
         return false;
     }
 
     @Override
     public int hashCode() {
-        return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ getPlatformKind().hashCode();
+        return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ getLIRKind().hashCode();
     }
 }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -251,8 +251,8 @@
             this.result = result;
             this.x = x;
             this.y = y;
-            this.scratch1 = gen.newVariable(x.getKind());
-            this.scratch2 = gen.newVariable(x.getKind());
+            this.scratch1 = gen.newVariable(x.getLIRKind());
+            this.scratch2 = gen.newVariable(x.getLIRKind());
             this.state = state;
         }
 
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -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
@@ -62,7 +62,7 @@
         this.result = result;
         this.input = input;
         if (opcode == IntrinsicOpcode.IBSR || opcode == IntrinsicOpcode.LBSR) {
-            scratch = gen.newVariable(input.getKind());
+            scratch = gen.newVariable(input.getLIRKind());
         }
     }
 
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -192,16 +192,14 @@
                             emitCompare(masm, target, condition, CC.Icc);
                             break;
                         case Long: {
-                            Register temp = asLongReg(scratch);
-                            SPARCMove.move(crb, masm, temp.asValue(Kind.Long), keyConstants[index]);
-                            new Cmp(keyRegister, temp).emit(masm);
+                            SPARCMove.move(crb, masm, scratch, keyConstants[index]);
+                            new Cmp(keyRegister, asLongReg(scratch)).emit(masm);
                             emitCompare(masm, target, condition, CC.Xcc);
                             break;
                         }
                         case Object: {
-                            Register temp = asObjectReg(scratch);
-                            SPARCMove.move(crb, masm, temp.asValue(Kind.Object), keyConstants[index]);
-                            new Cmp(keyRegister, temp).emit(masm);
+                            SPARCMove.move(crb, masm, scratch, keyConstants[index]);
+                            new Cmp(keyRegister, asObjectReg(scratch)).emit(masm);
                             emitCompare(masm, target, condition, CC.Ptrcc);
                             break;
                         }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -34,7 +34,7 @@
  *
  * <pre>
  *   Base       Contents
- * 
+ *
  *            :                                :  -----
  *   caller   | incoming overflow argument n   |    ^
  *   frame    :     ...                        :    | positive
@@ -98,7 +98,7 @@
     }
 
     @Override
-    protected StackSlot allocateNewSpillSlot(PlatformKind kind, int additionalOffset) {
+    protected StackSlot allocateNewSpillSlot(LIRKind kind, int additionalOffset) {
         return StackSlot.get(kind, -spillSize + additionalOffset, true);
     }
 }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java	Mon Jun 30 12:02:19 2014 +0200
@@ -67,7 +67,7 @@
     }
 
     private static void saveRegister(CompilationResultBuilder crb, SPARCMacroAssembler masm, StackSlot result, Register register) {
-        RegisterValue input = register.asValue(result.getKind());
+        RegisterValue input = register.asValue(result.getLIRKind());
         SPARCMove.move(crb, masm, result, input);
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -26,9 +26,9 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 
 /**
  * Base class to represent values that need to be stored in more than one register.
@@ -48,14 +48,14 @@
 
     private static final DebugMetric COMPOSITE_VALUE_COUNT = Debug.metric("CompositeValues");
 
-    public CompositeValue(PlatformKind kind) {
+    public CompositeValue(LIRKind kind) {
         super(kind);
         COMPOSITE_VALUE_COUNT.increment();
         valueClass = CompositeValueClass.get(getClass());
     }
 
-    public final void forEachComponent(OperandMode mode, ValueProcedure proc) {
-        valueClass.forEachComponent(this, mode, proc);
+    public final void forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
+        valueClass.forEachComponent(inst, this, mode, proc);
     }
 
     @Override
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Mon Jun 30 12:02:19 2014 +0200
@@ -27,9 +27,9 @@
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.CompositeValue.Component;
+import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 
 /**
  * Lazily associated metadata for every {@link CompositeValue} type. The metadata includes:
@@ -139,8 +139,8 @@
         return str.toString();
     }
 
-    public final void forEachComponent(CompositeValue obj, OperandMode mode, ValueProcedure proc) {
-        forEach(obj, directComponentCount, componentOffsets, mode, componentFlags, proc);
+    public final void forEachComponent(LIRInstruction inst, CompositeValue obj, OperandMode mode, InstructionValueProcedure proc) {
+        forEach(inst, obj, directComponentCount, componentOffsets, mode, componentFlags, proc);
     }
 
     public String toString(CompositeValue obj) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -259,17 +259,17 @@
      * @param additionalOffset
      * @return A spill slot denoting the reserved memory area.
      */
-    protected abstract StackSlot allocateNewSpillSlot(PlatformKind kind, int additionalOffset);
+    protected abstract StackSlot allocateNewSpillSlot(LIRKind kind, int additionalOffset);
 
     /**
-     * Returns the spill slot size for the given {@link PlatformKind}. The default value is the size
-     * in bytes for the target architecture.
+     * Returns the spill slot size for the given {@link LIRKind}. The default value is the size in
+     * bytes for the target architecture.
      *
-     * @param kind the {@link PlatformKind} to be stored in the spill slot.
+     * @param kind the {@link LIRKind} to be stored in the spill slot.
      * @return the size in bytes
      */
-    public int spillSlotSize(PlatformKind kind) {
-        return target.getSizeInBytes(kind);
+    public int spillSlotSize(LIRKind kind) {
+        return target.getSizeInBytes(kind.getPlatformKind());
     }
 
     /**
@@ -280,12 +280,12 @@
      * @param kind The kind of the spill slot to be reserved.
      * @return A spill slot denoting the reserved memory area.
      */
-    public StackSlot allocateSpillSlot(PlatformKind kind) {
+    public StackSlot allocateSpillSlot(LIRKind kind) {
         assert frameSize == -1 : "frame size must not yet be fixed";
         if (freedSlots != null) {
             for (Iterator<StackSlot> iter = freedSlots.iterator(); iter.hasNext();) {
                 StackSlot s = iter.next();
-                if (s.getPlatformKind() == kind) {
+                if (s.getLIRKind().equals(kind)) {
                     iter.remove();
                     if (freedSlots.isEmpty()) {
                         freedSlots = null;
@@ -302,8 +302,8 @@
     private Set<StackSlot> freedSlots;
 
     /**
-     * Frees a spill slot that was obtained via {@link #allocateSpillSlot(PlatformKind)} such that
-     * it can be reused for the next allocation request for the same kind of slot.
+     * Frees a spill slot that was obtained via {@link #allocateSpillSlot(LIRKind)} such that it can
+     * be reused for the next allocation request for the same kind of slot.
      */
     public void freeSpillSlot(StackSlot slot) {
         if (freedSlots == null) {
@@ -338,7 +338,7 @@
             for (int slotIndex = 0; slotIndex < slots; slotIndex++) {
                 StackSlot objectSlot = null;
                 if (objects.get(slotIndex)) {
-                    objectSlot = allocateNewSpillSlot(Kind.Object, slotIndex * stackSlotSize());
+                    objectSlot = allocateNewSpillSlot(LIRKind.reference(Kind.Object), slotIndex * stackSlotSize());
                     objectStackSlots.add(objectSlot);
                     if (outObjectStackSlots != null) {
                         outObjectStackSlots.add(objectSlot);
@@ -348,7 +348,7 @@
                     if (objectSlot != null) {
                         result = objectSlot;
                     } else {
-                        result = allocateNewSpillSlot(target.wordKind, 0);
+                        result = allocateNewSpillSlot(LIRKind.value(target.wordKind), 0);
                     }
                 }
             }
@@ -356,7 +356,7 @@
             return result;
 
         } else {
-            return allocateNewSpillSlot(target.wordKind, 0);
+            return allocateNewSpillSlot(LIRKind.value(target.wordKind), 0);
         }
     }
 
@@ -377,9 +377,9 @@
      * @param refMap A reference map, as created by {@link #initReferenceMap(boolean)}.
      */
     public void setReference(Value location, ReferenceMap refMap) {
-        PlatformKind kind = location.getPlatformKind();
+        LIRKind kind = location.getLIRKind();
         if (isRegister(location)) {
-            refMap.setRegister(asRegister(location).number, kind);
+            refMap.setRegister(asRegister(location).getReferenceMapIndex(), kind);
         } else if (isStackSlot(location)) {
             int offset = offsetForStackSlot(asStackSlot(location));
             refMap.setStackSlot(offset, kind);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,9 +28,9 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 
 /**
  * This class represents garbage collection and deoptimization information attached to a LIR
@@ -59,17 +59,17 @@
     }
 
     /**
-     * Iterates the frame state and calls the {@link ValueProcedure} for every variable.
-     * 
+     * Iterates the frame state and calls the {@link InstructionValueProcedure} for every variable.
+     *
      * @param proc The procedure called for variables.
      */
-    public void forEachState(ValueProcedure proc) {
+    public void forEachState(LIRInstruction inst, InstructionValueProcedure proc) {
         for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
-            processValues(cur.values, proc);
+            processValues(inst, cur.values, proc);
         }
         if (virtualObjects != null) {
             for (VirtualObject obj : virtualObjects) {
-                processValues(obj.getValues(), proc);
+                processValues(inst, obj.getValues(), proc);
             }
         }
     }
@@ -80,16 +80,16 @@
      */
     protected static final EnumSet<OperandFlag> STATE_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK);
 
-    protected void processValues(Value[] values, ValueProcedure proc) {
+    protected void processValues(LIRInstruction inst, Value[] values, InstructionValueProcedure proc) {
         for (int i = 0; i < values.length; i++) {
             Value value = values[i];
-            values[i] = processValue(proc, value);
+            values[i] = processValue(inst, proc, value);
         }
     }
 
-    protected Value processValue(ValueProcedure proc, Value value) {
+    protected Value processValue(LIRInstruction inst, InstructionValueProcedure proc, Value value) {
         if (processed(value)) {
-            return proc.doValue(value, OperandMode.ALIVE, STATE_FLAGS);
+            return proc.doValue(inst, value, OperandMode.ALIVE, STATE_FLAGS);
         }
         return value;
     }
@@ -111,7 +111,7 @@
 
     /**
      * Called by the register allocator before {@link #markLocation} to initialize the frame state.
-     * 
+     *
      * @param frameMap The frame map.
      * @param canHaveRegisters True if there can be any register map entries.
      */
@@ -123,7 +123,7 @@
      * Called by the register allocator to mark the specified location as a reference in the
      * reference map of the debug information. The tracked location can be a {@link RegisterValue}
      * or a {@link StackSlot}. Note that a {@link Constant} is automatically tracked.
-     * 
+     *
      * @param location The location to be added to the reference map.
      * @param frameMap The frame map.
      */
@@ -133,7 +133,7 @@
 
     /**
      * Called by the register allocator after all locations are marked.
-     * 
+     *
      * @param op The instruction to which this frame state belongs.
      * @param frameMap The frame map.
      */
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Mon Jun 30 12:02:19 2014 +0200
@@ -46,12 +46,44 @@
      * methods. Clients of the class must only call the doValue method that takes additional
      * parameters.
      */
-    public abstract static class ValueProcedure {
+    public abstract static class InstructionValueProcedure {
 
         /**
          * Iterator method to be overwritten. This version of the iterator does not take additional
          * parameters to keep the signature short.
-         * 
+         *
+         * @param instruction The current instruction.
+         * @param value The value that is iterated.
+         * @return The new value to replace the value that was passed in.
+         */
+        protected Value doValue(LIRInstruction instruction, Value value) {
+            throw GraalInternalError.shouldNotReachHere("One of the doValue() methods must be overwritten");
+        }
+
+        /**
+         * Iterator method to be overwritten. This version of the iterator gets additional
+         * parameters about the processed value.
+         *
+         * @param instruction The current instruction.
+         * @param value The value that is iterated.
+         * @param mode The operand mode for the value.
+         * @param flags A set of flags for the value.
+         * @return The new value to replace the value that was passed in.
+         */
+        public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            return doValue(instruction, value);
+        }
+    }
+
+    /**
+     * Similar to {@link InstructionValueProcedure} but without an {@link LIRInstruction} parameter.
+     */
+    public abstract static class ValueProcedure extends InstructionValueProcedure {
+
+        /**
+         * Iterator method to be overwritten. This version of the iterator does not take additional
+         * parameters to keep the signature short.
+         *
          * @param value The value that is iterated.
          * @return The new value to replace the value that was passed in.
          */
@@ -62,15 +94,25 @@
         /**
          * Iterator method to be overwritten. This version of the iterator gets additional
          * parameters about the processed value.
-         * 
+         *
          * @param value The value that is iterated.
          * @param mode The operand mode for the value.
          * @param flags A set of flags for the value.
          * @return The new value to replace the value that was passed in.
          */
-        public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        protected Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
             return doValue(value);
         }
+
+        @Override
+        final protected Value doValue(LIRInstruction instruction, Value value) {
+            throw GraalInternalError.shouldNotReachHere("This doValue() methods should never be called");
+        }
+
+        @Override
+        final public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            return doValue(value, mode, flags);
+        }
     }
 
     public abstract static class StateProcedure {
@@ -255,23 +297,23 @@
         return false;
     }
 
-    public final void forEachInput(ValueProcedure proc) {
+    public final void forEachInput(InstructionValueProcedure proc) {
         instructionClass.forEachUse(this, proc);
     }
 
-    public final void forEachAlive(ValueProcedure proc) {
+    public final void forEachAlive(InstructionValueProcedure proc) {
         instructionClass.forEachAlive(this, proc);
     }
 
-    public final void forEachTemp(ValueProcedure proc) {
+    public final void forEachTemp(InstructionValueProcedure proc) {
         instructionClass.forEachTemp(this, proc);
     }
 
-    public final void forEachOutput(ValueProcedure proc) {
+    public final void forEachOutput(InstructionValueProcedure proc) {
         instructionClass.forEachDef(this, proc);
     }
 
-    public final void forEachState(ValueProcedure proc) {
+    public final void forEachState(InstructionValueProcedure proc) {
         instructionClass.forEachState(this, proc);
     }
 
@@ -286,7 +328,7 @@
      * Subclasses can override this method. The default implementation processes all Input operands
      * as the hints for an Output operand, and all Output operands as the hints for an Input
      * operand.
-     * 
+     *
      * @param value The value the hints are needed for.
      * @param mode The operand mode of the value.
      * @param proc The procedure invoked for all the hints. If the procedure returns a non-null
@@ -294,7 +336,7 @@
      *            clients can stop the iteration once a suitable hint has been found.
      * @return The non-null value returned by the procedure, or null.
      */
-    public Value forEachRegisterHint(Value value, OperandMode mode, ValueProcedure proc) {
+    public Value forEachRegisterHint(Value value, OperandMode mode, InstructionValueProcedure proc) {
         return instructionClass.forEachRegisterHint(this, mode, proc);
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,10 +28,10 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.LIRInstruction.StateProcedure;
-import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 
 public class LIRInstructionClass extends LIRIntrospection {
 
@@ -262,27 +262,27 @@
         return false;
     }
 
-    public final void forEachUse(LIRInstruction obj, ValueProcedure proc) {
-        forEach(obj, directUseCount, useOffsets, OperandMode.USE, useFlags, proc);
+    public final void forEachUse(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, obj, directUseCount, useOffsets, OperandMode.USE, useFlags, proc);
     }
 
-    public final void forEachAlive(LIRInstruction obj, ValueProcedure proc) {
-        forEach(obj, directAliveCount, aliveOffsets, OperandMode.ALIVE, aliveFlags, proc);
+    public final void forEachAlive(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, obj, directAliveCount, aliveOffsets, OperandMode.ALIVE, aliveFlags, proc);
     }
 
-    public final void forEachTemp(LIRInstruction obj, ValueProcedure proc) {
-        forEach(obj, directTempCount, tempOffsets, OperandMode.TEMP, tempFlags, proc);
+    public final void forEachTemp(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, obj, directTempCount, tempOffsets, OperandMode.TEMP, tempFlags, proc);
     }
 
-    public final void forEachDef(LIRInstruction obj, ValueProcedure proc) {
-        forEach(obj, directDefCount, defOffsets, OperandMode.DEF, defFlags, proc);
+    public final void forEachDef(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, obj, directDefCount, defOffsets, OperandMode.DEF, defFlags, proc);
     }
 
-    public final void forEachState(LIRInstruction obj, ValueProcedure proc) {
+    public final void forEachState(LIRInstruction obj, InstructionValueProcedure proc) {
         for (int i = 0; i < stateOffsets.length; i++) {
             LIRFrameState state = getState(obj, stateOffsets[i]);
             if (state != null) {
-                state.forEachState(proc);
+                state.forEachState(obj, proc);
             }
         }
     }
@@ -296,7 +296,7 @@
         }
     }
 
-    public final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, ValueProcedure proc) {
+    public final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, InstructionValueProcedure proc) {
         int hintDirectCount = 0;
         long[] hintOffsets = null;
         if (mode == OperandMode.USE) {
@@ -312,7 +312,7 @@
         for (int i = 0; i < hintOffsets.length; i++) {
             if (i < hintDirectCount) {
                 Value hintValue = getValue(obj, hintOffsets[i]);
-                Value result = proc.doValue(hintValue, null, null);
+                Value result = proc.doValue(obj, hintValue, null, null);
                 if (result != null) {
                     return result;
                 }
@@ -320,7 +320,7 @@
                 Value[] hintValues = getValueArray(obj, hintOffsets[i]);
                 for (int j = 0; j < hintValues.length; j++) {
                     Value hintValue = hintValues[j];
-                    Value result = proc.doValue(hintValue, null, null);
+                    Value result = proc.doValue(obj, hintValue, null, null);
                     if (result != null) {
                         return result;
                     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,9 +32,9 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 
 abstract class LIRIntrospection extends FieldIntrospection {
 
@@ -119,7 +119,7 @@
         }
     }
 
-    protected static void forEach(Object obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, ValueProcedure proc) {
+    protected static void forEach(LIRInstruction inst, Object obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, InstructionValueProcedure proc) {
         for (int i = 0; i < offsets.length; i++) {
             assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
 
@@ -127,9 +127,9 @@
                 Value value = getValue(obj, offsets[i]);
                 if (value instanceof CompositeValue) {
                     CompositeValue composite = (CompositeValue) value;
-                    composite.forEachComponent(mode, proc);
+                    composite.forEachComponent(inst, mode, proc);
                 } else {
-                    setValue(obj, offsets[i], proc.doValue(value, mode, flags[i]));
+                    setValue(obj, offsets[i], proc.doValue(inst, value, mode, flags[i]));
                 }
             } else {
                 Value[] values = getValueArray(obj, offsets[i]);
@@ -137,9 +137,9 @@
                     Value value = values[j];
                     if (value instanceof CompositeValue) {
                         CompositeValue composite = (CompositeValue) value;
-                        composite.forEachComponent(mode, proc);
+                        composite.forEachComponent(inst, mode, proc);
                     } else {
-                        values[j] = proc.doValue(value, mode, flags[i]);
+                        values[j] = proc.doValue(inst, value, mode, flags[i]);
                     }
                 }
             }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
@@ -62,14 +63,15 @@
         return isRegister(value) && frameMap.registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable();
     }
 
-    public static boolean verify(final LIRInstruction op) {
-        ValueProcedure allowedProc = new ValueProcedure() {
+    private static InstructionValueProcedure allowedProc = new InstructionValueProcedure() {
 
-            @Override
-            public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-                return allowed(op, value, mode, flags);
-            }
-        };
+        @Override
+        public Value doValue(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            return allowed(op, value, mode, flags);
+        }
+    };
+
+    public static boolean verify(final LIRInstruction op) {
 
         op.forEachInput(allowedProc);
         op.forEachAlive(allowedProc);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -340,7 +340,7 @@
                 int sourceIdx = getStateIdx(moveOp.getInput());
                 int destIdx = getStateIdx(moveOp.getResult());
                 if (sourceIdx >= 0 && destIdx >= 0) {
-                    assert isObjectValue(state[sourceIdx]) || (moveOp.getInput().getKind() != Kind.Object) : "move op moves object but input is not defined as object";
+                    assert isObjectValue(state[sourceIdx]) || moveOp.getInput().getLIRKind().isValue() : "move op moves object but input is not defined as object";
                     state[destIdx] = state[sourceIdx];
                     Debug.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx);
                     return initValueNum;
@@ -378,7 +378,7 @@
                         /*
                          * Assign a unique number to the output or temp location.
                          */
-                        state[stateIdx] = encodeValueNum(opValueNum++, operand.getKind() == Kind.Object);
+                        state[stateIdx] = encodeValueNum(opValueNum++, !operand.getLIRKind().isValue());
                         Debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]);
                     }
                     return operand;
@@ -510,7 +510,7 @@
             /*
              * Moves with mismatching kinds are not moves, but memory loads/stores!
              */
-            return source.getKind() == dest.getKind() && source.getPlatformKind() == dest.getPlatformKind() && source.getKind() != Kind.Illegal;
+            return source.getLIRKind().equals(dest.getLIRKind());
         }
         return false;
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -42,11 +42,11 @@
 
     /**
      * Creates a new variable.
-     * 
+     *
      * @param kind
      * @param index
      */
-    public Variable(PlatformKind kind, int index) {
+    public Variable(LIRKind kind, int index) {
         super(kind);
         assert index >= 0;
         this.index = index;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/ArithmeticLIRGenerator.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/ArithmeticLIRGenerator.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -32,7 +32,7 @@
  */
 public interface ArithmeticLIRGenerator {
 
-    PlatformKind getPlatformKind(Stamp stamp);
+    LIRKind getLIRKind(Stamp stamp);
 
     Value emitNegate(Value input);
 
@@ -70,7 +70,7 @@
 
     Value emitFloatConvert(FloatConvert op, Value inputVal);
 
-    Value emitReinterpret(PlatformKind to, Value inputVal);
+    Value emitReinterpret(LIRKind to, Value inputVal);
 
     Value emitNarrow(Value inputVal, int bits);
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,9 +23,6 @@
 package com.oracle.graal.lir.gen;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.api.meta.Value.*;
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.lir.LIR.*;
 import static com.oracle.graal.lir.LIRValueUtil.*;
 
 import java.util.*;
@@ -42,13 +39,12 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
 import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.NoOp;
 import com.oracle.graal.options.*;
 
 /**
  * This class traverses the HIR instructions and generates LIR instructions from them.
  */
-public abstract class LIRGenerator implements LIRGeneratorTool, PlatformKindTool {
+public abstract class LIRGenerator implements LIRGeneratorTool, LIRKindTool {
 
     public static class Options {
         // @formatter:off
@@ -64,97 +60,6 @@
 
     private AbstractBlock<?> currentBlock;
 
-    /**
-     * Handle for an operation that loads a constant into a variable. The operation starts in the
-     * first block where the constant is used but will eventually be
-     * {@linkplain LIRGenerator#insertConstantLoads() moved} to a block dominating all usages of the
-     * constant.
-     */
-    public static class LoadConstant implements Comparable<LoadConstant> {
-        /**
-         * The index of {@link #op} within {@link #block}'s instruction list or -1 if {@code op} is
-         * to be moved to a dominator block.
-         */
-        int index;
-
-        /**
-         * The operation that loads the constant.
-         */
-        private final LIRInstruction op;
-
-        /**
-         * The block that does or will contain {@link #op}. This is initially the block where the
-         * first usage of the constant is seen during LIR generation.
-         */
-        AbstractBlock<?> block;
-
-        /**
-         * The variable into which the constant is loaded.
-         */
-        final Variable variable;
-
-        public LoadConstant(Variable variable, AbstractBlock<?> block, int index, LIRInstruction op) {
-            this.variable = variable;
-            this.block = block;
-            this.index = index;
-            this.op = op;
-        }
-
-        /**
-         * Sorts {@link LoadConstant} objects according to their enclosing blocks. This is used to
-         * group loads per block in {@link LIRGenerator#insertConstantLoads()}.
-         */
-        public int compareTo(LoadConstant o) {
-            if (block.getId() < o.block.getId()) {
-                return -1;
-            }
-            if (block.getId() > o.block.getId()) {
-                return 1;
-            }
-            return 0;
-        }
-
-        @Override
-        public String toString() {
-            return block + "#" + op;
-        }
-
-        /**
-         * Removes the {@link #op} from its original location if it is still at that location.
-         */
-        public void unpin(LIR lir) {
-            if (index >= 0) {
-                // Replace the move with a filler op so that the operation
-                // list does not need to be adjusted.
-                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-                instructions.set(index, new NoOp(null, -1));
-                index = -1;
-            }
-        }
-
-        public AbstractBlock<?> getBlock() {
-            return block;
-        }
-
-        public void setBlock(AbstractBlock<?> block) {
-            this.block = block;
-        }
-
-        public Variable getVariable() {
-            return variable;
-        }
-
-        public int getIndex() {
-            return index;
-        }
-
-        public void setIndex(int index) {
-            this.index = index;
-        }
-    }
-
-    private Map<Constant, LoadConstant> constantLoads;
-
     private LIRGenerationResult res;
 
     public LIRGenerator(CodeGenProviders providers, CallingConvention cc, LIRGenerationResult res) {
@@ -198,12 +103,12 @@
     /**
      * Creates a new {@linkplain Variable variable}.
      *
-     * @param platformKind The kind of the new variable.
+     * @param lirKind The kind of the new variable.
      * @return a new variable
      */
     @Override
-    public Variable newVariable(PlatformKind platformKind) {
-        return new Variable(platformKind, res.getLIR().nextVariable());
+    public Variable newVariable(LIRKind lirKind) {
+        return new Variable(lirKind, res.getLIR().nextVariable());
     }
 
     @Override
@@ -250,11 +155,8 @@
      * @return the operand representing the ABI defined location used return a value of kind
      *         {@code kind}
      */
-    public AllocatableValue resultOperandFor(Kind kind) {
-        if (kind == Kind.Void) {
-            return ILLEGAL;
-        }
-        return res.getFrameMap().registerConfig.getReturnRegister(kind).asValue(kind);
+    public AllocatableValue resultOperandFor(LIRKind kind) {
+        return res.getFrameMap().registerConfig.getReturnRegister((Kind) kind.getPlatformKind()).asValue(kind);
     }
 
     public void append(LIRInstruction op) {
@@ -328,10 +230,11 @@
         if (value.getKind().getStackKind() != value.getKind()) {
             // We only have stack-kinds in the LIR, so convert the operand kind for values from the
             // calling convention.
+            LIRKind stackKind = value.getLIRKind().changeType(value.getKind().getStackKind());
             if (isRegister(value)) {
-                return asRegister(value).asValue(value.getKind().getStackKind());
+                return asRegister(value).asValue(stackKind);
             } else if (isStackSlot(value)) {
-                return StackSlot.get(value.getKind().getStackKind(), asStackSlot(value).getRawOffset(), asStackSlot(value).getRawAddFrameSize());
+                return StackSlot.get(stackKind, asStackSlot(value).getRawOffset(), asStackSlot(value).getRawAddFrameSize());
             } else {
                 throw GraalInternalError.shouldNotReachHere();
             }
@@ -409,83 +312,6 @@
 
     @Override
     public void beforeRegisterAllocation() {
-        insertConstantLoads();
-    }
-
-    /**
-     * Moves deferred {@linkplain LoadConstant loads} of constants into blocks dominating all usages
-     * of the constant. Any operations inserted into a block are guaranteed to be immediately prior
-     * to the first control flow instruction near the end of the block.
-     */
-    private void insertConstantLoads() {
-        if (constantLoads != null) {
-            // Remove loads where all usages are in the same block.
-            for (Iterator<Map.Entry<Constant, LoadConstant>> iter = constantLoads.entrySet().iterator(); iter.hasNext();) {
-                LoadConstant lc = iter.next().getValue();
-
-                // Move loads of constant outside of loops
-                if (OptScheduleOutOfLoops.getValue()) {
-                    AbstractBlock<?> outOfLoopDominator = lc.block;
-                    while (outOfLoopDominator.getLoop() != null) {
-                        outOfLoopDominator = outOfLoopDominator.getDominator();
-                    }
-                    if (outOfLoopDominator != lc.block) {
-                        lc.unpin(res.getLIR());
-                        lc.block = outOfLoopDominator;
-                    }
-                }
-
-                if (lc.index != -1) {
-                    assert res.getLIR().getLIRforBlock(lc.block).get(lc.index) == lc.op;
-                    iter.remove();
-                }
-            }
-            if (constantLoads.isEmpty()) {
-                return;
-            }
-
-            // Sorting groups the loads per block.
-            LoadConstant[] groupedByBlock = constantLoads.values().toArray(new LoadConstant[constantLoads.size()]);
-            Arrays.sort(groupedByBlock);
-
-            int groupBegin = 0;
-            while (true) {
-                int groupEnd = groupBegin + 1;
-                AbstractBlock<?> block = groupedByBlock[groupBegin].block;
-                while (groupEnd < groupedByBlock.length && groupedByBlock[groupEnd].block == block) {
-                    groupEnd++;
-                }
-                int groupSize = groupEnd - groupBegin;
-
-                List<LIRInstruction> ops = res.getLIR().getLIRforBlock(block);
-                int lastIndex = ops.size() - 1;
-                assert ops.get(lastIndex) instanceof BlockEndOp;
-                int insertionIndex = lastIndex;
-                for (int i = Math.max(0, lastIndex - MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END); i < lastIndex; i++) {
-                    if (getExceptionEdge(ops.get(i)) != null) {
-                        insertionIndex = i;
-                        break;
-                    }
-                }
-
-                if (groupSize == 1) {
-                    ops.add(insertionIndex, groupedByBlock[groupBegin].op);
-                } else {
-                    assert groupSize > 1;
-                    List<LIRInstruction> moves = new ArrayList<>(groupSize);
-                    for (int i = groupBegin; i < groupEnd; i++) {
-                        moves.add(groupedByBlock[i].op);
-                    }
-                    ops.addAll(insertionIndex, moves);
-                }
-
-                if (groupEnd == groupedByBlock.length) {
-                    break;
-                }
-                groupBegin = groupEnd;
-            }
-            constantLoads = null;
-        }
     }
 
     /**
@@ -520,47 +346,47 @@
     /**
      * Default implementation: Return the Java stack kind for each stamp.
      */
-    public PlatformKind getPlatformKind(Stamp stamp) {
-        return stamp.getPlatformKind(this);
+    public LIRKind getLIRKind(Stamp stamp) {
+        return stamp.getLIRKind(this);
     }
 
-    public PlatformKind getIntegerKind(int bits) {
+    public LIRKind getIntegerKind(int bits) {
         if (bits <= 8) {
-            return Kind.Byte;
+            return LIRKind.value(Kind.Byte);
         } else if (bits <= 16) {
-            return Kind.Short;
+            return LIRKind.value(Kind.Short);
         } else if (bits <= 32) {
-            return Kind.Int;
+            return LIRKind.value(Kind.Int);
         } else {
             assert bits <= 64;
-            return Kind.Long;
+            return LIRKind.value(Kind.Long);
         }
     }
 
-    public PlatformKind getFloatingKind(int bits) {
+    public LIRKind getFloatingKind(int bits) {
         switch (bits) {
             case 32:
-                return Kind.Float;
+                return LIRKind.value(Kind.Float);
             case 64:
-                return Kind.Double;
+                return LIRKind.value(Kind.Double);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
     }
 
-    public PlatformKind getObjectKind() {
-        return Kind.Object;
+    public LIRKind getObjectKind() {
+        return LIRKind.reference(Kind.Object);
     }
 
-    public abstract void emitBitCount(Variable result, Value operand);
-
-    public abstract void emitBitScanForward(Variable result, Value operand);
-
-    public abstract void emitBitScanReverse(Variable result, Value operand);
-
-    public abstract void emitByteSwap(Variable result, Value operand);
-
-    public abstract void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+    protected LIRKind getAddressKind(Value base, long displacement, Value index) {
+        if (base.getLIRKind().isValue() && (index.equals(Value.ILLEGAL) || index.getLIRKind().isValue())) {
+            return LIRKind.value(target().wordKind);
+        } else if (base.getLIRKind().isReference(0) && displacement == 0L && index.equals(Value.ILLEGAL)) {
+            return LIRKind.reference(target().wordKind);
+        } else {
+            return LIRKind.derivedReference(target().wordKind);
+        }
+    }
 
     public AbstractBlock<?> getCurrentBlock() {
         return currentBlock;
@@ -573,12 +399,4 @@
     public LIRGenerationResult getResult() {
         return res;
     }
-
-    public Map<Constant, LoadConstant> getConstantLoads() {
-        return constantLoads;
-    }
-
-    public void setConstantLoads(Map<Constant, LoadConstant> constantLoads) {
-        this.constantLoads = constantLoads;
-    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.lir.gen;
 
-import java.util.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
@@ -31,7 +29,6 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.common.spi.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.gen.LIRGenerator.*;
 
 public interface LIRGeneratorTool extends ArithmeticLIRGenerator {
 
@@ -55,13 +52,9 @@
 
     void doBlockEnd(AbstractBlock<?> block);
 
-    Map<Constant, LoadConstant> getConstantLoads();
-
-    void setConstantLoads(Map<Constant, LoadConstant> constantLoads);
+    Value emitLoad(LIRKind kind, Value address, LIRFrameState state);
 
-    Value emitLoad(PlatformKind kind, Value address, LIRFrameState state);
-
-    void emitStore(PlatformKind kind, Value address, Value input, LIRFrameState state);
+    void emitStore(LIRKind kind, Value address, Value input, LIRFrameState state);
 
     void emitNullCheck(Value address, LIRFrameState state);
 
@@ -113,7 +106,7 @@
 
     RegisterAttributes attributes(Register register);
 
-    Variable newVariable(PlatformKind kind);
+    Variable newVariable(LIRKind kind);
 
     Variable emitMove(Value input);
 
@@ -173,7 +166,7 @@
      * @return the operand representing the ABI defined location used return a value of kind
      *         {@code kind}
      */
-    AllocatableValue resultOperandFor(Kind kind);
+    AllocatableValue resultOperandFor(LIRKind kind);
 
     void append(LIRInstruction op);
 
@@ -196,14 +189,14 @@
 
     CallingConvention getCallingConvention();
 
-    void emitBitCount(Variable result, Value operand);
+    Value emitBitCount(Value operand);
 
-    void emitBitScanForward(Variable result, Value operand);
+    Value emitBitScanForward(Value operand);
 
-    void emitBitScanReverse(Variable result, Value operand);
+    Value emitBitScanReverse(Value operand);
 
-    void emitByteSwap(Variable result, Value operand);
+    Value emitByteSwap(Value operand);
 
-    void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+    Value emitArrayEquals(Kind kind, Value array1, Value array2, Value length);
 
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Mon Jun 30 12:02:19 2014 +0200
@@ -124,12 +124,12 @@
         ValueNode stride = strideNode();
         ValueNode initNode = this.initNode();
         if (!fromStamp.isCompatible(stamp)) {
-            stride = IntegerConvertNode.convert(stride, stamp);
-            initNode = IntegerConvertNode.convert(initNode, stamp);
+            stride = IntegerConvertNode.convert(stride, stamp, graph());
+            initNode = IntegerConvertNode.convert(initNode, stamp, graph());
         }
         ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount);
         if (!maxTripCount.stamp().isCompatible(stamp)) {
-            maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp);
+            maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph());
         }
         return IntegerArithmeticNode.add(graph, IntegerArithmeticNode.mul(graph, stride, IntegerArithmeticNode.sub(graph, maxTripCount, ConstantNode.forIntegerStamp(stamp, 1, graph))), initNode);
     }
@@ -139,7 +139,7 @@
         Stamp stamp = phi.stamp();
         ValueNode maxTripCount = loop.counted().maxTripCountNode(false);
         if (!maxTripCount.stamp().isCompatible(stamp)) {
-            maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp);
+            maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph());
         }
         return IntegerArithmeticNode.add(graph(), IntegerArithmeticNode.mul(graph(), strideNode(), maxTripCount), initNode());
     }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Mon Jun 30 12:02:19 2014 +0200
@@ -62,7 +62,7 @@
                 range = IntegerArithmeticNode.sub(graph, range, ConstantNode.forIntegerStamp(stamp, 1, graph));
             }
         }
-        IntegerDivNode div = graph.add(new IntegerDivNode(iv.valueNode().stamp().unrestricted(), range, iv.strideNode()));
+        IntegerDivNode div = graph.add(new IntegerDivNode(range, iv.strideNode()));
         graph.addBeforeFixed(loop.entryPoint(), div);
         ConstantNode zero = ConstantNode.forIntegerStamp(stamp, 0, graph);
         if (assumePositive) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Mon Jun 30 12:02:19 2014 +0200
@@ -72,7 +72,7 @@
 
     @Override
     public long constantStride() {
-        if (value instanceof IntegerSubNode && base.valueNode() == value.y()) {
+        if (value instanceof IntegerSubNode && base.valueNode() == value.getY()) {
             return -base.constantStride();
         }
         return base.constantStride();
@@ -85,7 +85,7 @@
 
     @Override
     public ValueNode strideNode() {
-        if (value instanceof IntegerSubNode && base.valueNode() == value.y()) {
+        if (value instanceof IntegerSubNode && base.valueNode() == value.getY()) {
             return graph().unique(new NegateNode(base.strideNode()));
         }
         return base.strideNode();
@@ -93,7 +93,7 @@
 
     @Override
     public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp) {
-        return op(base.extremumNode(assumePositiveTripCount, stamp), IntegerConvertNode.convert(offset, stamp));
+        return op(base.extremumNode(assumePositiveTripCount, stamp), IntegerConvertNode.convert(offset, stamp, graph()));
     }
 
     @Override
@@ -116,10 +116,10 @@
             return b + o;
         }
         if (value instanceof IntegerSubNode) {
-            if (base.valueNode() == value.x()) {
+            if (base.valueNode() == value.getX()) {
                 return b - o;
             } else {
-                assert base.valueNode() == value.y();
+                assert base.valueNode() == value.getY();
                 return o - b;
             }
         }
@@ -131,10 +131,10 @@
             return IntegerArithmeticNode.add(graph(), b, o);
         }
         if (value instanceof IntegerSubNode) {
-            if (base.valueNode() == value.x()) {
+            if (base.valueNode() == value.getX()) {
                 return IntegerArithmeticNode.sub(graph(), b, o);
             } else {
-                assert base.valueNode() == value.y();
+                assert base.valueNode() == value.getY();
                 return IntegerArithmeticNode.sub(graph(), o, b);
             }
         }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Mon Jun 30 12:02:19 2014 +0200
@@ -25,6 +25,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.util.*;
 
 public class DerivedScaledInductionVariable extends InductionVariable {
 
@@ -102,7 +103,7 @@
 
     @Override
     public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp) {
-        return IntegerArithmeticNode.mul(graph(), base.extremumNode(assumePositiveTripCount, stamp), IntegerConvertNode.convert(scale, stamp));
+        return IntegerArithmeticNode.mul(graph(), base.extremumNode(assumePositiveTripCount, stamp), IntegerConvertNode.convert(scale, stamp, graph()));
     }
 
     @Override
@@ -119,4 +120,11 @@
     public long constantExtremum() {
         return base.constantExtremum() * scale.asConstant().asLong();
     }
+
+    @Override
+    public void deleteUnusedNodes() {
+        if (scale.isAlive() && scale.usages().isEmpty()) {
+            GraphUtil.killWithUnusedFloatingInputs(scale);
+        }
+    }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java	Mon Jun 30 12:02:19 2014 +0200
@@ -62,7 +62,7 @@
     public abstract Direction direction();
 
     /**
-     * Returns the value node that is described by this InductionVariable instance.
+     * Returns the value node that is described by this induction variable.
      */
     public abstract ValueNode valueNode();
 
@@ -104,4 +104,10 @@
      * induction variable at the loop exit.
      */
     public abstract ValueNode exitValueNode();
+
+    /**
+     * Deletes any nodes created within the scope of this object that have no usages.
+     */
+    public void deleteUnusedNodes() {
+    }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Mon Jun 30 12:02:19 2014 +0200
@@ -95,10 +95,10 @@
     private ValueNode addSub(ValueNode op, ValueNode base) {
         if (op instanceof IntegerAddNode || op instanceof IntegerSubNode) {
             IntegerArithmeticNode aritOp = (IntegerArithmeticNode) op;
-            if (aritOp.x() == base && loop.isOutsideLoop(aritOp.y())) {
-                return aritOp.y();
-            } else if (aritOp.y() == base && loop.isOutsideLoop(aritOp.x())) {
-                return aritOp.x();
+            if (aritOp.getX() == base && loop.isOutsideLoop(aritOp.getY())) {
+                return aritOp.getY();
+            } else if (aritOp.getY() == base && loop.isOutsideLoop(aritOp.getX())) {
+                return aritOp.getX();
             }
         }
         return null;
@@ -107,18 +107,27 @@
     private ValueNode mul(ValueNode op, ValueNode base) {
         if (op instanceof IntegerMulNode) {
             IntegerMulNode mul = (IntegerMulNode) op;
-            if (mul.x() == base && loop.isOutsideLoop(mul.y())) {
-                return mul.y();
-            } else if (mul.y() == base && loop.isOutsideLoop(mul.x())) {
-                return mul.x();
+            if (mul.getX() == base && loop.isOutsideLoop(mul.getY())) {
+                return mul.getY();
+            } else if (mul.getY() == base && loop.isOutsideLoop(mul.getX())) {
+                return mul.getX();
             }
         }
         if (op instanceof LeftShiftNode) {
             LeftShiftNode shift = (LeftShiftNode) op;
-            if (shift.x() == base && shift.y().isConstant()) {
-                return ConstantNode.forInt(1 << shift.y().asConstant().asInt(), base.graph());
+            if (shift.getX() == base && shift.getY().isConstant()) {
+                return ConstantNode.forInt(1 << shift.getY().asConstant().asInt(), base.graph());
             }
         }
         return null;
     }
+
+    /**
+     * Deletes any nodes created within the scope of this object that have no usages.
+     */
+    public void deleteUnusedNodes() {
+        for (InductionVariable iv : ivs.values()) {
+            iv.deleteUnusedNodes();
+        }
+    }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Mon Jun 30 12:02:19 2014 +0200
@@ -39,20 +39,20 @@
 
 public class LoopEx {
 
-    private final Loop<Block> lirLoop;
+    private final Loop<Block> loop;
     private LoopFragmentInside inside;
     private LoopFragmentWhole whole;
     private CountedLoopInfo counted; // TODO (gd) detect
     private LoopsData data;
     private InductionVariables ivs;
 
-    LoopEx(Loop<Block> lirLoop, LoopsData data) {
-        this.lirLoop = lirLoop;
+    LoopEx(Loop<Block> loop, LoopsData data) {
+        this.loop = loop;
         this.data = data;
     }
 
-    public Loop<Block> lirLoop() {
-        return lirLoop;
+    public Loop<Block> loop() {
+        return loop;
     }
 
     public LoopFragmentInside inside() {
@@ -91,7 +91,7 @@
     }
 
     public LoopBeginNode loopBegin() {
-        return (LoopBeginNode) lirLoop().getHeader().getBeginNode();
+        return (LoopBeginNode) loop().getHeader().getBeginNode();
     }
 
     public FixedNode predecessor() {
@@ -111,10 +111,10 @@
     }
 
     public LoopEx parent() {
-        if (lirLoop.getParent() == null) {
+        if (loop.getParent() == null) {
             return null;
         }
-        return data.loop(lirLoop.getParent());
+        return data.loop(loop.getParent());
     }
 
     public int size() {
@@ -123,7 +123,7 @@
 
     @Override
     public String toString() {
-        return (isCounted() ? "CountedLoop [" + counted() + "] " : "Loop ") + "(depth=" + lirLoop().getDepth() + ") " + loopBegin();
+        return (isCounted() ? "CountedLoop [" + counted() + "] " : "Loop ") + "(depth=" + loop().getDepth() + ") " + loopBegin();
     }
 
     private class InvariantPredicate implements NodePredicate {
@@ -141,11 +141,15 @@
             if (!BinaryNode.canTryReassociate(binary)) {
                 continue;
             }
-            BinaryNode result = BinaryNode.reassociate(binary, invariant);
+            BinaryNode result = BinaryNode.reassociate(binary, invariant, binary.getX(), binary.getY());
             if (result != binary) {
                 if (Debug.isLogEnabled()) {
                     Debug.log("%s : Reassociated %s into %s", MetaUtil.format("%H::%n", graph.method()), binary, result);
                 }
+                if (!result.isAlive()) {
+                    assert !result.isDeleted();
+                    result = graph.addOrUniqueWithInputs(result);
+                }
                 graph.replaceFloating(binary, result);
             }
         }
@@ -177,17 +181,17 @@
             Condition condition = null;
             InductionVariable iv = null;
             ValueNode limit = null;
-            if (isOutsideLoop(lessThan.x())) {
-                iv = getInductionVariables().get(lessThan.y());
+            if (isOutsideLoop(lessThan.getX())) {
+                iv = getInductionVariables().get(lessThan.getY());
                 if (iv != null) {
                     condition = lessThan.condition().mirror();
-                    limit = lessThan.x();
+                    limit = lessThan.getX();
                 }
-            } else if (isOutsideLoop(lessThan.y())) {
-                iv = getInductionVariables().get(lessThan.x());
+            } else if (isOutsideLoop(lessThan.getY())) {
+                iv = getInductionVariables().get(lessThan.getX());
                 if (iv != null) {
                     condition = lessThan.condition();
-                    limit = lessThan.y();
+                    limit = lessThan.getY();
                 }
             }
             if (condition == null) {
@@ -237,9 +241,9 @@
             if (b == untilBlock) {
                 continue;
             }
-            if (lirLoop().getExits().contains(b)) {
+            if (loop().getExits().contains(b)) {
                 exits.add((LoopExitNode) b.getBeginNode());
-            } else if (lirLoop().getBlocks().contains(b)) {
+            } else if (loop().getBlocks().contains(b)) {
                 blocks.add(b.getBeginNode());
                 work.addAll(b.getDominated());
             }
@@ -253,4 +257,13 @@
         }
         return ivs;
     }
+
+    /**
+     * Deletes any nodes created within the scope of this object that have no usages.
+     */
+    public void deleteUnusedNodes() {
+        if (ivs != null) {
+            ivs.deleteUnusedNodes();
+        }
+    }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon Jun 30 12:02:19 2014 +0200
@@ -302,7 +302,7 @@
     protected void mergeEarlyExits() {
         assert isDuplicate();
         StructuredGraph graph = graph();
-        for (BeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().getExits())) {
+        for (BeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().loop().getExits())) {
             LoopExitNode loopEarlyExit = (LoopExitNode) earlyExit;
             FixedNode next = loopEarlyExit.next();
             if (loopEarlyExit.isDeleted() || !this.original().contains(loopEarlyExit)) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java	Mon Jun 30 12:02:19 2014 +0200
@@ -56,8 +56,8 @@
     @Override
     public NodeBitMap nodes() {
         if (nodes == null) {
-            Loop<Block> lirLoop = loop().lirLoop();
-            nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(lirLoop.getBlocks()), LoopFragment.toHirExits(lirLoop.getExits()));
+            Loop<Block> loop = loop().loop();
+            nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(loop.getBlocks()), LoopFragment.toHirExits(loop.getExits()));
         }
         return nodes;
     }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Mon Jun 30 12:02:19 2014 +0200
@@ -34,7 +34,7 @@
 
 public class LoopsData {
 
-    private Map<Loop<Block>, LoopEx> lirLoopToEx = newIdentityMap();
+    private Map<Loop<Block>, LoopEx> loopToEx = newIdentityMap();
     private Map<LoopBeginNode, LoopEx> loopBeginToEx = newNodeIdentityMap();
     private ControlFlowGraph cfg;
 
@@ -45,15 +45,15 @@
             throw Debug.handle(e);
         }
 
-        for (Loop<Block> lirLoop : cfg.getLoops()) {
-            LoopEx ex = new LoopEx(lirLoop, this);
-            lirLoopToEx.put(lirLoop, ex);
+        for (Loop<Block> loop : cfg.getLoops()) {
+            LoopEx ex = new LoopEx(loop, this);
+            loopToEx.put(loop, ex);
             loopBeginToEx.put(ex.loopBegin(), ex);
         }
     }
 
-    public LoopEx loop(Loop<?> lirLoop) {
-        return lirLoopToEx.get(lirLoop);
+    public LoopEx loop(Loop<?> loop) {
+        return loopToEx.get(loop);
     }
 
     public LoopEx loop(LoopBeginNode loopBegin) {
@@ -61,16 +61,16 @@
     }
 
     public Collection<LoopEx> loops() {
-        return lirLoopToEx.values();
+        return loopToEx.values();
     }
 
-    public List<LoopEx> outterFirst() {
+    public List<LoopEx> outerFirst() {
         ArrayList<LoopEx> loops = new ArrayList<>(loops());
         Collections.sort(loops, new Comparator<LoopEx>() {
 
             @Override
             public int compare(LoopEx o1, LoopEx o2) {
-                return o1.lirLoop().getDepth() - o2.lirLoop().getDepth();
+                return o1.loop().getDepth() - o2.loop().getDepth();
             }
         });
         return loops;
@@ -82,7 +82,7 @@
 
             @Override
             public int compare(LoopEx o1, LoopEx o2) {
-                return o2.lirLoop().getDepth() - o1.lirLoop().getDepth();
+                return o2.loop().getDepth() - o1.loop().getDepth();
             }
         });
         return loops;
@@ -121,4 +121,13 @@
         }
         return match;
     }
+
+    /**
+     * Deletes any nodes created within the scope of this object that have no usages.
+     */
+    public void deleteUnusedNodes() {
+        for (LoopEx loop : loops()) {
+            loop.deleteUnusedNodes();
+        }
+    }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -56,6 +56,7 @@
                         break;
                     }
                 }
+                dataCounted.deleteUnusedNodes();
             } while (peeled);
         }
     }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -37,7 +37,7 @@
         if (context.getOptimisticOptimizations().useLoopLimitChecks()) {
             loops.detectedCountedLoops();
             for (LoopEx loop : loops.countedLoops()) {
-                if (loop.lirLoop().getChildren().isEmpty() && loop.counted().getStamp().getBits() <= 32) {
+                if (loop.loop().getChildren().isEmpty() && loop.counted().getStamp().getBits() <= 32) {
                     boolean hasSafepoint = false;
                     for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
                         hasSafepoint |= loopEnd.canSafepoint();
@@ -54,7 +54,7 @@
         for (LoopEx loop : loops.countedLoops()) {
             for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
                 Block b = loops.controlFlowGraph().blockFor(loopEnd);
-                blocks: while (b != loop.lirLoop().getHeader()) {
+                blocks: while (b != loop.loop().getHeader()) {
                     assert b != null;
                     for (FixedNode node : b.getNodes()) {
                         if (node instanceof Invoke || node instanceof ForeignCallNode) {
@@ -66,5 +66,6 @@
                 }
             }
         }
+        loops.deleteUnusedNodes();
     }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -40,13 +40,14 @@
             if (LoopPeeling.getValue()) {
                 ToDoubleFunction<FixedNode> probabilities = new FixedNodeProbabilityCache();
                 LoopsData data = new LoopsData(graph);
-                for (LoopEx loop : data.outterFirst()) {
+                for (LoopEx loop : data.outerFirst()) {
                     if (LoopPolicies.shouldPeel(loop, probabilities)) {
                         Debug.log("Peeling %s", loop);
                         LoopTransformations.peel(loop);
                         Debug.dump(graph, "After peeling %s", loop);
                     }
                 }
+                data.deleteUnusedNodes();
             }
         }
     }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -47,6 +47,7 @@
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
+                dataReassociate.deleteUnusedNodes();
             }
             if (LoopUnswitch.getValue()) {
                 boolean unswitched;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/LoopPhiCanonicalizerTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 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.test;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class LoopPhiCanonicalizerTest extends GraalCompilerTest {
+
+    private static int[] array = new int[1000];
+
+    @BeforeClass
+    public static void before() {
+        for (int i = 0; i < array.length; i++) {
+            array[i] = i;
+        }
+    }
+
+    public static long loopSnippet() {
+        int a = 0;
+        int b = 0;
+        int c = 0;
+        int d = 0;
+
+        long sum = 0;
+        while (d < 1000) {
+            sum += array[a++] + array[b++] + array[c++] + array[d++];
+        }
+        return sum;
+    }
+
+    @Test
+    public void test() {
+        StructuredGraph graph = parse("loopSnippet");
+        NodePredicate loopPhis = node -> node instanceof PhiNode && ((PhiNode) node).merge() instanceof LoopBeginNode;
+
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        Assert.assertEquals(5, graph.getNodes().filter(loopPhis).count());
+        new CanonicalizerPhase(false).apply(graph, context);
+        Assert.assertEquals(2, graph.getNodes().filter(loopPhis).count());
+
+        test("loopSnippet");
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,7 +28,7 @@
 
 /**
  * This node represents an unconditional explicit request for immediate deoptimization.
- * 
+ *
  * After this node, execution will continue using a fallback execution engine (such as an
  * interpreter) at the position described by the {@link #stateBefore() deoptimization state}.
  */
@@ -40,6 +40,11 @@
         super(StampFactory.forVoid());
     }
 
+    public AbstractDeoptimizeNode(FrameState stateBefore) {
+        super(StampFactory.forVoid());
+        this.stateBefore = stateBefore;
+    }
+
     @Override
     public boolean canDeoptimize() {
         return true;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -78,7 +78,7 @@
     public void simplify(SimplifierTool tool) {
         while (condition instanceof LogicNegationNode) {
             LogicNegationNode negation = (LogicNegationNode) condition;
-            setCondition(negation.getInput());
+            setCondition(negation.getValue());
             negated = !negated;
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -22,22 +22,19 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.TriState;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.spi.*;
 
-public abstract class BinaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable {
+public abstract class BinaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable.Binary<ValueNode> {
 
     @Input private ValueNode x;
     @Input private ValueNode y;
 
-    public ValueNode x() {
+    public ValueNode getX() {
         return x;
     }
 
-    public ValueNode y() {
+    public ValueNode getY() {
         return y;
     }
 
@@ -57,8 +54,6 @@
         this.y = y;
     }
 
-    public abstract TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY);
-
     @Override
     public boolean verify() {
         assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp());
@@ -66,17 +61,6 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        switch (evaluate(tool.getConstantReflection(), x(), y())) {
-            case FALSE:
-                return LogicConstantNode.contradiction(graph());
-            case TRUE:
-                return LogicConstantNode.tautology(graph());
-        }
-        return this;
-    }
-
-    @Override
     public void generate(NodeLIRBuilderTool gen) {
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -29,7 +29,7 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(nameTemplate = "ConditionAnchor(!={p#negated})", allowedUsageTypes = {InputType.Guard})
-public final class ConditionAnchorNode extends FixedWithNextNode implements Canonicalizable, Lowerable, GuardingNode {
+public final class ConditionAnchorNode extends FixedWithNextNode implements Canonicalizable.Unary<Node>, Lowerable, GuardingNode {
 
     @Input(InputType.Condition) private LogicNode condition;
     private boolean negated;
@@ -48,11 +48,6 @@
         return condition;
     }
 
-    private void setCondition(LogicNode x) {
-        updateUsages(condition, x);
-        condition = x;
-    }
-
     public boolean isNegated() {
         return negated;
     }
@@ -66,24 +61,19 @@
         }
     }
 
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public Node canonical(CanonicalizerTool tool, Node forValue) {
         if (condition instanceof LogicNegationNode) {
             LogicNegationNode negation = (LogicNegationNode) condition;
-            setCondition(negation.getInput());
-            negated = !negated;
+            return new ConditionAnchorNode(negation.getValue(), !negated);
         }
-
         if (condition instanceof LogicConstantNode) {
             LogicConstantNode c = (LogicConstantNode) condition;
             if (c.getValue() != negated) {
-                this.replaceAtUsages(null);
                 return null;
             } else {
-                return graph().add(new ValueAnchorNode(null));
+                return new ValueAnchorNode(null);
             }
         }
-
         return this;
     }
 
@@ -94,4 +84,8 @@
             graph().replaceFixedWithFixed(this, newAnchor);
         }
     }
+
+    public Node getValue() {
+        return condition;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -68,34 +68,6 @@
     }
 
     /**
-     * Used to measure the impact of ConstantNodes not recording their usages. This and all code
-     * predicated on this value being true will be removed at some point.
-     */
-    public static final boolean ConstantNodeRecordsUsages = Boolean.parseBoolean(System.getProperty("graal.constantNodeRecordsUsages", "true"));
-
-    @Override
-    public boolean recordsUsages() {
-        return ConstantNodeRecordsUsages;
-    }
-
-    /**
-     * Computes the usages of this node by iterating over all the nodes in the graph, searching for
-     * those that have this node as an input.
-     */
-    public List<Node> gatherUsages(StructuredGraph graph) {
-        assert !ConstantNodeRecordsUsages;
-        List<Node> usages = new ArrayList<>();
-        for (Node node : graph.getNodes()) {
-            for (Node input : node.inputs()) {
-                if (input == this) {
-                    usages.add(node);
-                }
-            }
-        }
-        return usages;
-    }
-
-    /**
      * Gathers all the {@link ConstantNode}s that are inputs to the
      * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.
      */
@@ -104,25 +76,15 @@
     }
 
     /**
-     * Replaces this node at its usages with another node. If {@link #ConstantNodeRecordsUsages} is
-     * false, this is an expensive operation that should only be used in test/verification/AOT code.
+     * Replaces this node at its usages with another node.
      */
     public void replace(StructuredGraph graph, Node replacement) {
-        if (!recordsUsages()) {
-            List<Node> usages = gatherUsages(graph);
-            for (Node usage : usages) {
-                usage.replaceFirstInput(this, replacement);
-            }
-            graph.removeFloating(this);
-        } else {
-            assert graph == graph();
-            graph().replaceFloating(this, replacement);
-        }
+        assert graph == graph();
+        graph().replaceFloating(this, replacement);
     }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        assert ConstantNodeRecordsUsages : "LIR generator should generate constants per-usage";
         if (gen.getLIRGeneratorTool().canInlineConstant(value) || onlyUsedInVirtualState()) {
             gen.setResult(this, value);
         } else {
@@ -152,10 +114,25 @@
         }
     }
 
+    public static ConstantNode forConstant(Constant constant, MetaAccessProvider metaAccess) {
+        if (constant.getKind().getStackKind() == Kind.Int && constant.getKind() != Kind.Int) {
+            return forInt(constant.asInt());
+        }
+        if (constant.getKind() == Kind.Object) {
+            return new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess));
+        } else {
+            return createPrimitive(constant);
+        }
+    }
+
     public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph) {
         return graph.unique(new ConstantNode(constant, stamp.constant(constant, metaAccess)));
     }
 
+    public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess) {
+        return new ConstantNode(constant, stamp.constant(constant, metaAccess));
+    }
+
     /**
      * Returns a node for a Java primitive.
      */
@@ -165,6 +142,14 @@
     }
 
     /**
+     * Returns a node for a Java primitive.
+     */
+    public static ConstantNode forPrimitive(Constant constant) {
+        assert constant.getKind() != Kind.Object;
+        return forConstant(constant, null);
+    }
+
+    /**
      * Returns a node for a primitive of a given type.
      */
     public static ConstantNode forPrimitive(Stamp stamp, Constant constant, StructuredGraph graph) {
@@ -179,6 +164,20 @@
     }
 
     /**
+     * Returns a node for a primitive of a given type.
+     */
+    public static ConstantNode forPrimitive(Stamp stamp, Constant constant) {
+        if (stamp instanceof IntegerStamp) {
+            assert constant.getKind().isNumericInteger() && stamp.getStackKind() == constant.getKind().getStackKind();
+            IntegerStamp istamp = (IntegerStamp) stamp;
+            return forIntegerBits(istamp.getBits(), constant);
+        } else {
+            assert constant.getKind().isNumericFloat() && stamp.getStackKind() == constant.getKind();
+            return forConstant(constant, null);
+        }
+    }
+
+    /**
      * Returns a node for a double constant.
      *
      * @param d the double value for which to create the instruction
@@ -189,6 +188,16 @@
     }
 
     /**
+     * Returns a node for a double constant.
+     *
+     * @param d the double value for which to create the instruction
+     * @return a node for a double constant
+     */
+    public static ConstantNode forDouble(double d) {
+        return createPrimitive(Constant.forDouble(d));
+    }
+
+    /**
      * Returns a node for a float constant.
      *
      * @param f the float value for which to create the instruction
@@ -199,6 +208,16 @@
     }
 
     /**
+     * Returns a node for a float constant.
+     *
+     * @param f the float value for which to create the instruction
+     * @return a node for a float constant
+     */
+    public static ConstantNode forFloat(float f) {
+        return createPrimitive(Constant.forFloat(f));
+    }
+
+    /**
      * Returns a node for an long constant.
      *
      * @param i the long value for which to create the instruction
@@ -209,6 +228,16 @@
     }
 
     /**
+     * Returns a node for an long constant.
+     *
+     * @param i the long value for which to create the instruction
+     * @return a node for an long constant
+     */
+    public static ConstantNode forLong(long i) {
+        return createPrimitive(Constant.forLong(i));
+    }
+
+    /**
      * Returns a node for an integer constant.
      *
      * @param i the integer value for which to create the instruction
@@ -219,6 +248,16 @@
     }
 
     /**
+     * Returns a node for an integer constant.
+     *
+     * @param i the integer value for which to create the instruction
+     * @return a node for an integer constant
+     */
+    public static ConstantNode forInt(int i) {
+        return createPrimitive(Constant.forInt(i));
+    }
+
+    /**
      * Returns a node for a boolean constant.
      *
      * @param i the boolean value for which to create the instruction
@@ -229,6 +268,16 @@
     }
 
     /**
+     * Returns a node for a boolean constant.
+     *
+     * @param i the boolean value for which to create the instruction
+     * @return a node representing the boolean
+     */
+    public static ConstantNode forBoolean(boolean i) {
+        return createPrimitive(Constant.forInt(i ? 1 : 0));
+    }
+
+    /**
      * Returns a node for a byte constant.
      *
      * @param i the byte value for which to create the instruction
@@ -276,6 +325,20 @@
         return forIntegerBits(bits, Constant.forPrimitiveInt(bits, value), graph);
     }
 
+    private static ConstantNode forIntegerBits(int bits, Constant constant) {
+        long value = constant.asLong();
+        long bounds = SignExtendNode.signExtend(value, bits);
+        return new ConstantNode(constant, StampFactory.forInteger(bits, bounds, bounds));
+    }
+
+    /**
+     * Returns a node for a constant integer that's not directly representable as Java primitive
+     * (e.g. short).
+     */
+    public static ConstantNode forIntegerBits(int bits, long value) {
+        return forIntegerBits(bits, Constant.forPrimitiveInt(bits, value));
+    }
+
     /**
      * Returns a node for a constant integer that's compatible to a given stamp.
      */
@@ -288,6 +351,18 @@
         }
     }
 
+    /**
+     * Returns a node for a constant integer that's compatible to a given stamp.
+     */
+    public static ConstantNode forIntegerStamp(Stamp stamp, long value) {
+        if (stamp instanceof IntegerStamp) {
+            IntegerStamp intStamp = (IntegerStamp) stamp;
+            return forIntegerBits(intStamp.getBits(), value);
+        } else {
+            return forIntegerKind(stamp.getStackKind(), value);
+        }
+    }
+
     public static ConstantNode forIntegerKind(Kind kind, long value, StructuredGraph graph) {
         switch (kind) {
             case Byte:
@@ -301,6 +376,19 @@
         }
     }
 
+    public static ConstantNode forIntegerKind(Kind kind, long value) {
+        switch (kind) {
+            case Byte:
+            case Short:
+            case Int:
+                return createPrimitive(Constant.forInt((int) value));
+            case Long:
+                return createPrimitive(Constant.forLong(value));
+            default:
+                throw GraalInternalError.shouldNotReachHere("unknown kind " + kind);
+        }
+    }
+
     public static ConstantNode forFloatingKind(Kind kind, double value, StructuredGraph graph) {
         switch (kind) {
             case Float:
@@ -312,6 +400,17 @@
         }
     }
 
+    public static ConstantNode forFloatingKind(Kind kind, double value) {
+        switch (kind) {
+            case Float:
+                return ConstantNode.forFloat((float) value);
+            case Double:
+                return ConstantNode.forDouble(value);
+            default:
+                throw GraalInternalError.shouldNotReachHere("unknown kind " + kind);
+        }
+    }
+
     /**
      * Returns a node for a constant double that's compatible to a given stamp.
      */
@@ -319,6 +418,13 @@
         return forFloatingKind(stamp.getStackKind(), value, graph);
     }
 
+    /**
+     * Returns a node for a constant double that's compatible to a given stamp.
+     */
+    public static ConstantNode forFloatingStamp(Stamp stamp, double value) {
+        return forFloatingKind(stamp.getStackKind(), value);
+    }
+
     public static ConstantNode defaultForKind(Kind kind, StructuredGraph graph) {
         switch (kind) {
             case Boolean:
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -35,10 +35,11 @@
     private final Constant speculation;
 
     public DeoptimizeNode(DeoptimizationAction action, DeoptimizationReason reason) {
-        this(action, reason, 0, Constant.NULL_OBJECT);
+        this(action, reason, 0, Constant.NULL_OBJECT, null);
     }
 
-    public DeoptimizeNode(DeoptimizationAction action, DeoptimizationReason reason, int debugId, Constant speculation) {
+    public DeoptimizeNode(DeoptimizationAction action, DeoptimizationReason reason, int debugId, Constant speculation, FrameState stateBefore) {
+        super(stateBefore);
         assert action != null;
         assert reason != null;
         assert speculation.getKind() == Kind.Object;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -33,6 +33,11 @@
         super(stamp);
     }
 
+    public DeoptimizingFixedWithNextNode(Stamp stamp, FrameState stateBefore) {
+        super(stamp);
+        this.stateBefore = stateBefore;
+    }
+
     @Override
     public FrameState stateBefore() {
         return stateBefore;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -63,10 +63,8 @@
         if (actionAndReason.isConstant() && speculation.isConstant()) {
             Constant constant = actionAndReason.asConstant();
             Constant speculationConstant = speculation.asConstant();
-            DeoptimizeNode newDeopt = graph().add(
-                            new DeoptimizeNode(tool.getMetaAccess().decodeDeoptAction(constant), tool.getMetaAccess().decodeDeoptReason(constant), tool.getMetaAccess().decodeDebugId(constant),
-                                            speculationConstant));
-            newDeopt.setStateBefore(stateBefore());
+            DeoptimizeNode newDeopt = new DeoptimizeNode(tool.getMetaAccess().decodeDeoptAction(constant), tool.getMetaAccess().decodeDeoptReason(constant), tool.getMetaAccess().decodeDebugId(
+                            constant), speculationConstant, stateBefore());
             return newDeopt;
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.java.*;
@@ -40,6 +41,8 @@
 @NodeInfo(nameTemplate = "FrameState@{p#method/s}:{p#bci}")
 public final class FrameState extends VirtualState implements IterableNodeType {
 
+    private static final DebugMetric METRIC_FRAMESTATE_COUNT = Debug.metric("FrameStateCount");
+
     protected final int localsSize;
 
     protected final int stackSize;
@@ -97,6 +100,7 @@
         this.duringCall = duringCall;
         assert !this.rethrowException || this.stackSize == 1 : "must have exception on top of the stack";
         assert this.locksSize() == this.monitorIds.size();
+        METRIC_FRAMESTATE_COUNT.increment();
     }
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -65,11 +65,6 @@
         return condition;
     }
 
-    public void setCondition(LogicNode x) {
-        updateUsages(condition, x);
-        condition = x;
-    }
-
     public boolean negated() {
         return negated;
     }
@@ -103,11 +98,11 @@
     public Node canonical(CanonicalizerTool tool) {
         if (condition() instanceof LogicNegationNode) {
             LogicNegationNode negation = (LogicNegationNode) condition();
-            return graph().unique(new GuardNode(negation.getInput(), getAnchor(), reason, action, !negated, speculation));
-        } else if (condition() instanceof LogicConstantNode) {
+            return new GuardNode(negation.getValue(), getAnchor(), reason, action, !negated, speculation);
+        }
+        if (condition() instanceof LogicConstantNode) {
             LogicConstantNode c = (LogicConstantNode) condition();
             if (c.getValue() != negated) {
-                this.replaceAtUsages(null);
                 return null;
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -83,7 +83,7 @@
             if (stamp().equals(object().stamp())) {
                 return object();
             } else {
-                return graph().unique(new PiNode(object(), stamp()));
+                return new PiNode(object(), stamp());
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -94,8 +94,10 @@
     public void lower(LoweringTool tool) {
         GuardingNode guard = tool.createGuard(next(), condition, reason, action, negated);
         ValueAnchorNode anchor = graph().add(new ValueAnchorNode((ValueNode) guard));
-        PiNode pi = graph().unique(new PiNode(object, stamp(), (ValueNode) guard));
-        replaceAtUsages(pi);
+        if (usages().isNotEmpty()) {
+            PiNode pi = graph().unique(new PiNode(object, stamp(), (ValueNode) guard));
+            replaceAtUsages(pi);
+        }
         graph().replaceFixedWithFixed(this, anchor);
     }
 
@@ -116,19 +118,19 @@
     public Node canonical(CanonicalizerTool tool) {
         if (stamp() == StampFactory.illegal(object.getKind())) {
             // The guard always fails
-            return graph().add(new DeoptimizeNode(action, reason));
+            return new DeoptimizeNode(action, reason);
         }
         if (condition instanceof LogicConstantNode) {
             LogicConstantNode c = (LogicConstantNode) condition;
             if (c.getValue() == negated) {
                 // The guard always fails
-                return graph().add(new DeoptimizeNode(action, reason));
+                return new DeoptimizeNode(action, reason);
             } else if (stamp().equals(object().stamp())) {
                 // The guard always succeeds, and does not provide new type information
                 return object;
             } else {
                 // The guard always succeeds, and provides new type information
-                return graph().unique(new PiNode(object, stamp()));
+                return new PiNode(object, stamp());
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -147,7 +147,7 @@
             setTrueSuccessor(null);
             setFalseSuccessor(null);
             LogicNegationNode negation = (LogicNegationNode) condition();
-            IfNode newIfNode = graph().add(new IfNode(negation.getInput(), falseSucc, trueSucc, 1 - trueSuccessorProbability));
+            IfNode newIfNode = graph().add(new IfNode(negation.getValue(), falseSucc, trueSucc, 1 - trueSuccessorProbability));
             predecessor().replaceFirstSuccessor(this, newIfNode);
             GraphUtil.killWithUnusedFloatingInputs(this);
             return;
@@ -229,15 +229,17 @@
                         trueNext.replaceAtPredecessor(next);
                         graph().addBeforeFixed(this, trueNext);
                         for (Node usage : trueNext.usages().snapshot()) {
-                            if (usage.getNodeClass().valueNumberable() && !usage.getNodeClass().isLeafNode()) {
-                                Node newNode = graph().findDuplicate(usage);
-                                if (newNode != null) {
-                                    usage.replaceAtUsages(newNode);
-                                    usage.safeDelete();
+                            if (usage.isAlive()) {
+                                if (usage.getNodeClass().valueNumberable() && !usage.getNodeClass().isLeafNode()) {
+                                    Node newNode = graph().findDuplicate(usage);
+                                    if (newNode != null) {
+                                        usage.replaceAtUsages(newNode);
+                                        usage.safeDelete();
+                                    }
                                 }
-                            }
-                            if (usage.isAlive()) {
-                                tool.addToWorkList(usage);
+                                if (usage.isAlive()) {
+                                    tool.addToWorkList(usage);
+                                }
                             }
                         }
                         continue;
@@ -257,7 +259,7 @@
         assert trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty();
         if (condition() instanceof IntegerLessThanNode) {
             IntegerLessThanNode lessThan = (IntegerLessThanNode) condition();
-            Constant y = lessThan.y().stamp().asConstant();
+            Constant y = lessThan.getY().stamp().asConstant();
             if (y != null && y.asLong() == 0 && falseSuccessor().next() instanceof IfNode) {
                 IfNode ifNode2 = (IfNode) falseSuccessor().next();
                 if (ifNode2.condition() instanceof IntegerLessThanNode) {
@@ -269,24 +271,24 @@
                      * Convert x >= 0 && x < positive which is represented as !(x < 0) && x <
                      * <positive> into an unsigned compare.
                      */
-                    if (lessThan2.x() == lessThan.x() && lessThan2.y().stamp() instanceof IntegerStamp && ((IntegerStamp) lessThan2.y().stamp()).isPositive() &&
+                    if (lessThan2.getX() == lessThan.getX() && lessThan2.getY().stamp() instanceof IntegerStamp && ((IntegerStamp) lessThan2.getY().stamp()).isPositive() &&
                                     sameDestination(trueSuccessor(), ifNode2.falseSuccessor)) {
-                        below = graph().unique(new IntegerBelowThanNode(lessThan2.x(), lessThan2.y()));
+                        below = graph().unique(new IntegerBelowThanNode(lessThan2.getX(), lessThan2.getY()));
                         // swap direction
                         BeginNode tmp = falseSucc;
                         falseSucc = trueSucc;
                         trueSucc = tmp;
-                    } else if (lessThan2.y() == lessThan.x() && sameDestination(trueSuccessor(), ifNode2.trueSuccessor)) {
+                    } else if (lessThan2.getY() == lessThan.getX() && sameDestination(trueSuccessor(), ifNode2.trueSuccessor)) {
                         /*
                          * Convert x >= 0 && x <= positive which is represented as !(x < 0) &&
                          * !(<positive> > x), into x <| positive + 1. This can only be done for
                          * constants since there isn't a IntegerBelowEqualThanNode but that doesn't
                          * appear to be interesting.
                          */
-                        Constant positive = lessThan2.x().asConstant();
+                        Constant positive = lessThan2.getX().asConstant();
                         if (positive != null && positive.asLong() > 0 && positive.asLong() < positive.getKind().getMaxValue()) {
                             ConstantNode newLimit = ConstantNode.forIntegerKind(positive.getKind(), positive.asLong() + 1, graph());
-                            below = graph().unique(new IntegerBelowThanNode(lessThan.x(), newLimit));
+                            below = graph().unique(new IntegerBelowThanNode(lessThan.getX(), newLimit));
                         }
                     }
                     if (below != null) {
@@ -353,7 +355,7 @@
             InstanceOfNode instanceOfA = (InstanceOfNode) a;
             if (b instanceof IsNullNode) {
                 IsNullNode isNullNode = (IsNullNode) b;
-                if (isNullNode.object() == instanceOfA.object()) {
+                if (isNullNode.getValue() == instanceOfA.getValue()) {
                     if (instanceOfA.profile() != null && instanceOfA.profile().getNullSeen() != TriState.FALSE) {
                         instanceOfA.setProfile(new JavaTypeProfile(TriState.FALSE, instanceOfA.profile().getNotRecordedProbability(), instanceOfA.profile().getTypes()));
                     }
@@ -362,7 +364,7 @@
                 }
             } else if (b instanceof InstanceOfNode) {
                 InstanceOfNode instanceOfB = (InstanceOfNode) b;
-                if (instanceOfA.object() == instanceOfB.object() && !instanceOfA.type().isInterface() && !instanceOfB.type().isInterface() &&
+                if (instanceOfA.getValue() == instanceOfB.getValue() && !instanceOfA.type().isInterface() && !instanceOfB.type().isInterface() &&
                                 !instanceOfA.type().isAssignableFrom(instanceOfB.type()) && !instanceOfB.type().isAssignableFrom(instanceOfA.type())) {
                     // Two instanceof on the same value with mutually exclusive types.
                     JavaTypeProfile profileA = instanceOfA.profile();
@@ -423,9 +425,9 @@
                 }
                 Condition comparableCondition = null;
                 Condition conditionB = compareB.condition();
-                if (compareB.x() == compareA.x() && compareB.y() == compareA.y()) {
+                if (compareB.getX() == compareA.getX() && compareB.getY() == compareA.getY()) {
                     comparableCondition = conditionB;
-                } else if (compareB.x() == compareA.y() && compareB.y() == compareA.x()) {
+                } else if (compareB.getX() == compareA.getY() && compareB.getY() == compareA.getX()) {
                     comparableCondition = conditionB.mirror();
                 }
 
@@ -438,13 +440,13 @@
                     }
                 } else if (conditionA == Condition.EQ && conditionB == Condition.EQ) {
                     boolean canSwap = false;
-                    if ((compareA.x() == compareB.x() && valuesDistinct(constantReflection, compareA.y(), compareB.y()))) {
+                    if ((compareA.getX() == compareB.getX() && valuesDistinct(constantReflection, compareA.getY(), compareB.getY()))) {
                         canSwap = true;
-                    } else if ((compareA.x() == compareB.y() && valuesDistinct(constantReflection, compareA.y(), compareB.x()))) {
+                    } else if ((compareA.getX() == compareB.getY() && valuesDistinct(constantReflection, compareA.getY(), compareB.getX()))) {
                         canSwap = true;
-                    } else if ((compareA.y() == compareB.x() && valuesDistinct(constantReflection, compareA.x(), compareB.y()))) {
+                    } else if ((compareA.getY() == compareB.getX() && valuesDistinct(constantReflection, compareA.getX(), compareB.getY()))) {
                         canSwap = true;
-                    } else if ((compareA.y() == compareB.y() && valuesDistinct(constantReflection, compareA.x(), compareB.x()))) {
+                    } else if ((compareA.getY() == compareB.getY() && valuesDistinct(constantReflection, compareA.getX(), compareB.getX()))) {
                         canSwap = true;
                     }
 
@@ -558,11 +560,11 @@
             }
             boolean negateConditionalCondition;
             ValueNode otherValue;
-            if (constant == conditional.x()) {
-                otherValue = conditional.y();
+            if (constant == conditional.trueValue()) {
+                otherValue = conditional.falseValue();
                 negateConditionalCondition = false;
-            } else if (constant == conditional.y()) {
-                otherValue = conditional.x();
+            } else if (constant == conditional.falseValue()) {
+                otherValue = conditional.trueValue();
                 negateConditionalCondition = true;
             } else {
                 return null;
@@ -643,7 +645,7 @@
             return false;
         }
         Node singleUsage = mergeUsages.first();
-        if (!(singleUsage instanceof ValuePhiNode) || (singleUsage != compare.x() && singleUsage != compare.y())) {
+        if (!(singleUsage instanceof ValuePhiNode) || (singleUsage != compare.getX() && singleUsage != compare.getY())) {
             return false;
         }
 
@@ -662,8 +664,8 @@
         List<AbstractEndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
         assert phi.valueCount() == merge.forwardEndCount();
 
-        Constant[] xs = constantValues(compare.x(), merge, false);
-        Constant[] ys = constantValues(compare.y(), merge, false);
+        Constant[] xs = constantValues(compare.getX(), merge, false);
+        Constant[] ys = constantValues(compare.getY(), merge, false);
         if (xs == null || ys == null) {
             return false;
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -165,9 +165,9 @@
         } else {
             graph().replaceFixed(this, node);
         }
-        call.safeDelete();
+        GraphUtil.killWithUnusedFloatingInputs(call);
         if (stateAfter.usages().isEmpty()) {
-            stateAfter.safeDelete();
+            GraphUtil.killWithUnusedFloatingInputs(stateAfter);
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -189,9 +189,9 @@
         } else {
             graph().replaceSplit(this, node, next());
         }
-        call.safeDelete();
+        GraphUtil.killWithUnusedFloatingInputs(call);
         if (state.usages().isEmpty()) {
-            state.safeDelete();
+            GraphUtil.killWithUnusedFloatingInputs(state);
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -40,7 +40,7 @@
 
     /**
      * Returns a node for a boolean constant.
-     * 
+     *
      * @param v the boolean value for which to create the instruction
      * @param graph
      * @return a node representing the boolean
@@ -50,6 +50,16 @@
     }
 
     /**
+     * Returns a node for a boolean constant.
+     *
+     * @param v the boolean value for which to create the instruction
+     * @return a node representing the boolean
+     */
+    public static LogicConstantNode forBoolean(boolean v) {
+        return new LogicConstantNode(v);
+    }
+
+    /**
      * Gets a constant for {@code true}.
      */
     public static LogicConstantNode tautology(Graph graph) {
@@ -63,6 +73,20 @@
         return forBoolean(false, graph);
     }
 
+    /**
+     * Gets a constant for {@code true}.
+     */
+    public static LogicConstantNode tautology() {
+        return forBoolean(true);
+    }
+
+    /**
+     * Gets a constant for {@code false}.
+     */
+    public static LogicConstantNode contradiction() {
+        return forBoolean(false);
+    }
+
     public boolean getValue() {
         return value;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNegationNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNegationNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -28,22 +28,22 @@
 /**
  * Logic node that negates its argument.
  */
-public class LogicNegationNode extends LogicNode implements Canonicalizable {
+public class LogicNegationNode extends LogicNode implements Canonicalizable.Unary<LogicNode> {
 
-    @Input(InputType.Condition) private LogicNode input;
+    @Input(InputType.Condition) private LogicNode value;
 
-    public LogicNegationNode(LogicNode input) {
-        this.input = input;
+    public LogicNegationNode(LogicNode value) {
+        this.value = value;
     }
 
-    public LogicNode getInput() {
-        return input;
+    public LogicNode getValue() {
+        return value;
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (input instanceof LogicNegationNode) {
-            return ((LogicNegationNode) input).getInput();
+    public LogicNode canonical(CanonicalizerTool tool, LogicNode forValue) {
+        if (forValue instanceof LogicNegationNode) {
+            return ((LogicNegationNode) forValue).getValue();
         } else {
             return this;
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -29,6 +29,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
@@ -175,7 +176,8 @@
 
     @Override
     public void simplify(SimplifierTool tool) {
-        // nothing yet
+        removeDeadPhis();
+        canonicalizePhis(tool);
     }
 
     public boolean isLoopExit(BeginNode begin) {
@@ -209,19 +211,101 @@
      * alive. This allows the removal of dead phi loops.
      */
     public void removeDeadPhis() {
-        Set<PhiNode> alive = new HashSet<>();
-        for (PhiNode phi : phis()) {
-            NodePredicate isAlive = u -> !isPhiAtMerge(u) || alive.contains(u);
-            if (phi.usages().filter(isAlive).isNotEmpty()) {
-                alive.add(phi);
-                for (PhiNode keptAlive : phi.values().filter(PhiNode.class).filter(isAlive.negate())) {
-                    alive.add(keptAlive);
+        if (phis().isNotEmpty()) {
+            Set<PhiNode> alive = new HashSet<>();
+            for (PhiNode phi : phis()) {
+                NodePredicate isAlive = u -> !isPhiAtMerge(u) || alive.contains(u);
+                if (phi.usages().filter(isAlive).isNotEmpty()) {
+                    alive.add(phi);
+                    for (PhiNode keptAlive : phi.values().filter(PhiNode.class).filter(isAlive.negate())) {
+                        alive.add(keptAlive);
+                    }
+                }
+            }
+            for (PhiNode phi : phis().filter(((NodePredicate) alive::contains).negate()).snapshot()) {
+                phi.replaceAtUsages(null);
+                phi.safeDelete();
+            }
+        }
+    }
+
+    private static final int NO_INCREMENT = Integer.MIN_VALUE;
+
+    /**
+     * Returns an array with one entry for each input of the phi, which is either
+     * {@link #NO_INCREMENT} or the increment, i.e., the value by which the phi is incremented in
+     * the corresponding branch.
+     */
+    private static int[] getSelfIncrements(PhiNode phi) {
+        int[] selfIncrement = new int[phi.valueCount()];
+        for (int i = 0; i < phi.valueCount(); i++) {
+            ValueNode input = phi.valueAt(i);
+            long increment = NO_INCREMENT;
+            if (input != null && input instanceof IntegerAddNode) {
+                IntegerAddNode add = (IntegerAddNode) input;
+                if (add.getX() == phi && add.getY().isConstant()) {
+                    increment = add.getY().asConstant().asLong();
+                } else if (add.getY() == phi && add.getX().isConstant()) {
+                    increment = add.getX().asConstant().asLong();
+                }
+            } else if (input == phi) {
+                increment = 0;
+            }
+            if (increment < Integer.MIN_VALUE || increment > Integer.MAX_VALUE || increment == NO_INCREMENT) {
+                increment = NO_INCREMENT;
+            }
+            selfIncrement[i] = (int) increment;
+        }
+        return selfIncrement;
+    }
+
+    /**
+     * Coalesces loop phis that represent the same value (which is not handled by normal Global
+     * Value Numbering).
+     */
+    public void canonicalizePhis(SimplifierTool tool) {
+        int phiCount = phis().count();
+        if (phiCount > 1) {
+            int phiInputCount = phiPredecessorCount();
+            int phiIndex = 0;
+            int[][] selfIncrement = new int[phiCount][];
+            PhiNode[] phis = this.phis().snapshot().toArray(new PhiNode[phiCount]);
+
+            for (phiIndex = 0; phiIndex < phiCount; phiIndex++) {
+                PhiNode phi = phis[phiIndex];
+                if (phi != null) {
+                    nextPhi: for (int otherPhiIndex = phiIndex + 1; otherPhiIndex < phiCount; otherPhiIndex++) {
+                        PhiNode otherPhi = phis[otherPhiIndex];
+                        if (otherPhi == null || phi.getNodeClass() != otherPhi.getNodeClass() || !phi.getNodeClass().valueEqual(phi, otherPhi)) {
+                            continue nextPhi;
+                        }
+                        if (selfIncrement[phiIndex] == null) {
+                            selfIncrement[phiIndex] = getSelfIncrements(phi);
+                        }
+                        if (selfIncrement[otherPhiIndex] == null) {
+                            selfIncrement[otherPhiIndex] = getSelfIncrements(otherPhi);
+                        }
+                        int[] phiIncrement = selfIncrement[phiIndex];
+                        int[] otherPhiIncrement = selfIncrement[otherPhiIndex];
+                        for (int inputIndex = 0; inputIndex < phiInputCount; inputIndex++) {
+                            if (phiIncrement[inputIndex] == NO_INCREMENT) {
+                                if (phi.valueAt(inputIndex) != otherPhi.valueAt(inputIndex)) {
+                                    continue nextPhi;
+                                }
+                            }
+                            if (phiIncrement[inputIndex] != otherPhiIncrement[inputIndex]) {
+                                continue nextPhi;
+                            }
+                        }
+                        if (tool != null) {
+                            tool.addToWorkList(otherPhi.usages());
+                        }
+                        otherPhi.replaceAtUsages(phi);
+                        GraphUtil.killWithUnusedFloatingInputs(otherPhi);
+                        phis[otherPhiIndex] = null;
+                    }
                 }
             }
         }
-        for (PhiNode phi : phis().filter(((NodePredicate) alive::contains).negate()).snapshot()) {
-            phi.replaceAtUsages(null);
-            phi.safeDelete();
-        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMap.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * Maps a {@linkplain LocationIdentity location} to the last node that (potentially) wrote to the
+ * location.
+ */
+public interface MemoryMap {
+
+    /**
+     * Gets the last node that that (potentially) wrote to {@code locationIdentity}.
+     */
+    MemoryNode getLastLocationAccess(LocationIdentity locationIdentity);
+
+    /**
+     * Gets the location identities in the domain of this map.
+     */
+    Collection<LocationIdentity> getLocations();
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes;
 
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -29,17 +31,68 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Extension})
-public abstract class MemoryMapNode extends FloatingNode {
+public class MemoryMapNode extends FloatingNode implements MemoryMap, LIRLowerable {
+
+    private final List<LocationIdentity> locationIdentities;
+    @Input(InputType.Memory) private final NodeInputList<ValueNode> nodes;
 
-    public MemoryMapNode() {
+    private boolean checkOrder(Map<LocationIdentity, MemoryNode> mmap) {
+        for (int i = 0; i < locationIdentities.size(); i++) {
+            LocationIdentity locationIdentity = locationIdentities.get(i);
+            ValueNode n = nodes.get(i);
+            assertTrue(mmap.get(locationIdentity) == n, "iteration order of keys differs from values in input map");
+        }
+        return true;
+    }
+
+    public MemoryMapNode(Map<LocationIdentity, MemoryNode> mmap) {
         super(StampFactory.forVoid());
+        locationIdentities = new ArrayList<>(mmap.keySet());
+        nodes = new NodeInputList<>(this, mmap.values());
+        assert checkOrder(mmap);
     }
 
-    public abstract MemoryNode getLastLocationAccess(LocationIdentity locationIdentity);
+    public boolean isEmpty() {
+        if (locationIdentities.isEmpty()) {
+            return true;
+        }
+        if (locationIdentities.size() == 1) {
+            if (nodes.get(0) instanceof StartNode) {
+                return true;
+            }
+        }
+        return false;
+    }
 
-    public abstract Set<LocationIdentity> getLocations();
+    public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) {
+        if (locationIdentity == FINAL_LOCATION) {
+            return null;
+        } else {
+            int index = locationIdentities.indexOf(locationIdentity);
+            if (index == -1) {
+                index = locationIdentities.indexOf(ANY_LOCATION);
+            }
+            assert index != -1;
+            return (MemoryNode) nodes.get(index);
+        }
+    }
 
-    public abstract boolean replaceLastLocationAccess(MemoryNode oldNode, MemoryNode newNode);
+    public Collection<LocationIdentity> getLocations() {
+        return locationIdentities;
+    }
+
+    public Map<LocationIdentity, MemoryNode> toMap() {
+        HashMap<LocationIdentity, MemoryNode> res = new HashMap<>(locationIdentities.size());
+        for (int i = 0; i < nodes.size(); i++) {
+            res.put(locationIdentities.get(i), (MemoryNode) nodes.get(i));
+        }
+        return res;
+    }
+
+    public void generate(NodeLIRBuilderTool generator) {
+        // nothing to do...
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -158,14 +158,19 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public void simplify(SimplifierTool tool) {
         ValueNode singleValue = singleValue();
 
         if (singleValue != null) {
-            return singleValue;
+            for (Node node : usages().snapshot()) {
+                if (node instanceof ProxyNode && ((ProxyNode) node).proxyPoint() instanceof LoopExitNode && ((LoopExitNode) ((ProxyNode) node).proxyPoint()).loopBegin() == merge) {
+                    tool.addToWorkList(node.usages());
+                    graph().replaceFloating((FloatingNode) node, singleValue);
+                }
+            }
+            graph().replaceFloating(this, singleValue);
+            usages().forEach(tool::addToWorkList);
         }
-
-        return this;
     }
 
     public ValueNode firstValue() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitOrNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitOrNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -25,7 +25,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 
-public class ShortCircuitOrNode extends LogicNode implements IterableNodeType, Canonicalizable {
+public class ShortCircuitOrNode extends LogicNode implements IterableNodeType, Canonicalizable.Binary<LogicNode> {
 
     @Input(InputType.Condition) private LogicNode x;
     @Input(InputType.Condition) private LogicNode y;
@@ -65,36 +65,35 @@
         return shortCircuitProbability;
     }
 
-    protected ShortCircuitOrNode canonicalizeNegation() {
-        LogicNode xCond = x;
+    protected ShortCircuitOrNode canonicalizeNegation(LogicNode forX, LogicNode forY) {
+        LogicNode xCond = forX;
         boolean xNeg = xNegated;
         while (xCond instanceof LogicNegationNode) {
-            xCond = ((LogicNegationNode) xCond).getInput();
+            xCond = ((LogicNegationNode) xCond).getValue();
             xNeg = !xNeg;
         }
 
-        LogicNode yCond = y;
+        LogicNode yCond = forY;
         boolean yNeg = yNegated;
         while (yCond instanceof LogicNegationNode) {
-            yCond = ((LogicNegationNode) yCond).getInput();
+            yCond = ((LogicNegationNode) yCond).getValue();
             yNeg = !yNeg;
         }
 
-        if (xCond != x || yCond != y) {
-            return graph().unique(new ShortCircuitOrNode(xCond, xNeg, yCond, yNeg, shortCircuitProbability));
+        if (xCond != forX || yCond != forY) {
+            return new ShortCircuitOrNode(xCond, xNeg, yCond, yNeg, shortCircuitProbability);
         } else {
-            return null;
+            return this;
         }
     }
 
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ShortCircuitOrNode ret = canonicalizeNegation();
-        if (ret != null) {
+    public LogicNode canonical(CanonicalizerTool tool, LogicNode forX, LogicNode forY) {
+        ShortCircuitOrNode ret = canonicalizeNegation(forX, forY);
+        if (ret != this) {
             return ret;
         }
 
-        if (getX() == getY()) {
+        if (forX == forY) {
             // @formatter:off
             //  a ||  a = a
             //  a || !a = true
@@ -104,40 +103,40 @@
             if (isXNegated()) {
                 if (isYNegated()) {
                     // !a || !a = !a
-                    return graph().unique(new LogicNegationNode(getX()));
+                    return new LogicNegationNode(forX);
                 } else {
                     // !a || a = true
-                    return LogicConstantNode.tautology(graph());
+                    return LogicConstantNode.tautology();
                 }
             } else {
                 if (isYNegated()) {
                     // a || !a = true
-                    return LogicConstantNode.tautology(graph());
+                    return LogicConstantNode.tautology();
                 } else {
                     // a || a = a
-                    return getX();
+                    return forX;
                 }
             }
         }
-        if (getX() instanceof LogicConstantNode) {
-            if (((LogicConstantNode) getX()).getValue() ^ isXNegated()) {
-                return LogicConstantNode.tautology(graph());
+        if (forX instanceof LogicConstantNode) {
+            if (((LogicConstantNode) forX).getValue() ^ isXNegated()) {
+                return LogicConstantNode.tautology();
             } else {
                 if (isYNegated()) {
-                    return graph().unique(new LogicNegationNode(getY()));
+                    return new LogicNegationNode(forY);
                 } else {
-                    return getY();
+                    return forY;
                 }
             }
         }
-        if (getY() instanceof LogicConstantNode) {
-            if (((LogicConstantNode) getY()).getValue() ^ isYNegated()) {
-                return LogicConstantNode.tautology(graph());
+        if (forY instanceof LogicConstantNode) {
+            if (((LogicConstantNode) forY).getValue() ^ isYNegated()) {
+                return LogicConstantNode.tautology();
             } else {
                 if (isXNegated()) {
-                    return graph().unique(new LogicNegationNode(getX()));
+                    return new LogicNegationNode(forX);
                 } else {
-                    return getX();
+                    return forX;
                 }
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -35,18 +35,16 @@
 /**
  * A node that attaches a type profile to a proxied input node.
  */
-public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, IterableNodeType, ValueProxy {
+public final class TypeProfileProxyNode extends UnaryNode implements IterableNodeType, ValueProxy {
 
-    @Input private ValueNode object;
     private final JavaTypeProfile profile;
     private transient ResolvedJavaType lastCheckedType;
     private transient JavaTypeProfile lastCheckedProfile;
 
-    public ValueNode getObject() {
-        return object;
-    }
-
     public static ValueNode create(ValueNode object, JavaTypeProfile profile) {
+        if (StampTool.isExactType(object)) {
+            return object;
+        }
         if (profile == null) {
             // No profile, so create no node.
             return object;
@@ -58,9 +56,8 @@
         return object.graph().addWithoutUnique(new TypeProfileProxyNode(object, profile));
     }
 
-    private TypeProfileProxyNode(ValueNode object, JavaTypeProfile profile) {
-        super(object.stamp());
-        this.object = object;
+    private TypeProfileProxyNode(ValueNode value, JavaTypeProfile profile) {
+        super(value.stamp(), value);
         this.profile = profile;
     }
 
@@ -70,16 +67,16 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(object.stamp());
+        return updateStamp(getValue().stamp());
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (StampTool.isExactType(object)) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (StampTool.isExactType(forValue)) {
             // The profile is useless - we know the type!
-            return object;
-        } else if (object instanceof TypeProfileProxyNode) {
-            TypeProfileProxyNode other = (TypeProfileProxyNode) object;
+            return forValue;
+        } else if (forValue instanceof TypeProfileProxyNode) {
+            TypeProfileProxyNode other = (TypeProfileProxyNode) forValue;
             JavaTypeProfile otherProfile = other.getProfile();
             if (otherProfile == lastCheckedProfile) {
                 // We have already incorporated the knowledge about this profile => abort.
@@ -90,33 +87,33 @@
             if (newProfile.equals(otherProfile)) {
                 // We are useless - just use the other proxy node.
                 Debug.log("Canonicalize with other proxy node.");
-                return object;
+                return forValue;
             }
             if (newProfile != this.profile) {
                 Debug.log("Improved profile via other profile.");
-                return TypeProfileProxyNode.create(object, newProfile);
+                return new TypeProfileProxyNode(forValue, newProfile);
             }
-        } else if (StampTool.typeOrNull(object) != null) {
-            ResolvedJavaType type = StampTool.typeOrNull(object);
+        } else if (StampTool.typeOrNull(forValue) != null) {
+            ResolvedJavaType type = StampTool.typeOrNull(forValue);
             ResolvedJavaType uniqueConcrete = type.findUniqueConcreteSubtype();
             if (uniqueConcrete != null) {
                 // Profile is useless => remove.
                 Debug.log("Profile useless, there is enough static type information available.");
-                return object;
+                return forValue;
             }
             if (Objects.equals(type, lastCheckedType)) {
                 // We have already incorporate the knowledge about this type => abort.
                 return this;
             }
             lastCheckedType = type;
-            JavaTypeProfile newProfile = this.profile.restrict(type, StampTool.isObjectNonNull(object));
+            JavaTypeProfile newProfile = this.profile.restrict(type, StampTool.isObjectNonNull(forValue));
             if (newProfile != this.profile) {
                 Debug.log("Improved profile via static type information.");
                 if (newProfile.getTypes().length == 0) {
                     // Only null profiling is not beneficial enough to keep the node around.
-                    return object;
+                    return forValue;
                 }
-                return TypeProfileProxyNode.create(object, newProfile);
+                return new TypeProfileProxyNode(forValue, newProfile);
             }
         }
         return this;
@@ -124,6 +121,6 @@
 
     @Override
     public ValueNode getOriginalNode() {
-        return object;
+        return getValue();
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -22,29 +22,22 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.spi.*;
 
-public abstract class UnaryOpLogicNode extends LogicNode implements LIRLowerable {
+public abstract class UnaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable.Unary<ValueNode> {
 
-    @Input private ValueNode object;
+    @Input private ValueNode value;
 
-    public ValueNode object() {
-        return object;
+    public ValueNode getValue() {
+        return value;
     }
 
-    protected void setX(ValueNode object) {
-        updateUsages(this.object, object);
-        this.object = object;
+    public UnaryOpLogicNode(ValueNode value) {
+        assert value != null;
+        this.value = value;
     }
 
-    public UnaryOpLogicNode(ValueNode object) {
-        assert object != null;
-        this.object = object;
-    }
-
-    public abstract TriState evaluate(ValueNode forObject);
-
     @Override
     public void generate(NodeLIRBuilderTool gen) {
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,9 +32,9 @@
  * variable.
  */
 @NodeInfo(nameTemplate = "ValuePhi({i#values})")
-public class ValuePhiNode extends PhiNode implements Canonicalizable {
+public class ValuePhiNode extends PhiNode implements Simplifiable {
 
-    @Input final NodeInputList<ValueNode> values = new NodeInputList<>(this);
+    @Input final NodeInputList<ValueNode> values;
 
     /**
      * Create a value phi with the specified stamp.
@@ -45,6 +45,20 @@
     public ValuePhiNode(Stamp stamp, MergeNode merge) {
         super(stamp, merge);
         assert stamp != StampFactory.forVoid();
+        values = new NodeInputList<>(this);
+    }
+
+    /**
+     * Create a value phi with the specified stamp and the given values.
+     *
+     * @param stamp the stamp of the value
+     * @param merge the merge that the new phi belongs to
+     * @param values the initial values of the phi
+     */
+    public ValuePhiNode(Stamp stamp, MergeNode merge, ValueNode[] values) {
+        super(stamp, merge);
+        assert stamp != StampFactory.forVoid();
+        this.values = new NodeInputList<>(this, values);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,17 +30,19 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "&")
-public final class AndNode extends BitLogicNode implements Canonicalizable, NarrowableArithmeticNode {
+public final class AndNode extends BitLogicNode implements NarrowableArithmeticNode {
 
-    public AndNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+    public AndNode(ValueNode x, ValueNode y) {
+        super(StampTool.and(x.stamp(), y.stamp()), x, y);
+        assert x.stamp().isCompatible(y.stamp());
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.and(x().stamp(), y().stamp()));
+        return updateStamp(StampTool.and(getX().stamp(), getY().stamp()));
     }
 
     @Override
@@ -50,46 +52,45 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return x();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return forX;
         }
-        if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new AndNode(stamp(), y(), x()));
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new AndNode(forY, forX);
         }
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(stamp(), evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            long rawY = y().asConstant().asLong();
+        if (forX.isConstant()) {
+            return ConstantNode.forPrimitive(stamp(), evalConst(forX.asConstant(), forY.asConstant()));
+        } else if (forY.isConstant()) {
+            long rawY = forY.asConstant().asLong();
             long mask = IntegerStamp.defaultMask(PrimitiveStamp.getBits(stamp()));
             if ((rawY & mask) == mask) {
-                return x();
+                return forX;
             }
             if ((rawY & mask) == 0) {
-                return ConstantNode.forIntegerStamp(stamp(), 0, graph());
+                return ConstantNode.forIntegerStamp(stamp(), 0);
             }
-            if (x() instanceof SignExtendNode) {
-                SignExtendNode ext = (SignExtendNode) x();
+            if (forX instanceof SignExtendNode) {
+                SignExtendNode ext = (SignExtendNode) forX;
                 if (rawY == ((1L << ext.getInputBits()) - 1)) {
-                    ValueNode result = graph().unique(new ZeroExtendNode(ext.getInput(), ext.getResultBits()));
-                    return result;
+                    return new ZeroExtendNode(ext.getValue(), ext.getResultBits());
                 }
             }
-            if (x().stamp() instanceof IntegerStamp) {
-                IntegerStamp xStamp = (IntegerStamp) x().stamp();
+            if (forX.stamp() instanceof IntegerStamp) {
+                IntegerStamp xStamp = (IntegerStamp) forX.stamp();
                 if (((xStamp.upMask() | xStamp.downMask()) & ~rawY) == 0) {
                     // No bits are set which are outside the mask, so the mask will have no effect.
-                    return x();
+                    return forX;
                 }
             }
 
-            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
+            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitAnd(builder.operand(x()), builder.operand(y())));
+        builder.setResult(this, gen.emitAnd(builder.operand(getX()), builder.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,21 +25,22 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * The {@code BinaryNode} class is the base of arithmetic and logic operations with two inputs.
  */
-public abstract class BinaryNode extends FloatingNode {
+public abstract class BinaryNode extends FloatingNode implements Canonicalizable.Binary<ValueNode> {
 
     @Input private ValueNode x;
     @Input private ValueNode y;
 
-    public ValueNode x() {
+    public ValueNode getX() {
         return x;
     }
 
-    public ValueNode y() {
+    public ValueNode getY() {
         return y;
     }
 
@@ -63,9 +64,9 @@
         public ValueNode getValue(BinaryNode binary) {
             switch (this) {
                 case x:
-                    return binary.x();
+                    return binary.getX();
                 case y:
-                    return binary.y();
+                    return binary.getY();
                 default:
                     throw GraalInternalError.shouldNotReachHere();
             }
@@ -74,9 +75,9 @@
         public ValueNode getOtherValue(BinaryNode binary) {
             switch (this) {
                 case x:
-                    return binary.y();
+                    return binary.getY();
                 case y:
-                    return binary.x();
+                    return binary.getX();
                 default:
                     throw GraalInternalError.shouldNotReachHere();
             }
@@ -89,7 +90,7 @@
         if (stamp instanceof IntegerStamp) {
             return IntegerArithmeticNode.add(graph, x, y);
         } else if (stamp instanceof FloatStamp) {
-            return graph.unique(new FloatAddNode(stamp, x, y, false));
+            return graph.unique(new FloatAddNode(x, y, false));
         } else {
             throw GraalInternalError.shouldNotReachHere();
         }
@@ -101,7 +102,7 @@
         if (stamp instanceof IntegerStamp) {
             return IntegerArithmeticNode.sub(graph, x, y);
         } else if (stamp instanceof FloatStamp) {
-            return graph.unique(new FloatSubNode(stamp, x, y, false));
+            return graph.unique(new FloatSubNode(x, y, false));
         } else {
             throw GraalInternalError.shouldNotReachHere();
         }
@@ -113,7 +114,7 @@
         if (stamp instanceof IntegerStamp) {
             return IntegerArithmeticNode.mul(graph, x, y);
         } else if (stamp instanceof FloatStamp) {
-            return graph.unique(new FloatMulNode(stamp, x, y, false));
+            return graph.unique(new FloatMulNode(x, y, false));
         } else {
             throw GraalInternalError.shouldNotReachHere();
         }
@@ -124,8 +125,8 @@
     }
 
     public static ReassociateMatch findReassociate(BinaryNode binary, NodePredicate criterion) {
-        boolean resultX = criterion.apply(binary.x());
-        boolean resultY = criterion.apply(binary.y());
+        boolean resultX = criterion.apply(binary.getX());
+        boolean resultY = criterion.apply(binary.getY());
         if (resultX && !resultY) {
             return ReassociateMatch.x;
         }
@@ -157,8 +158,11 @@
      * <p>
      * This method accepts only {@linkplain #canTryReassociate(BinaryNode) reassociable} operations
      * such as +, -, *, &amp;, | and ^
+     *
+     * @param forY
+     * @param forX
      */
-    public static BinaryNode reassociate(BinaryNode node, NodePredicate criterion) {
+    public static BinaryNode reassociate(BinaryNode node, NodePredicate criterion, ValueNode forX, ValueNode forY) {
         assert canTryReassociate(node);
         ReassociateMatch match1 = findReassociate(node, criterion);
         if (match1 == null) {
@@ -203,29 +207,28 @@
         ValueNode a = match2.getOtherValue(other);
         if (node instanceof IntegerAddNode || node instanceof IntegerSubNode) {
             BinaryNode associated;
-            StructuredGraph graph = node.graph();
             if (invertM1) {
-                associated = IntegerArithmeticNode.sub(graph, m2, m1);
+                associated = IntegerArithmeticNode.sub(m2, m1);
             } else if (invertM2) {
-                associated = IntegerArithmeticNode.sub(graph, m1, m2);
+                associated = IntegerArithmeticNode.sub(m1, m2);
             } else {
-                associated = IntegerArithmeticNode.add(graph, m1, m2);
+                associated = IntegerArithmeticNode.add(m1, m2);
             }
             if (invertA) {
-                return IntegerArithmeticNode.sub(graph, associated, a);
+                return IntegerArithmeticNode.sub(associated, a);
             }
             if (aSub) {
-                return IntegerArithmeticNode.sub(graph, a, associated);
+                return IntegerArithmeticNode.sub(a, associated);
             }
-            return IntegerArithmeticNode.add(graph, a, associated);
+            return IntegerArithmeticNode.add(a, associated);
         } else if (node instanceof IntegerMulNode) {
-            return IntegerArithmeticNode.mul(node.graph(), a, IntegerAddNode.mul(node.graph(), m1, m2));
+            return IntegerArithmeticNode.mul(a, IntegerAddNode.mul(m1, m2));
         } else if (node instanceof AndNode) {
-            return BitLogicNode.and(node.graph(), a, BitLogicNode.and(node.graph(), m1, m2));
+            return BitLogicNode.and(a, BitLogicNode.and(m1, m2));
         } else if (node instanceof OrNode) {
-            return BitLogicNode.or(node.graph(), a, BitLogicNode.or(node.graph(), m1, m2));
+            return BitLogicNode.or(a, BitLogicNode.or(m1, m2));
         } else if (node instanceof XorNode) {
-            return BitLogicNode.xor(node.graph(), a, BitLogicNode.xor(node.graph(), m1, m2));
+            return BitLogicNode.xor(a, BitLogicNode.xor(m1, m2));
         } else {
             throw GraalInternalError.shouldNotReachHere();
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code LogicNode} class definition.
@@ -34,7 +33,7 @@
 
     /**
      * Constructs a new logic operation node.
-     * 
+     *
      * @param x the first input into this node
      * @param y the second input into this node
      */
@@ -44,17 +43,26 @@
     }
 
     public static BitLogicNode and(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        assert v1.stamp().isCompatible(v2.stamp());
-        return graph.unique(new AndNode(StampTool.and(v1.stamp(), v2.stamp()), v1, v2));
+        return graph.unique(new AndNode(v1, v2));
+    }
+
+    public static BitLogicNode and(ValueNode v1, ValueNode v2) {
+        return new AndNode(v1, v2);
     }
 
     public static BitLogicNode or(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        assert v1.stamp().isCompatible(v2.stamp());
-        return graph.unique(new OrNode(StampTool.or(v1.stamp(), v2.stamp()), v1, v2));
+        return graph.unique(new OrNode(v1, v2));
+    }
+
+    public static BitLogicNode or(ValueNode v1, ValueNode v2) {
+        return new OrNode(v1, v2);
     }
 
     public static BitLogicNode xor(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        assert v1.stamp().isCompatible(v2.stamp());
-        return graph.unique(new XorNode(StampTool.xor(v1.stamp(), v2.stamp()), v1, v2));
+        return graph.unique(new XorNode(v1, v2));
+    }
+
+    public static BitLogicNode xor(ValueNode v1, ValueNode v2) {
+        return new XorNode(v1, v2);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,10 +23,8 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 
@@ -62,7 +60,7 @@
      */
     public abstract boolean unorderedIsTrue();
 
-    private LogicNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond) {
+    private ValueNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond) {
         Constant trueConstant = conditionalNode.trueValue().asConstant();
         Constant falseConstant = conditionalNode.falseValue().asConstant();
 
@@ -71,14 +69,14 @@
             boolean falseResult = cond.foldCondition(falseConstant, constant, constantReflection, unorderedIsTrue());
 
             if (trueResult == falseResult) {
-                return LogicConstantNode.forBoolean(trueResult, graph());
+                return LogicConstantNode.forBoolean(trueResult);
             } else {
                 if (trueResult) {
                     assert falseResult == false;
                     return conditionalNode.condition();
                 } else {
                     assert falseResult == true;
-                    return graph().unique(new LogicNegationNode(conditionalNode.condition()));
+                    return new LogicNegationNode(conditionalNode.condition());
 
                 }
             }
@@ -86,60 +84,49 @@
         return this;
     }
 
-    protected LogicNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+    protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
         throw new GraalInternalError("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored);
     }
 
     @Override
-    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         if (forX.isConstant() && forY.isConstant()) {
-            return TriState.get(condition().foldCondition(forX.asConstant(), forY.asConstant(), constantReflection, unorderedIsTrue()));
+            return LogicConstantNode.forBoolean(condition().foldCondition(forX.asConstant(), forY.asConstant(), tool.getConstantReflection(), unorderedIsTrue()));
         }
-        return TriState.UNKNOWN;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        Node result = super.canonical(tool);
-        if (result != this) {
-            return result;
-        }
-        if (x().isConstant()) {
-            if ((result = canonicalizeSymmetricConstant(tool, x().asConstant(), y(), true)) != this) {
+        ValueNode result;
+        if (forX.isConstant()) {
+            if ((result = canonicalizeSymmetricConstant(tool, forX.asConstant(), forY, true)) != this) {
                 return result;
             }
-        } else if (y().isConstant()) {
-            if ((result = canonicalizeSymmetricConstant(tool, y().asConstant(), x(), false)) != this) {
+        } else if (forY.isConstant()) {
+            if ((result = canonicalizeSymmetricConstant(tool, forY.asConstant(), forX, false)) != this) {
                 return result;
             }
-        } else if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
-            ConvertNode convertX = (ConvertNode) x();
-            ConvertNode convertY = (ConvertNode) y();
-            if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) {
-                return graph().unique(duplicateModified(convertX.getInput(), convertY.getInput()));
+        } else if (forX instanceof ConvertNode && forY instanceof ConvertNode) {
+            ConvertNode convertX = (ConvertNode) forX;
+            ConvertNode convertY = (ConvertNode) forY;
+            if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getValue().stamp().isCompatible(convertY.getValue().stamp())) {
+                return duplicateModified(convertX.getValue(), convertY.getValue());
             }
-
         }
         return this;
     }
 
     protected abstract CompareNode duplicateModified(ValueNode newX, ValueNode newY);
 
-    protected Node canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
-        if (nonConstant instanceof BinaryNode) {
-            if (nonConstant instanceof ConditionalNode) {
-                return optimizeConditional(constant, (ConditionalNode) nonConstant, tool.getConstantReflection(), mirrored ? condition().mirror() : condition());
-            } else if (nonConstant instanceof NormalizeCompareNode) {
-                return optimizeNormalizeCmp(constant, (NormalizeCompareNode) nonConstant, mirrored);
-            }
+    protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
+        if (nonConstant instanceof ConditionalNode) {
+            return optimizeConditional(constant, (ConditionalNode) nonConstant, tool.getConstantReflection(), mirrored ? condition().mirror() : condition());
+        } else if (nonConstant instanceof NormalizeCompareNode) {
+            return optimizeNormalizeCmp(constant, (NormalizeCompareNode) nonConstant, mirrored);
         } else if (nonConstant instanceof ConvertNode) {
             ConvertNode convert = (ConvertNode) nonConstant;
             ConstantNode newConstant = canonicalConvertConstant(tool, convert, constant);
             if (newConstant != null) {
                 if (mirrored) {
-                    return graph().unique(duplicateModified(newConstant, convert.getInput()));
+                    return duplicateModified(newConstant, convert.getValue());
                 } else {
-                    return graph().unique(duplicateModified(convert.getInput(), newConstant));
+                    return duplicateModified(convert.getValue(), newConstant);
                 }
             }
         }
@@ -150,13 +137,17 @@
         if (convert.preservesOrder(condition())) {
             Constant reverseConverted = convert.reverse(constant);
             if (convert.convert(reverseConverted).equals(constant)) {
-                return ConstantNode.forConstant(convert.getInput().stamp(), reverseConverted, tool.getMetaAccess(), convert.graph());
+                return ConstantNode.forConstant(convert.getValue().stamp(), reverseConverted, tool.getMetaAccess());
             }
         }
         return null;
     }
 
     public static CompareNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
+        return graph.unique(createCompareNode(condition, x, y));
+    }
+
+    public static CompareNode createCompareNode(Condition condition, ValueNode x, ValueNode y) {
         assert x.getKind() == y.getKind();
         assert condition.isCanonical() : "condition is not canonical: " + condition;
         assert !x.getKind().isNumericFloat();
@@ -178,6 +169,6 @@
             comparison = new IntegerBelowThanNode(x, y);
         }
 
-        return graph.unique(comparison);
+        return comparison;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -37,9 +37,11 @@
  * The {@code ConditionalNode} class represents a comparison that yields one of two values. Note
  * that these nodes are not built directly from the bytecode but are introduced by canonicalization.
  */
-public final class ConditionalNode extends BinaryNode implements Canonicalizable, LIRLowerable {
+public final class ConditionalNode extends FloatingNode implements Canonicalizable, LIRLowerable {
 
     @Input(InputType.Condition) private LogicNode condition;
+    @Input private ValueNode trueValue;
+    @Input private ValueNode falseValue;
 
     public LogicNode condition() {
         return condition;
@@ -50,39 +52,41 @@
     }
 
     public ConditionalNode(LogicNode condition, ValueNode trueValue, ValueNode falseValue) {
-        super(trueValue.stamp().meet(falseValue.stamp()), trueValue, falseValue);
+        super(trueValue.stamp().meet(falseValue.stamp()));
         assert trueValue.stamp().isCompatible(falseValue.stamp());
         this.condition = condition;
+        this.trueValue = trueValue;
+        this.falseValue = falseValue;
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(x().stamp().meet(y().stamp()));
+        return updateStamp(trueValue.stamp().meet(falseValue.stamp()));
     }
 
     public ValueNode trueValue() {
-        return x();
+        return trueValue;
     }
 
     public ValueNode falseValue() {
-        return y();
+        return falseValue;
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public ValueNode canonical(CanonicalizerTool tool) {
         if (condition instanceof LogicNegationNode) {
             LogicNegationNode negated = (LogicNegationNode) condition;
-            return graph().unique(new ConditionalNode(negated.getInput(), falseValue(), trueValue()));
+            return new ConditionalNode(negated.getValue(), falseValue(), trueValue());
         }
 
         // this optimizes the case where a value that can only be 0 or 1 is materialized to 0 or 1
-        if (x().isConstant() && y().isConstant() && condition instanceof IntegerEqualsNode) {
+        if (trueValue().isConstant() && falseValue().isConstant() && condition instanceof IntegerEqualsNode) {
             IntegerEqualsNode equals = (IntegerEqualsNode) condition;
-            if (equals.y().isConstant() && equals.y().asConstant().equals(Constant.INT_0) && equals.x().stamp() instanceof IntegerStamp) {
-                IntegerStamp equalsXStamp = (IntegerStamp) equals.x().stamp();
+            if (equals.getY().isConstant() && equals.getY().asConstant().equals(Constant.INT_0) && equals.getX().stamp() instanceof IntegerStamp) {
+                IntegerStamp equalsXStamp = (IntegerStamp) equals.getX().stamp();
                 if (equalsXStamp.upMask() == 1) {
-                    if (x().asConstant().equals(Constant.INT_0) && y().asConstant().equals(Constant.INT_1)) {
-                        return IntegerConvertNode.convertUnsigned(equals.x(), stamp());
+                    if (trueValue().asConstant().equals(Constant.INT_0) && falseValue().asConstant().equals(Constant.INT_1)) {
+                        return IntegerConvertNode.convertUnsigned(equals.getX(), stamp());
                     }
                 }
             }
@@ -98,7 +102,7 @@
         if (condition instanceof CompareNode && ((CompareNode) condition).condition() == Condition.EQ) {
             // optimize the pattern (x == y) ? x : y
             CompareNode compare = (CompareNode) condition;
-            if ((compare.x() == trueValue() && compare.y() == falseValue()) || (compare.x() == falseValue() && compare.y() == trueValue())) {
+            if ((compare.getX() == trueValue() && compare.getY() == falseValue()) || (compare.getX() == falseValue() && compare.getY() == trueValue())) {
                 return falseValue();
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,17 +31,10 @@
 /**
  * Represents a conversion between primitive types.
  */
-public abstract class ConvertNode extends FloatingNode implements ArithmeticOperation {
-
-    @Input private ValueNode input;
+public abstract class ConvertNode extends UnaryNode implements ArithmeticOperation {
 
-    protected ConvertNode(Stamp stamp, ValueNode input) {
-        super(stamp);
-        this.input = input;
-    }
-
-    public ValueNode getInput() {
-        return input;
+    protected ConvertNode(Stamp stamp, ValueNode value) {
+        super(stamp, value);
     }
 
     public abstract Constant convert(Constant c);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,24 +23,25 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 
-public abstract class FixedBinaryNode extends DeoptimizingFixedWithNextNode {
+public abstract class FixedBinaryNode extends DeoptimizingFixedWithNextNode implements Canonicalizable.Binary<ValueNode> {
 
     @Input private ValueNode x;
     @Input private ValueNode y;
 
-    public ValueNode x() {
-        return x;
-    }
-
-    public ValueNode y() {
-        return y;
-    }
-
     public FixedBinaryNode(Stamp stamp, ValueNode x, ValueNode y) {
         super(stamp);
         this.x = x;
         this.y = y;
     }
+
+    public ValueNode getX() {
+        return x;
+    }
+
+    public ValueNode getY() {
+        return y;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
@@ -31,10 +30,10 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "+")
-public final class FloatAddNode extends FloatArithmeticNode implements Canonicalizable {
+public final class FloatAddNode extends FloatArithmeticNode {
 
-    public FloatAddNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
-        super(stamp, x, y, isStrictFP);
+    public FloatAddNode(ValueNode x, ValueNode y, boolean isStrictFP) {
+        super(x.stamp().unrestricted(), x, y, isStrictFP);
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -49,26 +48,22 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new FloatAddNode(stamp(), y(), x(), isStrictFP()));
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new FloatAddNode(forY, forX, isStrictFP());
         }
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            Constant c = y().asConstant();
-            if ((c.getKind() == Kind.Float && c.asFloat() == 0.0f) || (c.getKind() == Kind.Double && c.asDouble() == 0.0)) {
-                return x();
-            }
+        if (forX.isConstant()) {
+            return ConstantNode.forConstant(evalConst(forX.asConstant(), forY.asConstant()), null);
         }
+        // Constant 0.0 can't be eliminated since it can affect the sign of the result.
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value op1 = builder.operand(x());
-        Value op2 = builder.operand(y());
-        if (!y().isConstant() && !livesLonger(this, y(), builder)) {
+        Value op1 = builder.operand(getX());
+        Value op2 = builder.operand(getY());
+        if (!getY().isConstant() && !livesLonger(this, getY(), builder)) {
             Value op = op1;
             op1 = op2;
             op2 = op;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -26,7 +26,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -36,7 +35,7 @@
  * A {@code FloatConvert} converts between integers and floating point numbers according to Java
  * semantics.
  */
-public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable {
+public class FloatConvertNode extends ConvertNode implements Lowerable, ArithmeticLIRLowerable {
 
     private final FloatConvert op;
 
@@ -95,7 +94,7 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(createStamp(op, getInput()));
+        return updateStamp(createStamp(op, getValue()));
     }
 
     private static Constant convert(FloatConvert op, Constant value) {
@@ -147,13 +146,13 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (getInput().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(getInput().asConstant()), graph());
-        } else if (getInput() instanceof FloatConvertNode) {
-            FloatConvertNode other = (FloatConvertNode) getInput();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forConstant(evalConst(forValue.asConstant()), null);
+        } else if (forValue instanceof FloatConvertNode) {
+            FloatConvertNode other = (FloatConvertNode) forValue;
             if (other.isLossless() && other.op == this.op.reverse()) {
-                return other.getInput();
+                return other.getValue();
             }
         }
         return this;
@@ -164,6 +163,6 @@
     }
 
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getInput())));
+        builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
@@ -31,10 +30,10 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "/")
-public final class FloatDivNode extends FloatArithmeticNode implements Canonicalizable {
+public final class FloatDivNode extends FloatArithmeticNode {
 
-    public FloatDivNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
-        super(stamp, x, y, isStrictFP);
+    public FloatDivNode(ValueNode x, ValueNode y, boolean isStrictFP) {
+        super(x.stamp().unrestricted(), x, y, isStrictFP);
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -49,15 +48,15 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitDiv(builder.operand(x()), builder.operand(y()), null));
+        builder.setResult(this, gen.emitDiv(builder.operand(getX()), builder.operand(getY()), null));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.util.*;
 
@@ -57,17 +56,21 @@
     }
 
     @Override
-    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = super.canonical(tool, forX, forY);
+        if (result != this) {
+            return result;
+        }
         if (forX.stamp() instanceof FloatStamp && forY.stamp() instanceof FloatStamp) {
             FloatStamp xStamp = (FloatStamp) forX.stamp();
             FloatStamp yStamp = (FloatStamp) forY.stamp();
             if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && xStamp.isNonNaN() && yStamp.isNonNaN()) {
-                return TriState.TRUE;
+                return LogicConstantNode.tautology();
             } else if (xStamp.alwaysDistinct(yStamp)) {
-                return TriState.FALSE;
+                return LogicConstantNode.contradiction();
             }
         }
-        return super.evaluate(constantReflection, forX, forY);
+        return this;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.util.*;
 
@@ -62,11 +61,15 @@
     }
 
     @Override
-    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = super.canonical(tool, forX, forY);
+        if (result != this) {
+            return result;
+        }
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && !unorderedIsTrue()) {
-            return TriState.FALSE;
+            return LogicConstantNode.contradiction();
         }
-        return super.evaluate(constantReflection, forX, forY);
+        return this;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
@@ -31,10 +30,10 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "*")
-public final class FloatMulNode extends FloatArithmeticNode implements Canonicalizable {
+public final class FloatMulNode extends FloatArithmeticNode {
 
-    public FloatMulNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
-        super(stamp, x, y, isStrictFP);
+    public FloatMulNode(ValueNode x, ValueNode y, boolean isStrictFP) {
+        super(x.stamp().unrestricted(), x, y, isStrictFP);
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -49,21 +48,21 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new FloatMulNode(stamp(), y(), x(), isStrictFP()));
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new FloatMulNode(forY, forX, isStrictFP());
         }
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+        if (forX.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value op1 = builder.operand(x());
-        Value op2 = builder.operand(y());
-        if (!y().isConstant() && !FloatAddNode.livesLonger(this, y(), builder)) {
+        Value op1 = builder.operand(getX());
+        Value op2 = builder.operand(getY());
+        if (!getY().isConstant() && !FloatAddNode.livesLonger(this, getY(), builder)) {
             Value op = op1;
             op1 = op2;
             op2 = op;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
@@ -31,10 +30,10 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "%")
-public class FloatRemNode extends FloatArithmeticNode implements Canonicalizable, Lowerable {
+public class FloatRemNode extends FloatArithmeticNode implements Lowerable {
 
-    public FloatRemNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
-        super(stamp, x, y, isStrictFP);
+    public FloatRemNode(ValueNode x, ValueNode y, boolean isStrictFP) {
+        super(x.stamp().unrestricted(), x, y, isStrictFP);
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -49,9 +48,9 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(getX().asConstant(), getY().asConstant()));
         }
         return this;
     }
@@ -63,6 +62,6 @@
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitRem(builder.operand(x()), builder.operand(y()), null));
+        builder.setResult(this, gen.emitRem(builder.operand(getX()), builder.operand(getY()), null));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,18 +23,18 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "-")
-public final class FloatSubNode extends FloatArithmeticNode implements Canonicalizable {
+public final class FloatSubNode extends FloatArithmeticNode {
 
-    public FloatSubNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
-        super(stamp, x, y, isStrictFP);
+    public FloatSubNode(ValueNode x, ValueNode y, boolean isStrictFP) {
+        super(x.stamp().unrestricted(), x, y, isStrictFP);
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -49,34 +49,19 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return ConstantNode.forFloatingStamp(stamp(), 0.0f, graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return ConstantNode.forFloatingStamp(stamp(), 0.0f);
         }
-        if (x().isConstant() && y().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            Constant c = y().asConstant();
-            if (c.getKind() == Kind.Float) {
-                float f = c.asFloat();
-                if (f == 0.0f) {
-                    return x();
-                }
-                return graph().unique(new FloatAddNode(stamp(), x(), ConstantNode.forFloat(-f, graph()), isStrictFP()));
-            } else {
-                assert c.getKind() == Kind.Double;
-                double d = c.asDouble();
-                if (d == 0.0) {
-                    return x();
-                }
-                return graph().unique(new FloatAddNode(stamp(), x(), ConstantNode.forDouble(-d, graph()), isStrictFP()));
-            }
+        if (forX.isConstant() && forY.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
         }
+        // Constant 0.0 can't be eliminated since it can affect the sign of the result.
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y())));
+        builder.setResult(this, gen.emitSub(builder.operand(getX()), builder.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -32,15 +32,15 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "+")
-public class IntegerAddNode extends IntegerArithmeticNode implements Canonicalizable, NarrowableArithmeticNode {
+public class IntegerAddNode extends IntegerArithmeticNode implements NarrowableArithmeticNode {
 
-    public IntegerAddNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+    public IntegerAddNode(ValueNode x, ValueNode y) {
+        super(StampTool.add(x.stamp(), y.stamp()), x, y);
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.add(x().stamp(), y().stamp()));
+        return updateStamp(StampTool.add(getX().stamp(), getY().stamp()));
     }
 
     @Override
@@ -50,51 +50,51 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new IntegerAddNode(stamp(), y(), x()));
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new IntegerAddNode(forY, forX);
         }
-        if (x() instanceof IntegerSubNode) {
-            IntegerSubNode sub = (IntegerSubNode) x();
-            if (sub.y() == y()) {
+        if (forX instanceof IntegerSubNode) {
+            IntegerSubNode sub = (IntegerSubNode) forX;
+            if (sub.getY() == forY) {
                 // (a - b) + b
-                return sub.x();
+                return sub.getX();
             }
         }
-        if (y() instanceof IntegerSubNode) {
-            IntegerSubNode sub = (IntegerSubNode) y();
-            if (sub.y() == x()) {
+        if (forY instanceof IntegerSubNode) {
+            IntegerSubNode sub = (IntegerSubNode) forY;
+            if (sub.getY() == forX) {
                 // b + (a - b)
-                return sub.x();
+                return sub.getX();
             }
         }
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            long c = y().asConstant().asLong();
+        if (forX.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
+        } else if (forY.isConstant()) {
+            long c = forY.asConstant().asLong();
             if (c == 0) {
-                return x();
+                return forX;
             }
             // canonicalize expressions like "(a + 1) + 2"
-            BinaryNode reassociated = BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
+            BinaryNode reassociated = BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
             if (reassociated != this) {
                 return reassociated;
             }
         }
-        if (x() instanceof NegateNode) {
-            return IntegerArithmeticNode.sub(graph(), y(), ((NegateNode) x()).x());
-        } else if (y() instanceof NegateNode) {
-            return IntegerArithmeticNode.sub(graph(), x(), ((NegateNode) y()).x());
+        if (forX instanceof NegateNode) {
+            return IntegerArithmeticNode.sub(forY, ((NegateNode) forX).getValue());
+        } else if (forY instanceof NegateNode) {
+            return IntegerArithmeticNode.sub(forX, ((NegateNode) forY).getValue());
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value op1 = builder.operand(x());
-        assert op1 != null : x() + ", this=" + this;
-        Value op2 = builder.operand(y());
-        if (!y().isConstant() && !FloatAddNode.livesLonger(this, y(), builder)) {
+        Value op1 = builder.operand(getX());
+        assert op1 != null : getX() + ", this=" + this;
+        Value op2 = builder.operand(getY());
+        if (!getY().isConstant() && !FloatAddNode.livesLonger(this, getY(), builder)) {
             Value op = op1;
             op1 = op2;
             op2 = op;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -25,7 +25,6 @@
 import com.oracle.graal.compiler.common.type.*;
 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 {
 
@@ -35,15 +34,26 @@
     }
 
     public static IntegerAddNode add(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        return graph.unique(new IntegerAddNode(StampTool.add(v1.stamp(), v2.stamp()), v1, v2));
+        return graph.unique(new IntegerAddNode(v1, v2));
+    }
+
+    public static IntegerAddNode add(ValueNode v1, ValueNode v2) {
+        return new IntegerAddNode(v1, v2);
     }
 
     public static IntegerMulNode mul(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        assert v1.stamp().isCompatible(v2.stamp());
-        return graph.unique(new IntegerMulNode(v1.stamp().unrestricted(), v1, v2));
+        return graph.unique(new IntegerMulNode(v1, v2));
+    }
+
+    public static IntegerMulNode mul(ValueNode v1, ValueNode v2) {
+        return new IntegerMulNode(v1, v2);
     }
 
     public static IntegerSubNode sub(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        return graph.unique(new IntegerSubNode(StampTool.sub(v1.stamp(), v2.stamp()), v1, v2));
+        return graph.unique(new IntegerSubNode(v1, v2));
+    }
+
+    public static IntegerSubNode sub(ValueNode v1, ValueNode v2) {
+        return new IntegerSubNode(v1, v2);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -57,32 +55,27 @@
     }
 
     @Override
-    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = super.canonical(tool, forX, forY);
+        if (result != this) {
+            return result;
+        }
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
-            return TriState.FALSE;
+            return LogicConstantNode.contradiction();
         } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
             IntegerStamp xStamp = (IntegerStamp) forX.stamp();
             IntegerStamp yStamp = (IntegerStamp) forY.stamp();
             if (yStamp.isPositive()) {
                 if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
-                    return TriState.TRUE;
+                    return LogicConstantNode.tautology();
                 } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
-                    return TriState.FALSE;
+                    return LogicConstantNode.contradiction();
                 }
             }
         }
-        return super.evaluate(constantReflection, forX, forY);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        Node result = super.canonical(tool);
-        if (result != this) {
-            return result;
-        }
-        if (x().isConstant() && x().asConstant().asLong() == 0) {
+        if (forX.isConstant() && forX.asConstant().asLong() == 0) {
             // 0 |<| y is the same as 0 != y
-            return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y())));
+            return new LogicNegationNode(CompareNode.createCompareNode(Condition.EQ, forX, forY));
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -22,16 +22,14 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
  * An {@code IntegerConvert} converts an integer to an integer of different width.
  */
-public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable {
+public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable {
 
     private final int resultBits;
 
@@ -45,8 +43,8 @@
     }
 
     public int getInputBits() {
-        if (getInput().stamp() instanceof IntegerStamp) {
-            return ((IntegerStamp) getInput().stamp()).getBits();
+        if (getValue().stamp() instanceof IntegerStamp) {
+            return ((IntegerStamp) getValue().stamp()).getBits();
         } else {
             return 0;
         }
@@ -60,30 +58,36 @@
         }
     }
 
-    protected ValueNode canonicalConvert() {
-        if (getInput().stamp() instanceof IntegerStamp) {
-            int inputBits = ((IntegerStamp) getInput().stamp()).getBits();
+    protected ValueNode canonicalConvert(ValueNode value) {
+        if (value.stamp() instanceof IntegerStamp) {
+            int inputBits = ((IntegerStamp) value.stamp()).getBits();
             if (inputBits == resultBits) {
-                return getInput();
-            } else if (getInput().isConstant()) {
-                Constant ret = evalConst(getInput().asConstant());
-                return ConstantNode.forIntegerBits(resultBits, ret.asLong(), graph());
+                return value;
+            } else if (value.isConstant()) {
+                return ConstantNode.forIntegerBits(resultBits, evalConst(value.asConstant()).asLong());
             }
         }
-
-        return null;
+        return this;
     }
 
     public static ValueNode convert(ValueNode input, Stamp stamp) {
         return convert(input, stamp, false);
     }
 
+    public static ValueNode convert(ValueNode input, Stamp stamp, StructuredGraph graph) {
+        ValueNode convert = convert(input, stamp, false);
+        if (!convert.isAlive()) {
+            assert !convert.isDeleted();
+            convert = graph.addOrUnique(convert);
+        }
+        return convert;
+    }
+
     public static ValueNode convertUnsigned(ValueNode input, Stamp stamp) {
         return convert(input, stamp, true);
     }
 
     public static ValueNode convert(ValueNode input, Stamp stamp, boolean zeroExtend) {
-        StructuredGraph graph = input.graph();
         IntegerStamp fromStamp = (IntegerStamp) input.stamp();
         IntegerStamp toStamp = (IntegerStamp) stamp;
 
@@ -91,13 +95,13 @@
         if (toStamp.getBits() == fromStamp.getBits()) {
             result = input;
         } else if (toStamp.getBits() < fromStamp.getBits()) {
-            result = graph.unique(new NarrowNode(input, toStamp.getBits()));
+            result = new NarrowNode(input, toStamp.getBits());
         } else if (zeroExtend) {
             // toStamp.getBits() > fromStamp.getBits()
-            result = graph.unique(new ZeroExtendNode(input, toStamp.getBits()));
+            result = new ZeroExtendNode(input, toStamp.getBits());
         } else {
             // toStamp.getBits() > fromStamp.getBits()
-            result = graph.unique(new SignExtendNode(input, toStamp.getBits()));
+            result = new SignExtendNode(input, toStamp.getBits());
         }
 
         IntegerStamp resultStamp = (IntegerStamp) result.stamp();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -31,62 +31,61 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "/")
-public class IntegerDivNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
+public class IntegerDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
 
-    public IntegerDivNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+    public IntegerDivNode(ValueNode x, ValueNode y) {
+        super(StampTool.div(x.stamp(), y.stamp()), x, y);
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.div(x().stamp(), y().stamp()));
+        return updateStamp(StampTool.div(getX().stamp(), getY().stamp()));
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant()) {
-            long y = y().asConstant().asLong();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            long y = forY.asConstant().asLong();
             if (y == 0) {
                 return this; // this will trap, can not canonicalize
             }
-            return ConstantNode.forIntegerStamp(stamp(), x().asConstant().asLong() / y, graph());
-        } else if (y().isConstant()) {
-            long c = y().asConstant().asLong();
+            return ConstantNode.forIntegerStamp(stamp(), forX.asConstant().asLong() / y);
+        } else if (forY.isConstant()) {
+            long c = forY.asConstant().asLong();
             if (c == 1) {
-                return x();
+                return forX;
             }
             if (c == -1) {
-                return graph().unique(new NegateNode(x()));
+                return new NegateNode(forX);
             }
             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();
+            if (CodeUtil.isPowerOf2(abs) && forX.stamp() instanceof IntegerStamp) {
+                ValueNode dividend = forX;
+                IntegerStamp stampX = (IntegerStamp) forX.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 = 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 sign = new RightShiftNode(forX, ConstantNode.forInt(bits - 1));
+                    UnsignedRightShiftNode round = new UnsignedRightShiftNode(sign, ConstantNode.forInt(bits - log2));
+                    dividend = IntegerArithmeticNode.add(dividend, round);
                 }
-                RightShiftNode shift = graph().unique(new RightShiftNode(unrestricted, dividend, ConstantNode.forInt(log2, graph())));
+                RightShiftNode shift = new RightShiftNode(dividend, ConstantNode.forInt(log2));
                 if (c < 0) {
-                    return graph().unique(new NegateNode(shift));
+                    return new NegateNode(shift);
                 }
                 return shift;
             }
         }
 
         // Convert the expression ((a - a % b) / b) into (a / b).
-        if (x() instanceof IntegerSubNode) {
-            IntegerSubNode integerSubNode = (IntegerSubNode) x();
-            if (integerSubNode.y() instanceof IntegerRemNode) {
-                IntegerRemNode integerRemNode = (IntegerRemNode) integerSubNode.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()));
+        if (forX instanceof IntegerSubNode) {
+            IntegerSubNode integerSubNode = (IntegerSubNode) forX;
+            if (integerSubNode.getY() instanceof IntegerRemNode) {
+                IntegerRemNode integerRemNode = (IntegerRemNode) integerSubNode.getY();
+                if (integerSubNode.stamp().isCompatible(this.stamp()) && integerRemNode.stamp().isCompatible(this.stamp()) && integerSubNode.getX() == integerRemNode.getX() &&
+                                forY == integerRemNode.getY()) {
+                    return new IntegerDivNode(integerSubNode.getX(), forY);
                 }
             }
         }
@@ -108,11 +107,11 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitDiv(gen.operand(x()), gen.operand(y()), gen.state(this)));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitDiv(gen.operand(getX()), gen.operand(getY()), gen.state(this)));
     }
 
     @Override
     public boolean canDeoptimize() {
-        return !(y().stamp() instanceof IntegerStamp) || ((IntegerStamp) y().stamp()).contains(0);
+        return !(getY().stamp() instanceof IntegerStamp) || ((IntegerStamp) getY().stamp()).contains(0);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -58,15 +57,15 @@
     }
 
     @Override
-    protected LogicNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+    protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
         if (constant.getKind() == Kind.Int && constant.asInt() == 0) {
-            ValueNode a = mirrored ? normalizeNode.y() : normalizeNode.x();
-            ValueNode b = mirrored ? normalizeNode.x() : normalizeNode.y();
+            ValueNode a = mirrored ? normalizeNode.getY() : normalizeNode.getX();
+            ValueNode b = mirrored ? normalizeNode.getX() : normalizeNode.getY();
 
-            if (normalizeNode.x().getKind() == Kind.Double || normalizeNode.x().getKind() == Kind.Float) {
-                return graph().unique(new FloatEqualsNode(a, b));
+            if (normalizeNode.getX().getKind() == Kind.Double || normalizeNode.getX().getKind() == Kind.Float) {
+                return new FloatEqualsNode(a, b);
             } else {
-                return graph().unique(new IntegerEqualsNode(a, b));
+                return new IntegerEqualsNode(a, b);
             }
         }
         return this;
@@ -83,56 +82,56 @@
     }
 
     @Override
-    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
-            return TriState.TRUE;
+            return LogicConstantNode.tautology();
         } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
-            return TriState.FALSE;
+            return LogicConstantNode.contradiction();
         }
-        return super.evaluate(constantReflection, forX, forY);
+        return super.canonical(tool, forX, forY);
     }
 
     @Override
-    protected Node canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
+    protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
         if (constant.asLong() == 0) {
             if (nonConstant instanceof AndNode) {
                 AndNode andNode = (AndNode) nonConstant;
-                return graph().unique(new IntegerTestNode(andNode.x(), andNode.y()));
+                return new IntegerTestNode(andNode.getX(), andNode.getY());
             } else if (nonConstant instanceof ShiftNode) {
                 if (nonConstant instanceof LeftShiftNode) {
                     LeftShiftNode shift = (LeftShiftNode) nonConstant;
-                    if (shift.y().isConstant()) {
+                    if (shift.getY().isConstant()) {
                         int mask = shift.getShiftAmountMask();
-                        int amount = shift.y().asConstant().asInt() & mask;
-                        if (shift.x().getKind() == Kind.Int) {
-                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 >>> amount, graph())));
+                        int amount = shift.getY().asConstant().asInt() & mask;
+                        if (shift.getX().getKind() == Kind.Int) {
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 >>> amount));
                         } else {
-                            assert shift.x().getKind() == Kind.Long;
-                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L >>> amount, graph())));
+                            assert shift.getX().getKind() == Kind.Long;
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L >>> amount));
                         }
                     }
                 } else if (nonConstant instanceof RightShiftNode) {
                     RightShiftNode shift = (RightShiftNode) nonConstant;
-                    if (shift.y().isConstant() && ((IntegerStamp) shift.x().stamp()).isPositive()) {
+                    if (shift.getY().isConstant() && ((IntegerStamp) shift.getX().stamp()).isPositive()) {
                         int mask = shift.getShiftAmountMask();
-                        int amount = shift.y().asConstant().asInt() & mask;
-                        if (shift.x().getKind() == Kind.Int) {
-                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 << amount, graph())));
+                        int amount = shift.getY().asConstant().asInt() & mask;
+                        if (shift.getX().getKind() == Kind.Int) {
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount));
                         } else {
-                            assert shift.x().getKind() == Kind.Long;
-                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L << amount, graph())));
+                            assert shift.getX().getKind() == Kind.Long;
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L << amount));
                         }
                     }
                 } else if (nonConstant instanceof UnsignedRightShiftNode) {
                     UnsignedRightShiftNode shift = (UnsignedRightShiftNode) nonConstant;
-                    if (shift.y().isConstant()) {
+                    if (shift.getY().isConstant()) {
                         int mask = shift.getShiftAmountMask();
-                        int amount = shift.y().asConstant().asInt() & mask;
-                        if (shift.x().getKind() == Kind.Int) {
-                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 << amount, graph())));
+                        int amount = shift.getY().asConstant().asInt() & mask;
+                        if (shift.getX().getKind() == Kind.Int) {
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount));
                         } else {
-                            assert shift.x().getKind() == Kind.Long;
-                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L << amount, graph())));
+                            assert shift.getX().getKind() == Kind.Long;
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L << amount));
                         }
                     }
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -58,46 +57,41 @@
     }
 
     @Override
-    protected LogicNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+    protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
         assert condition() == Condition.LT;
         if (constant.getKind() == Kind.Int && constant.asInt() == 0) {
-            ValueNode a = mirrored ? normalizeNode.y() : normalizeNode.x();
-            ValueNode b = mirrored ? normalizeNode.x() : normalizeNode.y();
+            ValueNode a = mirrored ? normalizeNode.getY() : normalizeNode.getX();
+            ValueNode b = mirrored ? normalizeNode.getX() : normalizeNode.getY();
 
-            if (normalizeNode.x().getKind() == Kind.Double || normalizeNode.x().getKind() == Kind.Float) {
-                return graph().unique(new FloatLessThanNode(a, b, mirrored ^ normalizeNode.isUnorderedLess));
+            if (normalizeNode.getX().getKind() == Kind.Double || normalizeNode.getX().getKind() == Kind.Float) {
+                return new FloatLessThanNode(a, b, mirrored ^ normalizeNode.isUnorderedLess);
             } else {
-                return graph().unique(new IntegerLessThanNode(a, b));
+                return new IntegerLessThanNode(a, b);
             }
         }
         return this;
     }
 
     @Override
-    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = super.canonical(tool, forX, forY);
+        if (result != this) {
+            return result;
+        }
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
-            return TriState.FALSE;
+            return LogicConstantNode.contradiction();
         } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
             IntegerStamp xStamp = (IntegerStamp) forX.stamp();
             IntegerStamp yStamp = (IntegerStamp) forY.stamp();
             if (xStamp.upperBound() < yStamp.lowerBound()) {
-                return TriState.TRUE;
+                return LogicConstantNode.tautology();
             } else if (xStamp.lowerBound() >= yStamp.upperBound()) {
-                return TriState.FALSE;
+                return LogicConstantNode.contradiction();
             }
         }
-        return super.evaluate(constantReflection, forX, forY);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        Node result = super.canonical(tool);
-        if (result != this) {
-            return result;
-        }
-        if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
-            if (IntegerStamp.sameSign((IntegerStamp) x().stamp(), (IntegerStamp) y().stamp())) {
-                return graph().unique(new IntegerBelowThanNode(x(), y()));
+        if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            if (IntegerStamp.sameSign((IntegerStamp) forX.stamp(), (IntegerStamp) forY.stamp())) {
+                return new IntegerBelowThanNode(forX, forY);
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -32,10 +32,11 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "*")
-public class IntegerMulNode extends IntegerArithmeticNode implements Canonicalizable, NarrowableArithmeticNode {
+public class IntegerMulNode extends IntegerArithmeticNode implements NarrowableArithmeticNode {
 
-    public IntegerMulNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+    public IntegerMulNode(ValueNode x, ValueNode y) {
+        super(x.stamp().unrestricted(), x, y);
+        assert x.stamp().isCompatible(y.stamp());
     }
 
     @Override
@@ -45,40 +46,40 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new IntegerMulNode(stamp(), y(), x()));
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new IntegerMulNode(forY, forX);
         }
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            long c = y().asConstant().asLong();
+        if (forX.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
+        } else if (forY.isConstant()) {
+            long c = forY.asConstant().asLong();
             if (c == 1) {
-                return x();
+                return forX;
             }
             if (c == 0) {
-                return ConstantNode.forIntegerStamp(stamp(), 0, graph());
+                return ConstantNode.forIntegerStamp(stamp(), 0);
             }
             long abs = Math.abs(c);
             if (abs > 0 && CodeUtil.isPowerOf2(abs)) {
-                LeftShiftNode shift = graph().unique(new LeftShiftNode(stamp().unrestricted(), x(), ConstantNode.forInt(CodeUtil.log2(abs), graph())));
+                LeftShiftNode shift = new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(abs)));
                 if (c < 0) {
-                    return graph().unique(new NegateNode(shift));
+                    return new NegateNode(shift);
                 } else {
                     return shift;
                 }
             }
             // canonicalize expressions like "(a * 1) * 2"
-            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
+            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value op1 = builder.operand(x());
-        Value op2 = builder.operand(y());
-        if (!y().isConstant() && !FloatAddNode.livesLonger(this, y(), builder)) {
+        Value op1 = builder.operand(getX());
+        Value op2 = builder.operand(getY());
+        if (!getY().isConstant() && !FloatAddNode.livesLonger(this, getY(), builder)) {
             Value op = op1;
             op1 = op2;
             op2 = op;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -31,31 +31,31 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "%")
-public class IntegerRemNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
+public class IntegerRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
 
-    public IntegerRemNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+    public IntegerRemNode(ValueNode x, ValueNode y) {
+        super(StampTool.rem(x.stamp(), y.stamp()), x, y);
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.rem(x().stamp(), y().stamp()));
+        return updateStamp(StampTool.rem(getX().stamp(), getY().stamp()));
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant()) {
-            long y = y().asConstant().asLong();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            long y = forY.asConstant().asLong();
             if (y == 0) {
                 return this; // this will trap, can not canonicalize
             }
-            return ConstantNode.forIntegerStamp(stamp(), x().asConstant().asLong() % y, graph());
-        } else if (y().isConstant()) {
-            long c = y().asConstant().asLong();
+            return ConstantNode.forIntegerStamp(stamp(), forX.asConstant().asLong() % y);
+        } else if (forY.isConstant()) {
+            long c = forY.asConstant().asLong();
             if (c == 1 || c == -1) {
-                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(stamp(), x(), ConstantNode.forIntegerStamp(stamp(), c - 1, graph())));
+                return ConstantNode.forIntegerStamp(stamp(), 0);
+            } else if (c > 0 && CodeUtil.isPowerOf2(c) && forX.stamp() instanceof IntegerStamp && ((IntegerStamp) forX.stamp()).isPositive()) {
+                return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), c - 1));
             }
         }
         return this;
@@ -68,11 +68,11 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitRem(gen.operand(x()), gen.operand(y()), gen.state(this)));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitRem(gen.operand(getX()), gen.operand(getY()), gen.state(this)));
     }
 
     @Override
     public boolean canDeoptimize() {
-        return !(y().stamp() instanceof IntegerStamp) || ((IntegerStamp) y().stamp()).contains(0);
+        return !(getY().stamp() instanceof IntegerStamp) || ((IntegerStamp) getY().stamp()).contains(0);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -30,17 +30,18 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "-")
-public class IntegerSubNode extends IntegerArithmeticNode implements Canonicalizable, NarrowableArithmeticNode {
+public class IntegerSubNode extends IntegerArithmeticNode implements NarrowableArithmeticNode {
 
-    public IntegerSubNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+    public IntegerSubNode(ValueNode x, ValueNode y) {
+        super(StampTool.sub(x.stamp(), y.stamp()), x, y);
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.sub(x().stamp(), y().stamp()));
+        return updateStamp(StampTool.sub(getX().stamp(), getY().stamp()));
     }
 
     @Override
@@ -50,75 +51,75 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return ConstantNode.forIntegerStamp(stamp(), 0, graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return ConstantNode.forIntegerStamp(stamp(), 0);
         }
-        if (x() instanceof IntegerAddNode) {
-            IntegerAddNode x = (IntegerAddNode) x();
-            if (x.y() == y()) {
+        if (forX instanceof IntegerAddNode) {
+            IntegerAddNode x = (IntegerAddNode) forX;
+            if (x.getY() == forY) {
                 // (a + b) - b
-                return x.x();
+                return x.getX();
             }
-            if (x.x() == y()) {
+            if (x.getX() == forY) {
                 // (a + b) - a
-                return x.y();
+                return x.getY();
             }
-        } else if (x() instanceof IntegerSubNode) {
-            IntegerSubNode x = (IntegerSubNode) x();
-            if (x.x() == y()) {
+        } else if (forX instanceof IntegerSubNode) {
+            IntegerSubNode x = (IntegerSubNode) forX;
+            if (x.getX() == forY) {
                 // (a - b) - a
-                return graph().unique(new NegateNode(x.y()));
+                return new NegateNode(x.getY());
             }
         }
-        if (y() instanceof IntegerAddNode) {
-            IntegerAddNode y = (IntegerAddNode) y();
-            if (y.x() == x()) {
+        if (forY instanceof IntegerAddNode) {
+            IntegerAddNode y = (IntegerAddNode) forY;
+            if (y.getX() == forX) {
                 // a - (a + b)
-                return graph().unique(new NegateNode(y.y()));
+                return new NegateNode(y.getY());
             }
-            if (y.y() == x()) {
+            if (y.getY() == forX) {
                 // b - (a + b)
-                return graph().unique(new NegateNode(y.x()));
+                return new NegateNode(y.getX());
             }
-        } else if (y() instanceof IntegerSubNode) {
-            IntegerSubNode y = (IntegerSubNode) y();
-            if (y.x() == x()) {
+        } else if (forY instanceof IntegerSubNode) {
+            IntegerSubNode y = (IntegerSubNode) forY;
+            if (y.getX() == forX) {
                 // a - (a - b)
-                return y.y();
+                return y.getY();
             }
         }
-        if (x().isConstant() && y().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            long c = y().asConstant().asLong();
+        if (forX.isConstant() && forY.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
+        } else if (forY.isConstant()) {
+            long c = forY.asConstant().asLong();
             if (c == 0) {
-                return x();
+                return forX;
             }
-            BinaryNode reassociated = BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
+            BinaryNode reassociated = BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
             if (reassociated != this) {
                 return reassociated;
             }
-            if (c < 0 || ((IntegerStamp) StampFactory.forKind(y().getKind())).contains(-c)) {
+            if (c < 0 || ((IntegerStamp) StampFactory.forKind(forY.getKind())).contains(-c)) {
                 // Adding a negative is more friendly to the backend since adds are
                 // commutative, so prefer add when it fits.
-                return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forIntegerStamp(stamp(), -c, graph()));
+                return IntegerArithmeticNode.add(forX, ConstantNode.forIntegerStamp(stamp(), -c));
             }
-        } else if (x().isConstant()) {
-            long c = x().asConstant().asLong();
+        } else if (forX.isConstant()) {
+            long c = forX.asConstant().asLong();
             if (c == 0) {
-                return graph().unique(new NegateNode(y()));
+                return new NegateNode(forY);
             }
-            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
+            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
         }
-        if (y() instanceof NegateNode) {
-            return IntegerArithmeticNode.add(graph(), x(), ((NegateNode) y()).x());
+        if (forY instanceof NegateNode) {
+            return IntegerArithmeticNode.add(forX, ((NegateNode) forY).getValue());
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y())));
+        builder.setResult(this, gen.emitSub(builder.operand(getX()), builder.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -22,9 +22,8 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -45,19 +44,19 @@
     }
 
     @Override
-    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         if (forX.isConstant() && forY.isConstant()) {
-            return TriState.get((forX.asConstant().asLong() & forY.asConstant().asLong()) == 0);
+            return LogicConstantNode.forBoolean((forX.asConstant().asLong() & forY.asConstant().asLong()) == 0);
         }
-        if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
+        if (getX().stamp() instanceof IntegerStamp && getY().stamp() instanceof IntegerStamp) {
             IntegerStamp xStamp = (IntegerStamp) forX.stamp();
             IntegerStamp yStamp = (IntegerStamp) forY.stamp();
             if ((xStamp.upMask() & yStamp.upMask()) == 0) {
-                return TriState.TRUE;
+                return LogicConstantNode.tautology();
             } else if ((xStamp.downMask() & yStamp.downMask()) != 0) {
-                return TriState.FALSE;
+                return LogicConstantNode.contradiction();
             }
         }
-        return TriState.UNKNOWN;
+        return this;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,9 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -34,7 +32,7 @@
 /**
  * An IsNullNode will be true if the supplied value is null, and false if it is non-null.
  */
-public final class IsNullNode extends UnaryOpLogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable {
+public final class IsNullNode extends UnaryOpLogicNode implements LIRLowerable, Virtualizable, PiPushable {
 
     /**
      * Constructs a new IsNullNode instruction.
@@ -52,38 +50,27 @@
 
     @Override
     public boolean verify() {
-        assertTrue(object() != null, "is null input must not be null");
-        assertTrue(object().stamp() instanceof AbstractObjectStamp, "is null input must be an object");
+        assertTrue(getValue() != null, "is null input must not be null");
+        assertTrue(getValue().stamp() instanceof AbstractObjectStamp, "is null input must be an object");
         return super.verify();
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        switch (evaluate(object())) {
-            case FALSE:
-                return LogicConstantNode.contradiction(graph());
-            case TRUE:
-                return LogicConstantNode.tautology(graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        Constant constant = forValue.asConstant();
+        if (constant != null) {
+            assert constant.getKind() == Kind.Object;
+            return LogicConstantNode.forBoolean(constant.isNull());
+        }
+        if (StampTool.isObjectNonNull(forValue.stamp())) {
+            return LogicConstantNode.contradiction();
         }
         return this;
     }
 
     @Override
-    public TriState evaluate(ValueNode forObject) {
-        Constant constant = forObject.asConstant();
-        if (constant != null) {
-            assert constant.getKind() == Kind.Object;
-            return TriState.get(constant.isNull());
-        }
-        if (StampTool.isObjectNonNull(forObject.stamp())) {
-            return TriState.FALSE;
-        }
-        return TriState.UNKNOWN;
-    }
-
-    @Override
     public void virtualize(VirtualizerTool tool) {
-        if (tool.getObjectState(object()) != null) {
+        if (tool.getObjectState(getValue()) != null) {
             tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
@@ -32,15 +31,15 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "<<")
-public final class LeftShiftNode extends ShiftNode implements Canonicalizable {
+public final class LeftShiftNode extends ShiftNode {
 
-    public LeftShiftNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+    public LeftShiftNode(ValueNode x, ValueNode y) {
+        super(x, y);
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.leftShift(x().stamp(), y().stamp()));
+        return updateStamp(StampTool.leftShift(getX().stamp(), getY().stamp()));
     }
 
     @Override
@@ -55,39 +54,39 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            int amount = y().asConstant().asInt();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
+        } else if (forY.isConstant()) {
+            int amount = forY.asConstant().asInt();
             int originalAmout = amount;
             int mask = getShiftAmountMask();
             amount &= mask;
             if (amount == 0) {
-                return x();
+                return forX;
             }
-            if (x() instanceof ShiftNode) {
-                ShiftNode other = (ShiftNode) x();
-                if (other.y().isConstant()) {
-                    int otherAmount = other.y().asConstant().asInt() & mask;
+            if (forX instanceof ShiftNode) {
+                ShiftNode other = (ShiftNode) forX;
+                if (other.getY().isConstant()) {
+                    int otherAmount = other.getY().asConstant().asInt() & mask;
                     if (other instanceof LeftShiftNode) {
                         int total = amount + otherAmount;
                         if (total != (total & mask)) {
-                            return ConstantNode.forIntegerKind(getKind(), 0, graph());
+                            return ConstantNode.forIntegerKind(getKind(), 0);
                         }
-                        return graph().unique(new LeftShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph())));
+                        return new LeftShiftNode(other.getX(), ConstantNode.forInt(total));
                     } else if ((other instanceof RightShiftNode || other instanceof UnsignedRightShiftNode) && otherAmount == amount) {
                         if (getKind() == Kind.Long) {
-                            return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forLong(-1L << amount, graph())));
+                            return new AndNode(other.getX(), ConstantNode.forLong(-1L << amount));
                         } else {
                             assert getKind() == Kind.Int;
-                            return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forInt(-1 << amount, graph())));
+                            return new AndNode(other.getX(), ConstantNode.forInt(-1 << amount));
                         }
                     }
                 }
             }
             if (originalAmout != amount) {
-                return graph().unique(new LeftShiftNode(stamp(), x(), ConstantNode.forInt(amount, graph())));
+                return new LeftShiftNode(forX, ConstantNode.forInt(amount));
             }
         }
         return this;
@@ -95,6 +94,6 @@
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitShl(builder.operand(x()), builder.operand(y())));
+        builder.setResult(this, gen.emitShl(builder.operand(getX()), builder.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -62,51 +61,50 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode ret = canonicalConvert();
-        if (ret != null) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = canonicalConvert(forValue);
+        if (ret != this) {
             return ret;
         }
 
-        if (getInput() instanceof NarrowNode) {
+        if (forValue 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) {
+            NarrowNode other = (NarrowNode) forValue;
+            return new NarrowNode(other.getValue(), getResultBits());
+        } else if (forValue instanceof IntegerConvertNode) {
             // SignExtendNode or ZeroExtendNode
-            IntegerConvertNode other = (IntegerConvertNode) getInput();
+            IntegerConvertNode other = (IntegerConvertNode) forValue;
             if (getResultBits() == other.getInputBits()) {
                 // xxxx -(extend)-> yyyy xxxx -(narrow)-> xxxx
                 // ==> no-op
-                return other.getInput();
+                return other.getValue();
             } else if (getResultBits() < other.getInputBits()) {
                 // yyyyxxxx -(extend)-> zzzzzzzz yyyyxxxx -(narrow)-> xxxx
                 // ==> yyyyxxxx -(narrow)-> xxxx
-                return graph().unique(new NarrowNode(other.getInput(), getResultBits()));
+                return new NarrowNode(other.getValue(), 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()));
+                    return new SignExtendNode(other.getValue(), 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 new ZeroExtendNode(other.getValue(), getResultBits());
                 }
             }
         }
-
         return this;
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.narrowingConversion(getInput().stamp(), getResultBits()));
+        return updateStamp(StampTool.narrowingConversion(getValue().stamp(), getResultBits()));
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitNarrow(builder.operand(getInput()), getResultBits()));
+        builder.setResult(this, gen.emitNarrow(builder.operand(getValue()), getResultBits()));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -34,27 +33,20 @@
 /**
  * The {@code NegateNode} node negates its operand.
  */
-public final class NegateNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode {
-
-    @Input private ValueNode x;
-
-    public ValueNode x() {
-        return x;
-    }
+public final class NegateNode extends UnaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.negate(x().stamp()));
+        return updateStamp(StampTool.negate(getValue().stamp()));
     }
 
     /**
      * Creates new NegateNode instance.
      *
-     * @param x the instruction producing the value that is input to this instruction
+     * @param value the instruction producing the value that is input to this instruction
      */
-    public NegateNode(ValueNode x) {
-        super(StampTool.negate(x.stamp()));
-        this.x = x;
+    public NegateNode(ValueNode value) {
+        super(StampTool.negate(value.stamp()), value);
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -75,22 +67,22 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x.asConstant()), graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forConstant(evalConst(forValue.asConstant()), null);
         }
-        if (x() instanceof NegateNode) {
-            return ((NegateNode) x()).x();
+        if (forValue instanceof NegateNode) {
+            return ((NegateNode) forValue).getValue();
         }
-        if (x() instanceof IntegerSubNode) {
-            IntegerSubNode sub = (IntegerSubNode) x;
-            return IntegerArithmeticNode.sub(graph(), sub.y(), sub.x());
+        if (forValue instanceof IntegerSubNode) {
+            IntegerSubNode sub = (IntegerSubNode) forValue;
+            return new IntegerSubNode(sub.getY(), sub.getX());
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitNegate(builder.operand(x())));
+        builder.setResult(this, gen.emitNegate(builder.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -50,15 +51,21 @@
     }
 
     @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        // nothing to do
+        return this;
+    }
+
+    @Override
     public void lower(LoweringTool tool) {
         LogicNode equalComp;
         LogicNode lessComp;
-        if (x().stamp() instanceof FloatStamp) {
-            equalComp = graph().unique(new FloatEqualsNode(x(), y()));
-            lessComp = graph().unique(new FloatLessThanNode(x(), y(), isUnorderedLess));
+        if (getX().stamp() instanceof FloatStamp) {
+            equalComp = graph().unique(new FloatEqualsNode(getX(), getY()));
+            lessComp = graph().unique(new FloatLessThanNode(getX(), getY(), isUnorderedLess));
         } else {
-            equalComp = graph().unique(new IntegerEqualsNode(x(), y()));
-            lessComp = graph().unique(new IntegerLessThanNode(x(), y()));
+            equalComp = graph().unique(new IntegerEqualsNode(getX(), getY()));
+            lessComp = graph().unique(new IntegerLessThanNode(getX(), getY()));
         }
 
         ConditionalNode equalValue = graph().unique(new ConditionalNode(equalComp, ConstantNode.forInt(0, graph()), ConstantNode.forInt(1, graph())));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -34,17 +33,11 @@
 /**
  * Binary negation of long or integer values.
  */
-public final class NotNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode {
-
-    @Input private ValueNode x;
-
-    public ValueNode x() {
-        return x;
-    }
+public final class NotNode extends UnaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.not(x().stamp()));
+        return updateStamp(StampTool.not(getValue().stamp()));
     }
 
     @Override
@@ -59,23 +52,22 @@
      * @param x the instruction producing the value that is input to this instruction
      */
     public NotNode(ValueNode x) {
-        super(StampTool.not(x.stamp()));
-        this.x = x;
+        super(StampTool.not(x.stamp()), x);
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant()), graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forConstant(evalConst(forValue.asConstant()), null);
         }
-        if (x() instanceof NotNode) {
-            return ((NotNode) x()).x();
+        if (forValue instanceof NotNode) {
+            return ((NotNode) forValue).getValue();
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitNot(builder.operand(x())));
+        builder.setResult(this, gen.emitNot(builder.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -58,26 +57,20 @@
     }
 
     @Override
-    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
-        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
-            return TriState.TRUE;
-        } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
-            return TriState.FALSE;
-        } else {
-            return super.evaluate(constantReflection, forX, forY);
-        }
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        Node result = super.canonical(tool);
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = super.canonical(tool, forX, forY);
         if (result != this) {
             return result;
         }
-        if (StampTool.isObjectAlwaysNull(x())) {
-            return graph().unique(new IsNullNode(y()));
-        } else if (StampTool.isObjectAlwaysNull(y())) {
-            return graph().unique(new IsNullNode(x()));
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return LogicConstantNode.tautology();
+        } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+            return LogicConstantNode.contradiction();
+        }
+        if (StampTool.isObjectAlwaysNull(forX)) {
+            return new IsNullNode(forY);
+        } else if (StampTool.isObjectAlwaysNull(forY)) {
+            return new IsNullNode(forX);
         }
         return this;
     }
@@ -103,15 +96,15 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State stateX = tool.getObjectState(x());
-        State stateY = tool.getObjectState(y());
+        State stateX = tool.getObjectState(getX());
+        State stateY = tool.getObjectState(getY());
         boolean xVirtual = stateX != null && stateX.getState() == EscapeState.Virtual;
         boolean yVirtual = stateY != null && stateY.getState() == EscapeState.Virtual;
 
         if (xVirtual && !yVirtual) {
-            virtualizeNonVirtualComparison(stateX, stateY != null ? stateY.getMaterializedValue() : y(), tool);
+            virtualizeNonVirtualComparison(stateX, stateY != null ? stateY.getMaterializedValue() : getY(), tool);
         } else if (!xVirtual && yVirtual) {
-            virtualizeNonVirtualComparison(stateY, stateX != null ? stateX.getMaterializedValue() : x(), tool);
+            virtualizeNonVirtualComparison(stateY, stateX != null ? stateX.getMaterializedValue() : getX(), tool);
         } else if (xVirtual && yVirtual) {
             boolean xIdentity = stateX.getVirtualObject().hasIdentity();
             boolean yIdentity = stateY.getVirtualObject().hasIdentity();
@@ -119,7 +112,7 @@
                 /*
                  * One of the two objects has identity, the other doesn't. In code, this looks like
                  * "Integer.valueOf(a) == new Integer(b)", which is always false.
-                 *
+                 * 
                  * In other words: an object created via valueOf can never be equal to one created
                  * by new in the same compilation unit.
                  */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -30,17 +30,19 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "|")
-public final class OrNode extends BitLogicNode implements Canonicalizable {
+public final class OrNode extends BitLogicNode {
 
-    public OrNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+    public OrNode(ValueNode x, ValueNode y) {
+        super(StampTool.or(x.stamp(), y.stamp()), x, y);
+        assert x.stamp().isCompatible(y.stamp());
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.or(x().stamp(), y().stamp()));
+        return updateStamp(StampTool.or(getX().stamp(), getY().stamp()));
     }
 
     @Override
@@ -50,31 +52,31 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return x();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return forX;
         }
-        if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new OrNode(stamp(), y(), x()));
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new OrNode(forY, forX);
         }
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(stamp(), evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            long rawY = y().asConstant().asLong();
+        if (forX.isConstant()) {
+            return ConstantNode.forPrimitive(stamp(), evalConst(forX.asConstant(), forY.asConstant()));
+        } else if (forY.isConstant()) {
+            long rawY = forY.asConstant().asLong();
             long mask = IntegerStamp.defaultMask(PrimitiveStamp.getBits(stamp()));
             if ((rawY & mask) == mask) {
-                return ConstantNode.forIntegerStamp(stamp(), mask, graph());
+                return ConstantNode.forIntegerStamp(stamp(), mask);
             }
             if ((rawY & mask) == 0) {
-                return x();
+                return forX;
             }
-            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
+            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitOr(builder.operand(x()), builder.operand(y())));
+        builder.setResult(this, gen.emitOr(builder.operand(getX()), builder.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -25,7 +25,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -36,22 +35,15 @@
  * of a primitive value to some other incompatible stamp. The new stamp must have the same width as
  * the old stamp.
  */
-public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
-
-    @Input private ValueNode value;
-
-    public ValueNode value() {
-        return value;
-    }
+public class ReinterpretNode extends UnaryNode implements ArithmeticLIRLowerable {
 
     private ReinterpretNode(Kind to, ValueNode value) {
         this(StampFactory.forKind(to), value);
     }
 
     public ReinterpretNode(Stamp to, ValueNode value) {
-        super(to);
+        super(to, value);
         assert to instanceof PrimitiveStamp;
-        this.value = value;
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -88,24 +80,24 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(value.asConstant()), graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forConstant(evalConst(forValue.asConstant()), null);
         }
-        if (stamp().isCompatible(value.stamp())) {
-            return value;
+        if (stamp().isCompatible(forValue.stamp())) {
+            return forValue;
         }
-        if (value instanceof ReinterpretNode) {
-            ReinterpretNode reinterpret = (ReinterpretNode) value;
-            return value.graph().unique(new ReinterpretNode(stamp(), reinterpret.value()));
+        if (forValue instanceof ReinterpretNode) {
+            ReinterpretNode reinterpret = (ReinterpretNode) forValue;
+            return new ReinterpretNode(stamp(), reinterpret.getValue());
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        PlatformKind kind = gen.getPlatformKind(stamp());
-        builder.setResult(this, gen.emitReinterpret(kind, builder.operand(value())));
+        LIRKind kind = gen.getLIRKind(stamp());
+        builder.setResult(this, gen.emitReinterpret(kind, builder.operand(getValue())));
     }
 
     public static ValueNode reinterpret(Kind toKind, ValueNode value) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -31,10 +31,10 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = ">>")
-public final class RightShiftNode extends ShiftNode implements Canonicalizable {
+public final class RightShiftNode extends ShiftNode {
 
-    public RightShiftNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+    public RightShiftNode(ValueNode x, ValueNode y) {
+        super(x, y);
     }
 
     @Override
@@ -49,35 +49,35 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().stamp() instanceof IntegerStamp && ((IntegerStamp) x().stamp()).isPositive()) {
-            return graph().unique(new UnsignedRightShiftNode(stamp(), x(), y()));
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.stamp() instanceof IntegerStamp && ((IntegerStamp) forX.stamp()).isPositive()) {
+            return new UnsignedRightShiftNode(forX, forY);
         }
-        if (x().isConstant() && y().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            int amount = y().asConstant().asInt();
+        if (forX.isConstant() && forY.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
+        } else if (forY.isConstant()) {
+            int amount = forY.asConstant().asInt();
             int originalAmout = amount;
             int mask = getShiftAmountMask();
             amount &= mask;
             if (amount == 0) {
-                return x();
+                return forX;
             }
-            if (x() instanceof ShiftNode) {
-                ShiftNode other = (ShiftNode) x();
-                if (other.y().isConstant()) {
-                    int otherAmount = other.y().asConstant().asInt() & mask;
+            if (forX instanceof ShiftNode) {
+                ShiftNode other = (ShiftNode) forX;
+                if (other.getY().isConstant()) {
+                    int otherAmount = other.getY().asConstant().asInt() & mask;
                     if (other instanceof RightShiftNode) {
                         int total = amount + otherAmount;
                         if (total != (total & mask)) {
-                            assert other.x().stamp() instanceof IntegerStamp;
-                            IntegerStamp istamp = (IntegerStamp) other.x().stamp();
+                            assert other.getX().stamp() instanceof IntegerStamp;
+                            IntegerStamp istamp = (IntegerStamp) other.getX().stamp();
 
                             if (istamp.isPositive()) {
-                                return ConstantNode.forIntegerKind(getKind(), 0, graph());
+                                return ConstantNode.forIntegerKind(getKind(), 0);
                             }
                             if (istamp.isStrictlyNegative()) {
-                                return ConstantNode.forIntegerKind(getKind(), -1L, graph());
+                                return ConstantNode.forIntegerKind(getKind(), -1L);
                             }
 
                             /*
@@ -85,14 +85,14 @@
                              * full shift for this kind
                              */
                             assert total >= mask;
-                            return graph().unique(new RightShiftNode(stamp(), other.x(), ConstantNode.forInt(mask, graph())));
+                            return new RightShiftNode(other.getX(), ConstantNode.forInt(mask));
                         }
-                        return graph().unique(new RightShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph())));
+                        return new RightShiftNode(other.getX(), ConstantNode.forInt(total));
                     }
                 }
             }
             if (originalAmout != amount) {
-                return graph().unique(new RightShiftNode(stamp(), x(), ConstantNode.forInt(amount, graph())));
+                return new RightShiftNode(forX, ConstantNode.forInt(amount));
             }
         }
         return this;
@@ -100,6 +100,6 @@
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitShr(builder.operand(x()), builder.operand(y())));
+        builder.setResult(this, gen.emitShr(builder.operand(getX()), builder.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -34,12 +33,13 @@
 
     /**
      * Creates a new shift operation.
-     * 
+     *
      * @param x the first input value
      * @param s the second input value
      */
-    public ShiftNode(Stamp stamp, ValueNode x, ValueNode s) {
-        super(stamp, x, s);
+    public ShiftNode(ValueNode x, ValueNode s) {
+        super(x.stamp().unrestricted(), x, s);
+        assert s.getKind() == Kind.Int;
     }
 
     public int getShiftAmountMask() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -68,32 +67,32 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode ret = canonicalConvert();
-        if (ret != null) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = canonicalConvert(forValue);
+        if (ret != this) {
             return ret;
         }
 
-        if (getInput() instanceof SignExtendNode) {
+        if (forValue 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();
+            SignExtendNode other = (SignExtendNode) forValue;
+            return new SignExtendNode(other.getValue(), getResultBits());
+        } else if (forValue instanceof ZeroExtendNode) {
+            ZeroExtendNode other = (ZeroExtendNode) forValue;
             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()));
+                return new ZeroExtendNode(other.getValue(), getResultBits());
             }
         }
 
-        if (getInput().stamp() instanceof IntegerStamp) {
-            IntegerStamp inputStamp = (IntegerStamp) getInput().stamp();
+        if (forValue.stamp() instanceof IntegerStamp) {
+            IntegerStamp inputStamp = (IntegerStamp) forValue.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 new ZeroExtendNode(forValue, getResultBits());
             }
         }
 
@@ -102,11 +101,11 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.signExtend(getInput().stamp(), getResultBits()));
+        return updateStamp(StampTool.signExtend(getValue().stamp(), getResultBits()));
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitSignExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
+        builder.setResult(this, gen.emitSignExtend(builder.operand(getValue()), getInputBits(), getResultBits()));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.calc;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * The {@code UnaryNode} class is the base of arithmetic and bit logic operations with exactly one
+ * input.
+ */
+public abstract class UnaryNode extends FloatingNode implements Canonicalizable.Unary<ValueNode> {
+
+    @Input private ValueNode value;
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    /**
+     * Creates a new UnaryNode instance.
+     *
+     * @param stamp the result type of this instruction
+     * @param value the input instruction
+     */
+    public UnaryNode(Stamp stamp, ValueNode value) {
+        super(stamp);
+        this.value = value;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -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.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -31,35 +30,27 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "|/|")
-public class UnsignedDivNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
+public class UnsignedDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
 
-    /**
-     * 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);
+    public UnsignedDivNode(ValueNode x, ValueNode y) {
+        super(x.stamp().unrestricted(), x, y);
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant()) {
-            long yConst = y().asConstant().asLong();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            long yConst = forY.asConstant().asLong();
             if (yConst == 0) {
                 return this; // this will trap, cannot canonicalize
             }
-            return ConstantNode.forIntegerStamp(stamp(), UnsignedMath.divide(x().asConstant().asLong(), yConst), graph());
-        } else if (y().isConstant()) {
-            long c = y().asConstant().asLong();
+            return ConstantNode.forIntegerStamp(stamp(), UnsignedMath.divide(forX.asConstant().asLong(), yConst));
+        } else if (forY.isConstant()) {
+            long c = forY.asConstant().asLong();
             if (c == 1) {
-                return x();
+                return forX;
             }
             if (CodeUtil.isPowerOf2(c)) {
-                return graph().unique(new UnsignedRightShiftNode(stamp(), x(), ConstantNode.forInt(CodeUtil.log2(c), graph())));
+                return new UnsignedRightShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(c)));
             }
         }
         return this;
@@ -72,11 +63,17 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitUDiv(gen.operand(x()), gen.operand(y()), gen.state(this)));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitUDiv(gen.operand(getX()), gen.operand(getY()), gen.state(this)));
     }
 
     @Override
     public boolean canDeoptimize() {
-        return !(y().stamp() instanceof IntegerStamp) || ((IntegerStamp) y().stamp()).contains(0);
+        return !(getY().stamp() instanceof IntegerStamp) || ((IntegerStamp) getY().stamp()).contains(0);
     }
+
+    @NodeIntrinsic
+    public static native int unsignedDivide(int a, int b);
+
+    @NodeIntrinsic
+    public static native long unsignedDivide(long a, long b);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -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.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -31,34 +30,26 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "|%|")
-public class UnsignedRemNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
+public class UnsignedRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
 
-    /**
-     * 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);
+    public UnsignedRemNode(ValueNode x, ValueNode y) {
+        super(x.stamp().unrestricted(), x, y);
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant()) {
-            long yConst = y().asConstant().asLong();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            long yConst = forY.asConstant().asLong();
             if (yConst == 0) {
                 return this; // this will trap, cannot canonicalize
             }
-            return ConstantNode.forIntegerStamp(stamp(), UnsignedMath.remainder(x().asConstant().asLong(), yConst), graph());
-        } else if (y().isConstant()) {
-            long c = y().asConstant().asLong();
+            return ConstantNode.forIntegerStamp(stamp(), UnsignedMath.remainder(forX.asConstant().asLong(), yConst));
+        } else if (forY.isConstant()) {
+            long c = forY.asConstant().asLong();
             if (c == 1) {
-                return ConstantNode.forIntegerStamp(stamp(), 0, graph());
+                return ConstantNode.forIntegerStamp(stamp(), 0);
             } else if (CodeUtil.isPowerOf2(c)) {
-                return graph().unique(new AndNode(stamp(), x(), ConstantNode.forIntegerStamp(stamp(), c - 1, graph())));
+                return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), c - 1));
             }
         }
         return this;
@@ -71,11 +62,17 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitURem(gen.operand(x()), gen.operand(y()), gen.state(this)));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitURem(gen.operand(getX()), gen.operand(getY()), gen.state(this)));
     }
 
     @Override
     public boolean canDeoptimize() {
-        return !(y().stamp() instanceof IntegerStamp) || ((IntegerStamp) y().stamp()).contains(0);
+        return !(getY().stamp() instanceof IntegerStamp) || ((IntegerStamp) getY().stamp()).contains(0);
     }
+
+    @NodeIntrinsic
+    public static native int unsignedRemainder(int a, int b);
+
+    @NodeIntrinsic
+    public static native long unsignedRemainder(long a, long b);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
@@ -32,15 +31,15 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = ">>>")
-public final class UnsignedRightShiftNode extends ShiftNode implements Canonicalizable {
+public final class UnsignedRightShiftNode extends ShiftNode {
 
-    public UnsignedRightShiftNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+    public UnsignedRightShiftNode(ValueNode x, ValueNode y) {
+        super(x, y);
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.unsignedRightShift(x().stamp(), y().stamp()));
+        return updateStamp(StampTool.unsignedRightShift(getX().stamp(), getY().stamp()));
     }
 
     @Override
@@ -55,39 +54,39 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            int amount = y().asConstant().asInt();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
+        } else if (forY.isConstant()) {
+            int amount = forY.asConstant().asInt();
             int originalAmout = amount;
             int mask = getShiftAmountMask();
             amount &= mask;
             if (amount == 0) {
-                return x();
+                return forX;
             }
-            if (x() instanceof ShiftNode) {
-                ShiftNode other = (ShiftNode) x();
-                if (other.y().isConstant()) {
-                    int otherAmount = other.y().asConstant().asInt() & mask;
+            if (forX instanceof ShiftNode) {
+                ShiftNode other = (ShiftNode) forX;
+                if (other.getY().isConstant()) {
+                    int otherAmount = other.getY().asConstant().asInt() & mask;
                     if (other instanceof UnsignedRightShiftNode) {
                         int total = amount + otherAmount;
                         if (total != (total & mask)) {
-                            return ConstantNode.forIntegerKind(getKind(), 0, graph());
+                            return ConstantNode.forIntegerKind(getKind(), 0);
                         }
-                        return graph().unique(new UnsignedRightShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph())));
+                        return new UnsignedRightShiftNode(other.getX(), ConstantNode.forInt(total));
                     } else if (other instanceof LeftShiftNode && otherAmount == amount) {
                         if (getKind() == Kind.Long) {
-                            return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forLong(-1L >>> amount, graph())));
+                            return new AndNode(other.getX(), ConstantNode.forLong(-1L >>> amount));
                         } else {
                             assert getKind() == Kind.Int;
-                            return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forInt(-1 >>> amount, graph())));
+                            return new AndNode(other.getX(), ConstantNode.forInt(-1 >>> amount));
                         }
                     }
                 }
             }
             if (originalAmout != amount) {
-                return graph().unique(new UnsignedRightShiftNode(stamp(), x(), ConstantNode.forInt(amount, graph())));
+                return new UnsignedRightShiftNode(forX, ConstantNode.forInt(amount));
             }
         }
         return this;
@@ -95,6 +94,6 @@
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitUShr(builder.operand(x()), builder.operand(y())));
+        builder.setResult(this, gen.emitUShr(builder.operand(getX()), builder.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,17 +30,19 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "^")
-public final class XorNode extends BitLogicNode implements Canonicalizable {
+public final class XorNode extends BitLogicNode {
 
-    public XorNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+    public XorNode(ValueNode x, ValueNode y) {
+        super(StampTool.xor(x.stamp(), y.stamp()), x, y);
+        assert x.stamp().isCompatible(y.stamp());
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.xor(x().stamp(), y().stamp()));
+        return updateStamp(StampTool.xor(getX().stamp(), getY().stamp()));
     }
 
     @Override
@@ -50,30 +52,30 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return ConstantNode.forIntegerStamp(stamp(), 0, graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return ConstantNode.forIntegerStamp(stamp(), 0);
         }
-        if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new XorNode(stamp(), y(), x()));
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new XorNode(forY, forX);
         }
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(stamp(), evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            long rawY = y().asConstant().asLong();
+        if (forX.isConstant()) {
+            return ConstantNode.forPrimitive(stamp(), evalConst(forX.asConstant(), forY.asConstant()));
+        } else if (forY.isConstant()) {
+            long rawY = forY.asConstant().asLong();
             long mask = IntegerStamp.defaultMask(PrimitiveStamp.getBits(stamp()));
             if ((rawY & mask) == 0) {
-                return x();
+                return forX;
             } else if ((rawY & mask) == mask) {
-                return graph().unique(new NotNode(x()));
+                return new NotNode(forX);
             }
-            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
+            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitXor(builder.operand(x()), builder.operand(y())));
+        builder.setResult(this, gen.emitXor(builder.operand(getX()), builder.operand(getY())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -25,7 +25,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -78,28 +77,28 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode ret = canonicalConvert();
-        if (ret != null) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = canonicalConvert(forValue);
+        if (ret != this) {
             return ret;
         }
 
-        if (getInput() instanceof ZeroExtendNode) {
+        if (forValue 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()));
+            ZeroExtendNode other = (ZeroExtendNode) forValue;
+            return new ZeroExtendNode(other.getValue(), getResultBits());
         }
-        if (getInput() instanceof NarrowNode) {
-            NarrowNode narrow = (NarrowNode) getInput();
-            Stamp inputStamp = narrow.getInput().stamp();
+        if (forValue instanceof NarrowNode) {
+            NarrowNode narrow = (NarrowNode) forValue;
+            Stamp inputStamp = narrow.getValue().stamp();
             if (inputStamp instanceof IntegerStamp && inputStamp.isCompatible(stamp())) {
                 IntegerStamp istamp = (IntegerStamp) inputStamp;
                 long mask = IntegerStamp.defaultMask(PrimitiveStamp.getBits(narrow.stamp()));
                 if (((istamp.upMask() | istamp.downMask()) & ~mask) == 0) {
                     // The original value is in the range of the masked zero extended result so
                     // simply return the original input.
-                    return narrow.getInput();
+                    return narrow.getValue();
                 }
             }
         }
@@ -109,11 +108,11 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.zeroExtend(getInput().stamp(), getResultBits()));
+        return updateStamp(StampTool.zeroExtend(getValue().stamp(), getResultBits()));
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitZeroExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
+        builder.setResult(this, gen.emitZeroExtend(builder.operand(getValue()), getInputBits(), getResultBits()));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -36,16 +36,16 @@
  * [(base + x) + y] where base is a node and x and y are location nodes.
  */
 @NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}")
-public final class AddLocationNode extends LocationNode implements Canonicalizable {
+public final class AddLocationNode extends LocationNode implements Canonicalizable.Binary<LocationNode> {
 
     @Input(InputType.Association) private ValueNode x;
     @Input(InputType.Association) private ValueNode y;
 
-    protected LocationNode getX() {
+    public LocationNode getX() {
         return (LocationNode) x;
     }
 
-    protected LocationNode getY() {
+    public LocationNode getY() {
         return (LocationNode) y;
     }
 
@@ -70,21 +70,20 @@
         return getX().getLocationIdentity();
     }
 
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x instanceof ConstantLocationNode) {
-            return canonical((ConstantLocationNode) x, getY());
+    public LocationNode canonical(CanonicalizerTool tool, LocationNode forX, LocationNode forY) {
+        if (forX instanceof ConstantLocationNode) {
+            return canonical((ConstantLocationNode) forX, forY);
         }
-        if (y instanceof ConstantLocationNode) {
-            return canonical((ConstantLocationNode) y, getX());
+        if (forY instanceof ConstantLocationNode) {
+            return canonical((ConstantLocationNode) forY, forX);
         }
-        if (x instanceof IndexedLocationNode && y instanceof IndexedLocationNode) {
-            IndexedLocationNode xIdx = (IndexedLocationNode) x;
-            IndexedLocationNode yIdx = (IndexedLocationNode) y;
+        if (forX instanceof IndexedLocationNode && forY instanceof IndexedLocationNode) {
+            IndexedLocationNode xIdx = (IndexedLocationNode) forX;
+            IndexedLocationNode yIdx = (IndexedLocationNode) forY;
             if (xIdx.getIndexScaling() == yIdx.getIndexScaling()) {
                 long displacement = xIdx.getDisplacement() + yIdx.getDisplacement();
-                ValueNode index = IntegerArithmeticNode.add(graph(), xIdx.getIndex(), yIdx.getIndex());
-                return IndexedLocationNode.create(getLocationIdentity(), getValueKind(), displacement, index, graph(), xIdx.getIndexScaling());
+                ValueNode index = IntegerArithmeticNode.add(xIdx.getIndex(), yIdx.getIndex());
+                return IndexedLocationNode.create(getLocationIdentity(), getValueKind(), displacement, index, xIdx.getIndexScaling());
             }
         }
         return this;
@@ -93,15 +92,15 @@
     private LocationNode canonical(ConstantLocationNode constant, LocationNode other) {
         if (other instanceof ConstantLocationNode) {
             ConstantLocationNode otherConst = (ConstantLocationNode) other;
-            return ConstantLocationNode.create(getLocationIdentity(), getValueKind(), otherConst.getDisplacement() + constant.getDisplacement(), graph());
+            return ConstantLocationNode.create(getLocationIdentity(), getValueKind(), otherConst.getDisplacement() + constant.getDisplacement());
         } else if (other instanceof IndexedLocationNode) {
             IndexedLocationNode otherIdx = (IndexedLocationNode) other;
-            return IndexedLocationNode.create(getLocationIdentity(), getValueKind(), otherIdx.getDisplacement() + constant.getDisplacement(), otherIdx.getIndex(), graph(), otherIdx.getIndexScaling());
+            return IndexedLocationNode.create(getLocationIdentity(), getValueKind(), otherIdx.getDisplacement() + constant.getDisplacement(), otherIdx.getIndex(), otherIdx.getIndexScaling());
         } else if (other instanceof AddLocationNode) {
             AddLocationNode otherAdd = (AddLocationNode) other;
             LocationNode newInner = otherAdd.canonical(constant, otherAdd.getX());
             if (newInner != otherAdd) {
-                return AddLocationNode.create(newInner, otherAdd.getY(), graph());
+                return new AddLocationNode(newInner, otherAdd.getY());
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -39,14 +38,12 @@
  * This node represents the boxing of a primitive value. This corresponds to a call to the valueOf
  * methods in Integer, Long, etc.
  */
-public class BoxNode extends FloatingNode implements VirtualizableAllocation, Lowerable, Canonicalizable {
+public class BoxNode extends UnaryNode implements VirtualizableAllocation, Lowerable {
 
-    @Input private ValueNode value;
     private final Kind boxingKind;
 
     public BoxNode(ValueNode value, ResolvedJavaType resultType, Kind boxingKind) {
-        super(StampFactory.exactNonNull(resultType));
-        this.value = value;
+        super(StampFactory.exactNonNull(resultType), value);
         this.boxingKind = boxingKind;
     }
 
@@ -54,24 +51,17 @@
         return boxingKind;
     }
 
-    public ValueNode getValue() {
-        return value;
-    }
-
     @Override
     public void lower(LoweringTool tool) {
         tool.getLowerer().lower(this, tool);
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
         /*
          * Constant values are not canonicalized into their constant boxing objects because this
          * would mean that the information that they came from a valueOf is lost.
          */
-        if (usages().isEmpty()) {
-            return null;
-        }
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BranchProbabilityNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BranchProbabilityNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -35,7 +34,7 @@
  * the if node's taken probability. Then the branch probability node will be removed. This node is
  * intended primarily for snippets, so that they can define their fast and slow paths.
  */
-public class BranchProbabilityNode extends FloatingNode implements Canonicalizable, Lowerable {
+public class BranchProbabilityNode extends FloatingNode implements Simplifiable, Lowerable {
 
     public static final double LIKELY_PROBABILITY = 0.6;
     public static final double NOT_LIKELY_PROBABILITY = 1 - LIKELY_PROBABILITY;
@@ -67,7 +66,7 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public void simplify(SimplifierTool tool) {
         if (probability.isConstant()) {
             double probabilityValue = probability.asConstant().asDouble();
             if (probabilityValue < 0.0) {
@@ -78,9 +77,9 @@
             boolean couldSet = false;
             for (IntegerEqualsNode node : this.usages().filter(IntegerEqualsNode.class)) {
                 if (node.condition() == Condition.EQ) {
-                    ValueNode other = node.x();
-                    if (node.x() == this) {
-                        other = node.y();
+                    ValueNode other = node.getX();
+                    if (node.getX() == this) {
+                        other = node.getY();
                     }
                     if (other.isConstant()) {
                         double probabilityToSet = probabilityValue;
@@ -94,15 +93,15 @@
                     }
                 }
             }
-            if (!couldSet) {
-                if (isSubstitutionGraph()) {
-                    return this;
+            if (couldSet) {
+                replaceAndDelete(condition);
+                tool.addToWorkList(condition.usages());
+            } else {
+                if (!isSubstitutionGraph()) {
+                    throw new GraalInternalError("Wrong usage of branch probability injection!");
                 }
-                throw new GraalInternalError("Wrong usage of branch probability injection!");
             }
-            return condition;
         }
-        return this;
     }
 
     private boolean isSubstitutionGraph() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -43,6 +43,10 @@
         return graph.unique(new ConstantLocationNode(identity, kind, displacement));
     }
 
+    public static ConstantLocationNode create(LocationIdentity identity, Kind kind, long displacement) {
+        return new ConstantLocationNode(identity, kind, displacement);
+    }
+
     private ConstantLocationNode(LocationIdentity identity, Kind kind, long displacement) {
         super(StampFactory.forVoid());
         assert kind != Kind.Illegal && kind != Kind.Void;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -64,19 +64,20 @@
     }
 
     public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp) {
-        this(object, location, stamp, null, BarrierType.NONE);
+        this(object, location, stamp, BarrierType.NONE);
     }
 
     public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
-        this(object, location, stamp, null, barrierType);
+        this(object, location, stamp, null, barrierType, false, null);
     }
 
-    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
-        super(stamp);
+    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
+        super(stamp, stateBefore);
         this.object = object;
         this.location = location;
         this.guard = guard;
         this.barrierType = barrierType;
+        this.nullCheck = nullCheck;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -36,11 +36,11 @@
     }
 
     public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
-        super(object, location, stamp, guard, barrierType);
+        super(object, location, stamp, guard, barrierType, false, null);
     }
 
-    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
-        super(object, location, stamp, barrierType);
+    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
+        super(object, location, stamp, guard, barrierType, nullCheck, stateBefore);
     }
 
     public abstract FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -62,14 +62,14 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
-        PlatformKind readKind = gen.getLIRGeneratorTool().getPlatformKind(stamp());
+        LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp());
         gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, null));
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
-            return graph().unique(new FloatingReadNode(((PiNode) object()).getOriginalNode(), location(), getLastLocationAccess(), stamp(), getGuard(), getBarrierType()));
+            return new FloatingReadNode(((PiNode) object()).getOriginalNode(), location(), getLastLocationAccess(), stamp(), getGuard(), getBarrierType());
         }
         return ReadNode.canonicalizeRead(this, location(), object(), tool);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -66,8 +66,14 @@
         return graph.unique(new IndexedLocationNode(identity, kind, displacement, index, indexScaling));
     }
 
+    public static IndexedLocationNode create(LocationIdentity identity, Kind kind, long displacement, ValueNode index, int indexScaling) {
+        return new IndexedLocationNode(identity, kind, displacement, index, indexScaling);
+    }
+
     public IndexedLocationNode(LocationIdentity identity, Kind kind, long displacement, ValueNode index, int indexScaling) {
         super(StampFactory.forVoid());
+        assert index != null;
+        assert indexScaling != 0;
         assert kind != Kind.Illegal && kind != Kind.Void;
         this.valueKind = kind;
         this.locationIdentity = identity;
@@ -88,10 +94,8 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (index == null || indexScaling == 0) {
-            return ConstantLocationNode.create(getLocationIdentity(), getValueKind(), displacement, graph());
-        } else if (index.isConstant()) {
-            return ConstantLocationNode.create(getLocationIdentity(), getValueKind(), index.asConstant().asLong() * indexScaling + displacement, graph());
+        if (index.isConstant()) {
+            return ConstantLocationNode.create(getLocationIdentity(), getValueKind(), index.asConstant().asLong() * indexScaling + displacement);
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -25,7 +25,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -34,23 +33,23 @@
  * Loads an object's {@linkplain Representation#ObjectHub hub}. The object is not null-checked by
  * this operation.
  */
-public final class LoadHubNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, Virtualizable {
+public final class LoadHubNode extends FloatingGuardedNode implements Lowerable, Canonicalizable.Unary<ValueNode>, Virtualizable {
 
-    @Input private ValueNode object;
+    @Input private ValueNode value;
 
-    public ValueNode object() {
-        return object;
+    public ValueNode getValue() {
+        return value;
     }
 
-    public LoadHubNode(ValueNode object, Kind kind) {
+    public LoadHubNode(ValueNode value, Kind kind) {
         super(getKind(kind), null);
-        this.object = object;
+        this.value = value;
     }
 
-    public LoadHubNode(ValueNode object, Kind kind, ValueNode guard) {
+    public LoadHubNode(ValueNode value, Kind kind, ValueNode guard) {
         super(getKind(kind), (GuardingNode) guard);
-        assert object != guard;
-        this.object = object;
+        assert value != guard;
+        this.value = value;
     }
 
     private static Stamp getKind(Kind kind) {
@@ -63,10 +62,10 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forObject) {
         MetaAccessProvider metaAccess = tool.getMetaAccess();
-        if (metaAccess != null && object.stamp() instanceof ObjectStamp) {
-            ObjectStamp stamp = (ObjectStamp) object.stamp();
+        if (metaAccess != null && forObject.stamp() instanceof ObjectStamp) {
+            ObjectStamp stamp = (ObjectStamp) forObject.stamp();
 
             ResolvedJavaType exactType;
             if (stamp.isExactType()) {
@@ -81,7 +80,7 @@
             }
 
             if (exactType != null) {
-                return ConstantNode.forConstant(exactType.getEncoding(Representation.ObjectHub), metaAccess, graph());
+                return ConstantNode.forConstant(exactType.getEncoding(Representation.ObjectHub), metaAccess);
             }
         }
         return this;
@@ -89,7 +88,7 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
+        State state = tool.getObjectState(value);
         if (state != null) {
             Constant constantHub = state.getVirtualObject().type().getEncoding(Representation.ObjectHub);
             tool.replaceWithValue(ConstantNode.forConstant(constantHub, tool.getMetaAccessProvider(), graph()));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -24,13 +24,16 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+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.*;
 
 /**
  * Loads a method from the virtual method table of a given hub.
  */
-public final class LoadMethodNode extends FixedWithNextNode implements Lowerable {
+public final class LoadMethodNode extends FixedWithNextNode implements Lowerable, Canonicalizable {
 
     @Input private ValueNode hub;
     private final ResolvedJavaMethod method;
@@ -55,6 +58,50 @@
         tool.getLowerer().lower(this, tool);
     }
 
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (hub instanceof LoadHubNode) {
+            ValueNode object = ((LoadHubNode) hub).getValue();
+            ResolvedJavaType type = StampTool.typeOrNull(object);
+            if (StampTool.isExactType(object)) {
+                return resolveExactMethod(tool, type);
+            }
+            if (type != null && tool.assumptions().useOptimisticAssumptions()) {
+                ResolvedJavaMethod resolvedMethod = type.findUniqueConcreteMethod(method);
+                if (resolvedMethod != null && !type.isInterface() && method.getDeclaringClass().isAssignableFrom(type)) {
+                    tool.assumptions().recordConcreteMethod(method, type, resolvedMethod);
+                    return ConstantNode.forConstant(resolvedMethod.getEncoding(), tool.getMetaAccess());
+                }
+            }
+        }
+        if (hub.isConstant()) {
+            return resolveExactMethod(tool, tool.getConstantReflection().asJavaType(hub.asConstant()));
+        }
+
+        return this;
+    }
+
+    /**
+     * Find the method which would be loaded.
+     *
+     * @param tool
+     * @param type the exact type of object being loaded from
+     * @return the method which would be invoked for {@code type} or null if it doesn't implement
+     *         the method
+     */
+    private Node resolveExactMethod(CanonicalizerTool tool, ResolvedJavaType type) {
+        ResolvedJavaMethod newMethod = type.resolveMethod(method, type);
+        if (newMethod == null) {
+            /*
+             * This really represent a misuse of LoadMethod since we're loading from a class which
+             * isn't known to implement the original method but for now at least fold it away.
+             */
+            return ConstantNode.forConstant(Constant.NULL_OBJECT, null);
+        } else {
+            return ConstantNode.forConstant(newMethod.getEncoding(), tool.getMetaAccess());
+        }
+    }
+
     public ResolvedJavaMethod getMethod() {
         return method;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,13 +37,17 @@
 public final class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, PiPushable, Virtualizable, GuardingNode {
 
     public ReadNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
-        super(object, location, stamp, barrierType);
+        super(object, location, stamp, null, barrierType);
     }
 
     public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
         super(object, location, stamp, guard, barrierType);
     }
 
+    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
+        super(object, location, stamp, guard, barrierType, nullCheck, stateBefore);
+    }
+
     private ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType) {
         /*
          * Used by node intrinsics. Really, you can trust me on that! Since the initial value for
@@ -56,17 +60,14 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
-        PlatformKind readKind = gen.getLIRGeneratorTool().getPlatformKind(stamp());
+        LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp());
         gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, gen.state(this)));
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
-            ReadNode readNode = graph().add(new ReadNode(((PiNode) object()).getOriginalNode(), location(), stamp(), getGuard(), getBarrierType()));
-            readNode.setNullCheck(getNullCheck());
-            readNode.setStateBefore(stateBefore());
-            return readNode;
+            return new ReadNode(((PiNode) object()).getOriginalNode(), location(), stamp(), getGuard(), getBarrierType(), getNullCheck(), stateBefore());
         }
         return canonicalizeRead(this, location(), object(), tool);
     }
@@ -87,7 +88,7 @@
             GuardingNode guard = ((Access) read).getGuard();
             if (guard != null && !(guard instanceof FixedNode)) {
                 // The guard is necessary even if the read goes away.
-                return read.graph().add(new ValueAnchorNode((ValueNode) guard));
+                return new ValueAnchorNode((ValueNode) guard);
             } else {
                 // Read without usages or guard can be safely removed.
                 return null;
@@ -109,7 +110,7 @@
                             constant = tool.getConstantReflection().readUnsafeConstant(Kind.Object, base, displacement);
                         }
                         if (constant != null) {
-                            return ConstantNode.forConstant(read.stamp(), constant, metaAccess, read.graph());
+                            return ConstantNode.forConstant(read.stamp(), constant, metaAccess);
                         }
                     }
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,20 +24,17 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class UnboxNode extends FloatingNode implements Virtualizable, Lowerable, Canonicalizable {
+public class UnboxNode extends UnaryNode implements Virtualizable, Lowerable {
 
-    @Input private ValueNode value;
     private final Kind boxingKind;
 
     public UnboxNode(ValueNode value, Kind boxingKind) {
-        super(StampFactory.forKind(boxingKind.getStackKind()));
-        this.value = value;
+        super(StampFactory.forKind(boxingKind.getStackKind()), value);
         this.boxingKind = boxingKind;
     }
 
@@ -45,10 +42,6 @@
         return boxingKind;
     }
 
-    public ValueNode getValue() {
-        return value;
-    }
-
     @Override
     public void lower(LoweringTool tool) {
         tool.getLowerer().lower(this, tool);
@@ -56,7 +49,7 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(value);
+        State state = tool.getObjectState(getValue());
         if (state != null && state.getState() == EscapeState.Virtual) {
             ResolvedJavaType objectType = state.getVirtualObject().type();
             ResolvedJavaType expectedType = tool.getMetaAccessProvider().lookupJavaType(boxingKind.toBoxedJavaClass());
@@ -67,22 +60,19 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            Constant constant = value.asConstant();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            Constant constant = forValue.asConstant();
             Constant unboxed = tool.getConstantReflection().unboxPrimitive(constant);
             if (unboxed != null && unboxed.getKind() == boxingKind) {
-                return ConstantNode.forConstant(unboxed, tool.getMetaAccess(), graph());
+                return ConstantNode.forConstant(unboxed, tool.getMetaAccess());
             }
-        } else if (value instanceof BoxNode) {
-            BoxNode box = (BoxNode) value;
+        } else if (forValue instanceof BoxNode) {
+            BoxNode box = (BoxNode) forValue;
             if (boxingKind == box.getBoxingKind()) {
                 return box.getValue();
             }
         }
-        if (usages().isEmpty()) {
-            return null;
-        }
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -76,12 +76,12 @@
 
     @Override
     protected ValueNode cloneAsFieldAccess(ResolvedJavaField field) {
-        return this.graph().add(new LoadFieldNode(object(), field));
+        return new LoadFieldNode(object(), field);
     }
 
     @Override
     protected ValueNode cloneAsArrayAccess(ValueNode location, LocationIdentity identity) {
-        return this.graph().add(new UnsafeLoadNode(object(), location, accessKind(), identity));
+        return new UnsafeLoadNode(object(), location, accessKind(), identity);
     }
 
     @SuppressWarnings({"unchecked", "unused"})
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -41,9 +41,14 @@
     @Input(InputType.State) private FrameState stateAfter;
 
     public UnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, Kind accessKind, LocationIdentity locationIdentity) {
+        this(object, offset, value, accessKind, locationIdentity, null);
+    }
+
+    public UnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, Kind accessKind, LocationIdentity locationIdentity, FrameState stateAfter) {
         super(StampFactory.forVoid(), object, offset, accessKind, locationIdentity);
+        this.value = value;
+        this.stateAfter = stateAfter;
         assert accessKind != Kind.Void && accessKind != Kind.Illegal;
-        this.value = value;
     }
 
     public FrameState stateAfter() {
@@ -103,14 +108,12 @@
 
     @Override
     protected ValueNode cloneAsFieldAccess(ResolvedJavaField field) {
-        StoreFieldNode storeFieldNode = graph().add(new StoreFieldNode(object(), field, value()));
-        storeFieldNode.setStateAfter(stateAfter());
-        return storeFieldNode;
+        return new StoreFieldNode(object(), field, value(), stateAfter());
     }
 
     @Override
     protected ValueNode cloneAsArrayAccess(ValueNode location, LocationIdentity identity) {
-        return this.graph().add(new UnsafeStoreNode(object(), location, value, accessKind(), identity));
+        return new UnsafeStoreNode(object(), location, value, accessKind(), identity);
     }
 
     public FrameState getState() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -53,7 +53,7 @@
         } else {
             v = gen.operand(value());
         }
-        PlatformKind writeKind = gen.getLIRGeneratorTool().getPlatformKind(value().stamp());
+        LIRKind writeKind = gen.getLIRGeneratorTool().getLIRKind(value().stamp());
         gen.getLIRGeneratorTool().emitStore(writeKind, address, v, gen.state(this));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -33,7 +32,7 @@
 /**
  * The {@code ArrayLength} instruction gets the length of an array.
  */
-public final class ArrayLengthNode extends FixedWithNextNode implements Canonicalizable, Lowerable, Virtualizable {
+public final class ArrayLengthNode extends FixedWithNextNode implements Canonicalizable.Unary<ValueNode>, Lowerable, Virtualizable {
 
     @Input private ValueNode array;
 
@@ -41,14 +40,17 @@
         return array;
     }
 
+    public ValueNode getValue() {
+        return array;
+    }
+
     public ArrayLengthNode(ValueNode array) {
         super(StampFactory.positiveInt());
         this.array = array;
     }
 
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode length = readArrayLength(graph(), array(), tool.getConstantReflection());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode length = readArrayLength(forValue, tool.getConstantReflection());
         if (length != null) {
             return length;
         }
@@ -60,7 +62,7 @@
      *
      * @return a node representing the length of {@code array} or null if it is not available
      */
-    public static ValueNode readArrayLength(StructuredGraph graph, ValueNode originalArray, ConstantReflectionProvider constantReflection) {
+    public static ValueNode readArrayLength(ValueNode originalArray, ConstantReflectionProvider constantReflection) {
         ArrayLengthProvider foundArrayLengthProvider = null;
         ValueNode result = originalArray;
         while (true) {
@@ -87,7 +89,7 @@
             if (constantValue != null && constantValue.isNonNull()) {
                 Integer constantLength = constantReflection.readArrayLength(constantValue);
                 if (constantLength != null) {
-                    return ConstantNode.forInt(constantLength, graph);
+                    return ConstantNode.forInt(constantLength);
                 }
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.java;
 
 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.*;
@@ -33,7 +32,7 @@
  * Implements a type check where the type being checked is loaded at runtime. This is used, for
  * instance, to implement an object array store check.
  */
-public final class CheckCastDynamicNode extends FixedWithNextNode implements Canonicalizable, Lowerable {
+public final class CheckCastDynamicNode extends FixedWithNextNode implements Canonicalizable.Binary<ValueNode>, Lowerable {
 
     @Input private ValueNode object;
     @Input private ValueNode hub;
@@ -55,6 +54,25 @@
         this.forStoreCheck = forStoreCheck;
     }
 
+    public ValueNode object() {
+        return object;
+    }
+
+    /**
+     * Gets the runtime-loaded type being cast to.
+     */
+    public ValueNode hub() {
+        return hub;
+    }
+
+    public ValueNode getX() {
+        return object;
+    }
+
+    public ValueNode getY() {
+        return hub;
+    }
+
     public boolean isForStoreCheck() {
         return forStoreCheck;
     }
@@ -70,32 +88,19 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        assert object() != null : this;
-
-        if (StampTool.isObjectAlwaysNull(object())) {
-            return object();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forObject, ValueNode forHub) {
+        if (StampTool.isObjectAlwaysNull(forObject)) {
+            return forObject;
         }
-        if (hub.isConstant()) {
-            ResolvedJavaType t = tool.getConstantReflection().asJavaType(hub.asConstant());
+        if (forHub.isConstant()) {
+            ResolvedJavaType t = tool.getConstantReflection().asJavaType(forHub.asConstant());
             if (t != null) {
-                return graph().add(new CheckCastNode(t, object(), null, forStoreCheck));
+                return new CheckCastNode(t, forObject, null, forStoreCheck);
             }
         }
         return this;
     }
 
-    public ValueNode object() {
-        return object;
-    }
-
-    /**
-     * Gets the runtime-loaded type being cast to.
-     */
-    public ValueNode hub() {
-        return hub;
-    }
-
     @NodeIntrinsic
     public static native <T> T checkCastDynamic(Class<T> type, Object object, @ConstantNodeParameter boolean forStoreCheck);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,7 @@
 /**
  * Implements a type check against a compile-time known type.
  */
-public class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Lowerable, Virtualizable, ValueProxy {
+public class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Simplifiable, Lowerable, Virtualizable, ValueProxy {
 
     @Input private ValueNode object;
     private final ResolvedJavaType type;
@@ -141,8 +141,6 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        assert object() != null : this;
-
         ResolvedJavaType objectType = StampTool.typeOrNull(object());
         if (objectType != null && type.isAssignableFrom(objectType)) {
             // we don't have to check for null types here because they will also pass the
@@ -150,6 +148,24 @@
             return object();
         }
 
+        if (StampTool.isObjectAlwaysNull(object())) {
+            return object();
+        }
+
+        if (tool.assumptions() != null && tool.assumptions().useOptimisticAssumptions()) {
+            ResolvedJavaType exactType = type.findUniqueConcreteSubtype();
+            if (exactType != null && !exactType.equals(type)) {
+                // Propagate more precise type information to usages of the checkcast.
+                tool.assumptions().recordConcreteSubtype(type, exactType);
+                return new CheckCastNode(exactType, object, profile, forStoreCheck);
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
         // if the previous node is also a checkcast, with a less precise and compatible type,
         // replace both with one checkcast checking the more specific type.
         if (predecessor() instanceof CheckCastNode) {
@@ -158,23 +174,10 @@
                 StructuredGraph graph = ccn.graph();
                 CheckCastNode newccn = graph.add(new CheckCastNode(type, ccn.object, ccn.profile, ccn.forStoreCheck));
                 graph.replaceFixedWithFixed(ccn, newccn);
-                return newccn;
+                replaceAtUsages(newccn);
+                graph.removeFixed(this);
             }
         }
-
-        if (StampTool.isObjectAlwaysNull(object())) {
-            return object();
-        }
-        if (tool.assumptions() != null && tool.assumptions().useOptimisticAssumptions()) {
-            ResolvedJavaType exactType = type.findUniqueConcreteSubtype();
-            if (exactType != null && !exactType.equals(type)) {
-                // Propagate more precise type information to usages of the checkcast.
-                tool.assumptions().recordConcreteSubtype(type, exactType);
-                return graph().add(new CheckCastNode(exactType, object, profile, forStoreCheck));
-            }
-        }
-
-        return this;
     }
 
     public ValueNode object() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+//JaCoCo Exclude
 package com.oracle.graal.nodes.java;
 
 import java.lang.reflect.*;
@@ -57,7 +58,8 @@
         if (isAlive() && elementType.isConstant()) {
             ResolvedJavaType javaType = tool.getConstantReflection().asJavaType(elementType.asConstant());
             if (javaType != null && !javaType.equals(tool.getMetaAccess().lookupJavaType(void.class))) {
-                NewArrayNode newArray = graph().add(new NewArrayNode(javaType, length(), fillContents()));
+                ValueNode length = length();
+                NewArrayNode newArray = graph().add(new NewArrayNode(javaType, length.isAlive() ? length : graph().addOrUniqueWithInputs(length), fillContents()));
                 List<Node> snapshot = inputs().snapshot();
                 graph().replaceFixedWithFixed(this, newArray);
                 for (Node input : snapshot) {
@@ -72,4 +74,12 @@
     public static Object newArray(Class<?> componentType, int length) {
         return Array.newInstance(componentType, length);
     }
+
+    @NodeIntrinsic
+    private static native Object newArray(Class<?> componentType, int length, @ConstantNodeParameter boolean fillContents);
+
+    public static Object newUninitializedArray(Class<?> componentType, int length) {
+        return newArray(componentType, length, false);
+    }
+
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -42,7 +42,7 @@
         if (clazz.isConstant()) {
             ResolvedJavaType type = tool.getConstantReflection().asJavaType(clazz.asConstant());
             if (type != null && type.isInitialized()) {
-                return graph().add(new NewInstanceNode(type, fillContents()));
+                return new NewInstanceNode(type, fillContents());
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.java;
 
 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.*;
@@ -34,7 +33,7 @@
  * known at compile time. This is used, for instance, to intrinsify {@link Class#isInstance(Object)}
  * .
  */
-public final class InstanceOfDynamicNode extends LogicNode implements Canonicalizable, Lowerable {
+public final class InstanceOfDynamicNode extends LogicNode implements Canonicalizable.Binary<ValueNode>, Lowerable {
 
     @Input private ValueNode object;
     @Input private ValueNode mirror;
@@ -56,16 +55,14 @@
         tool.getLowerer().lower(this, tool);
     }
 
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        assert object() != null : this;
-        if (mirror().isConstant()) {
-            ResolvedJavaType t = tool.getConstantReflection().asJavaType(mirror().asConstant());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forObject, ValueNode forMirror) {
+        if (forMirror.isConstant()) {
+            ResolvedJavaType t = tool.getConstantReflection().asJavaType(forMirror.asConstant());
             if (t != null) {
                 if (t.isPrimitive()) {
-                    return LogicConstantNode.contradiction(graph());
+                    return LogicConstantNode.contradiction();
                 } else {
-                    return graph().unique(new InstanceOfNode(t, object(), null));
+                    return new InstanceOfNode(t, forObject, null);
                 }
             }
         }
@@ -79,4 +76,12 @@
     public ValueNode mirror() {
         return mirror;
     }
+
+    public ValueNode getX() {
+        return object;
+    }
+
+    public ValueNode getY() {
+        return mirror;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,9 +23,7 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -34,7 +32,7 @@
 /**
  * The {@code InstanceOfNode} represents an instanceof test.
  */
-public class InstanceOfNode extends UnaryOpLogicNode implements Canonicalizable, Lowerable, Virtualizable {
+public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
 
     private final ResolvedJavaType type;
     private JavaTypeProfile profile;
@@ -58,40 +56,14 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        switch (evaluate(object())) {
-            case FALSE:
-                return LogicConstantNode.contradiction(graph());
-            case TRUE:
-                return LogicConstantNode.tautology(graph());
-            case UNKNOWN:
-                Stamp stamp = object().stamp();
-                if (stamp instanceof ObjectStamp) {
-                    ObjectStamp objectStamp = (ObjectStamp) stamp;
-                    ResolvedJavaType stampType = objectStamp.type();
-                    if (stampType != null && type().isAssignableFrom(stampType)) {
-                        if (!objectStamp.nonNull()) {
-                            // the instanceof matches if the object is non-null, so return true
-                            // depending on the null-ness.
-                            IsNullNode isNull = graph().unique(new IsNullNode(object()));
-                            return graph().unique(new LogicNegationNode(isNull));
-                        }
-                    }
-                }
-                return this;
-        }
-        return this;
-    }
-
-    @Override
-    public TriState evaluate(ValueNode forObject) {
-        Stamp stamp = forObject.stamp();
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        Stamp stamp = forValue.stamp();
         if (!(stamp instanceof ObjectStamp)) {
-            return TriState.UNKNOWN;
+            return this;
         }
         ObjectStamp objectStamp = (ObjectStamp) stamp;
         if (objectStamp.alwaysNull()) {
-            return TriState.FALSE;
+            return LogicConstantNode.contradiction();
         }
 
         ResolvedJavaType stampType = objectStamp.type();
@@ -100,25 +72,32 @@
             if (subType) {
                 if (objectStamp.nonNull()) {
                     // the instanceOf matches, so return true
-                    return TriState.TRUE;
+                    return LogicConstantNode.tautology();
                 }
             } else {
                 if (objectStamp.isExactType()) {
                     // since this type check failed for an exact type we know that it can never
                     // succeed at run time. we also don't care about null values, since they will
                     // also make the check fail.
-                    return TriState.FALSE;
+                    return LogicConstantNode.contradiction();
                 } else {
                     boolean superType = stampType.isAssignableFrom(type());
                     if (!superType && !stampType.isInterface() && !type().isInterface()) {
-                        return TriState.FALSE;
+                        return LogicConstantNode.contradiction();
                     }
                     // since the subtype comparison was only performed on a declared type we don't
                     // really know if it might be true at run time...
                 }
             }
         }
-        return TriState.UNKNOWN;
+        if (stampType != null && type().isAssignableFrom(stampType)) {
+            if (!objectStamp.nonNull()) {
+                // the instanceof matches if the object is non-null, so return true
+                // depending on the null-ness.
+                return new LogicNegationNode(new IsNullNode(forValue));
+            }
+        }
+        return this;
     }
 
     /**
@@ -138,7 +117,7 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object());
+        State state = tool.getObjectState(getValue());
         if (state != null) {
             tool.replaceWithValue(LogicConstantNode.forBoolean(type().isAssignableFrom(state.getVirtualObject().type()), graph()));
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,7 @@
  * The {@code LoadFieldNode} represents a read of a static or instance field.
  */
 @NodeInfo(nameTemplate = "LoadField#{p#field/s}")
-public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable, VirtualizableRoot {
+public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable.Unary<ValueNode>, VirtualizableRoot {
 
     /**
      * Creates a new LoadFieldNode instance.
@@ -49,6 +49,10 @@
         super(createStamp(field), object, field);
     }
 
+    public ValueNode getValue() {
+        return object();
+    }
+
     private static Stamp createStamp(ResolvedJavaField field) {
         Kind kind = field.getKind();
         if (kind == Kind.Object && field.getType() instanceof ResolvedJavaType) {
@@ -58,24 +62,23 @@
         }
     }
 
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (usages().isEmpty() && !isVolatile() && (isStatic() || StampTool.isObjectNonNull(object().stamp()))) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forObject) {
+        if (usages().isEmpty() && !isVolatile() && (isStatic() || StampTool.isObjectNonNull(forObject.stamp()))) {
             return null;
         }
         MetaAccessProvider metaAccess = tool.getMetaAccess();
         if (tool.canonicalizeReads() && metaAccess != null) {
-            ConstantNode constant = asConstant(metaAccess);
+            ConstantNode constant = asConstant(metaAccess, forObject);
             if (constant != null) {
                 return constant;
             }
-            PhiNode phi = asPhi(metaAccess);
+            PhiNode phi = asPhi(metaAccess, forObject);
             if (phi != null) {
                 return phi;
             }
         }
-        if (!isStatic() && object().isNullConstant()) {
-            return graph().add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.NullCheckException));
+        if (!isStatic() && forObject.isNullConstant()) {
+            return new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.NullCheckException);
         }
         return this;
     }
@@ -83,22 +86,22 @@
     /**
      * Gets a constant value for this load if possible.
      */
-    public ConstantNode asConstant(MetaAccessProvider metaAccess) {
+    public ConstantNode asConstant(MetaAccessProvider metaAccess, ValueNode forObject) {
         Constant constant = null;
         if (isStatic()) {
             constant = field().readConstantValue(null);
-        } else if (object().isConstant() && !object().isNullConstant()) {
-            constant = field().readConstantValue(object().asConstant());
+        } else if (forObject.isConstant() && !forObject.isNullConstant()) {
+            constant = field().readConstantValue(forObject.asConstant());
         }
         if (constant != null) {
-            return ConstantNode.forConstant(constant, metaAccess, graph());
+            return ConstantNode.forConstant(constant, metaAccess);
         }
         return null;
     }
 
-    private PhiNode asPhi(MetaAccessProvider metaAccess) {
-        if (!isStatic() && field.isFinal() && object() instanceof ValuePhiNode && ((ValuePhiNode) object()).values().filter(isNotA(ConstantNode.class)).isEmpty()) {
-            PhiNode phi = (PhiNode) object();
+    private PhiNode asPhi(MetaAccessProvider metaAccess, ValueNode forObject) {
+        if (!isStatic() && field.isFinal() && forObject instanceof ValuePhiNode && ((ValuePhiNode) forObject).values().filter(isNotA(ConstantNode.class)).isEmpty()) {
+            PhiNode phi = (PhiNode) forObject;
             Constant[] constants = new Constant[phi.valueCount()];
             for (int i = 0; i < phi.valueCount(); i++) {
                 Constant constantValue = field().readConstantValue(phi.valueAt(i).asConstant());
@@ -107,11 +110,11 @@
                 }
                 constants[i] = constantValue;
             }
-            PhiNode newPhi = graph().addWithoutUnique(new ValuePhiNode(stamp(), phi.merge()));
+            ConstantNode[] constantNodes = new ConstantNode[phi.valueCount()];
             for (int i = 0; i < phi.valueCount(); i++) {
-                newPhi.addInput(ConstantNode.forConstant(constants[i], metaAccess, graph()));
+                constantNodes[i] = ConstantNode.forConstant(constants[i], metaAccess);
             }
-            return newPhi;
+            return new ValuePhiNode(stamp(), phi.merge(), constantNodes);
         }
         return null;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -141,9 +141,12 @@
             ValueNode receiver = receiver();
             ResolvedJavaType type = StampTool.typeOrNull(receiver);
             if (type != null && (invoke().stateAfter() != null || invoke().stateDuring() != null)) {
-                // either the holder class is exact, or the receiver object has an exact type
+                /*
+                 * either the holder class is exact, or the receiver object has an exact type, or
+                 * it's an array type
+                 */
                 ResolvedJavaMethod resolvedMethod = type.resolveMethod(targetMethod, invoke().getContextType());
-                if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || StampTool.isExactType(receiver))) {
+                if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || StampTool.isExactType(receiver) || type.isArray())) {
                     invokeKind = InvokeKind.Special;
                     targetMethod = resolvedMethod;
                     return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -39,7 +39,7 @@
 
     /**
      * Constructs a new NewArrayNode.
-     * 
+     *
      * @param elementType the the type of the elements of the newly created array (not the type of
      *            the array itself).
      * @param length the node that produces the length for this allocation.
@@ -49,9 +49,16 @@
         super(StampFactory.exactNonNull(elementType.getArrayClass()), length, fillContents);
     }
 
+    @NodeIntrinsic
+    static private native Object newArray(@ConstantNodeParameter Class<?> elementType, int length, @ConstantNodeParameter boolean fillContents);
+
+    public static Object newUninitializedArray(Class<?> elementType, int length) {
+        return newArray(elementType, length, false);
+    }
+
     /**
      * Gets the element type of the array.
-     * 
+     *
      * @return the element type of the array
      */
     public ResolvedJavaType elementType() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -35,33 +35,33 @@
  * This node is used to perform the finalizer registration at the end of the java.lang.Object
  * constructor.
  */
-public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode.DeoptAfter {
+public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable.Unary<ValueNode>, LIRLowerable, Virtualizable, DeoptimizingNode.DeoptAfter {
 
     @Input(InputType.State) private FrameState deoptState;
-    @Input private ValueNode object;
+    @Input private ValueNode value;
 
-    public ValueNode object() {
-        return object;
+    public RegisterFinalizerNode(ValueNode value) {
+        super(StampFactory.forVoid());
+        this.value = value;
     }
 
-    public RegisterFinalizerNode(ValueNode object) {
-        super(StampFactory.forVoid());
-        this.object = object;
+    public ValueNode getValue() {
+        return value;
     }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(REGISTER_FINALIZER);
-        gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(object()));
+        gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(getValue()));
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (!(object.stamp() instanceof ObjectStamp)) {
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (!(forValue.stamp() instanceof ObjectStamp)) {
             return this;
         }
 
-        ObjectStamp stamp = (ObjectStamp) object.stamp();
+        ObjectStamp stamp = (ObjectStamp) forValue.stamp();
 
         boolean needsCheck = true;
         if (stamp.isExactType()) {
@@ -84,7 +84,7 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
+        State state = tool.getObjectState(getValue());
         if (state != null && !state.getVirtualObject().type().hasFinalizer()) {
             tool.delete();
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -68,6 +68,12 @@
         this.value = value;
     }
 
+    public StoreFieldNode(ValueNode object, ResolvedJavaField field, ValueNode value, FrameState stateAfter) {
+        super(StampFactory.forVoid(), object, field);
+        this.value = value;
+        this.stateAfter = stateAfter;
+    }
+
     @Override
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -121,8 +121,8 @@
             tool.addToWorkList(blockSuccessor(survivingEdge));
             graph().removeSplit(this, blockSuccessor(survivingEdge));
         }
-        if (value() instanceof LoadHubNode && ((LoadHubNode) value()).object().stamp() instanceof ObjectStamp) {
-            ObjectStamp stamp = (ObjectStamp) ((LoadHubNode) value()).object().stamp();
+        if (value() instanceof LoadHubNode && ((LoadHubNode) value()).getValue().stamp() instanceof ObjectStamp) {
+            ObjectStamp stamp = (ObjectStamp) ((LoadHubNode) value()).getValue().stamp();
             if (stamp.type() != null) {
                 int validKeys = 0;
                 for (int i = 0; i < keyCount(); i++) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Mon Jun 30 12:02:19 2014 +0200
@@ -68,13 +68,5 @@
 
     Value[] visitInvokeArguments(CallingConvention cc, Collection<ValueNode> arguments);
 
-    Variable newVariable(Kind kind);
-
-    void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
-
-    void emitBitCount(Variable result, Value operand);
-
-    void emitBitScanForward(Variable result, Value operand);
-
     void doBlock(Block block, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Mon Jun 30 12:02:19 2014 +0200
@@ -114,25 +114,20 @@
 
     public static Stamp rem(IntegerStamp stamp1, IntegerStamp stamp2) {
         assert stamp1.getBits() == stamp2.getBits();
-        long magnitude; // the maximum absolute value of the result
+        // zero is always possible
+        long lowerBound = Math.min(stamp1.lowerBound(), 0);
+        long upperBound = Math.max(stamp1.upperBound(), 0);
+
+        long magnitude; // the maximum absolute value of the result, derived from stamp2
         if (stamp2.lowerBound() == IntegerStamp.defaultMinValue(stamp2.getBits())) {
             // Math.abs(...) - 1 does not work in this case
             magnitude = IntegerStamp.defaultMaxValue(stamp2.getBits());
         } else {
             magnitude = Math.max(Math.abs(stamp2.lowerBound()), Math.abs(stamp2.upperBound())) - 1;
         }
-        long lowerBound = Math.max(stamp1.lowerBound(), -magnitude);
-        if (stamp1.upperBound() > magnitude) {
-            // if the result can wrap around at the upper bound, it can reach any value between 0
-            // and magnitude
-            lowerBound = Math.min(lowerBound, 0);
-        }
-        long upperBound = Math.min(stamp1.upperBound(), magnitude);
-        if (stamp1.lowerBound() < -magnitude) {
-            // if the result can wrap around at the lower bound, it can reach any value between
-            // -magnitude and 0
-            upperBound = Math.max(upperBound, 0);
-        }
+        lowerBound = Math.max(lowerBound, -magnitude);
+        upperBound = Math.min(upperBound, magnitude);
+
         return StampFactory.forInteger(stamp1.getBits(), lowerBound, upperBound);
     }
 
@@ -200,7 +195,7 @@
         return add(stamp1, (IntegerStamp) StampTool.negate(stamp2));
     }
 
-    private static Stamp stampForMask(int bits, long downMask, long upMask) {
+    public static Stamp stampForMask(int bits, long downMask, long upMask) {
         long lowerBound;
         long upperBound;
         if (((upMask >>> (bits - 1)) & 1) == 0) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Mon Jun 30 12:02:19 2014 +0200
@@ -94,13 +94,13 @@
             } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) {
                 // not a loop anymore
                 if (tool != null) {
-                    merge.phis().forEach(phi -> phi.usages().forEach(tool::addToWorkList));
+                    merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
                 }
                 graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
             } else if (merge.phiPredecessorCount() == 1) {
                 // not a merge anymore
                 if (tool != null) {
-                    merge.phis().forEach(phi -> phi.usages().forEach(tool::addToWorkList));
+                    merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
                 }
                 graph.reduceTrivialMerge(merge);
             }
@@ -181,6 +181,9 @@
     }
 
     public static void checkRedundantProxy(ProxyNode vpn) {
+        if (vpn.isDeleted()) {
+            return;
+        }
         BeginNode proxyPoint = vpn.proxyPoint();
         if (proxyPoint instanceof LoopExitNode) {
             LoopExitNode exit = (LoopExitNode) proxyPoint;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -146,6 +146,6 @@
     }
 
     public ValueNode length() {
-        return ConstantNode.forInt(length, graph());
+        return ConstantNode.forInt(length);
     }
 }
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionDescriptor.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionDescriptor.java	Mon Jun 30 12:02:19 2014 +0200
@@ -42,11 +42,13 @@
         this.option = option;
         this.declaringClass = declaringClass;
         this.fieldName = fieldName;
+        assert !type.isPrimitive() : "must used boxed type instead of " + type;
         option.setDescriptor(this);
     }
 
     /**
-     * Gets the type of values stored in the option.
+     * Gets the type of values stored in the option. This will be the boxed type for a primitive
+     * option.
      */
     public Class<?> getType() {
         return type;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -27,8 +27,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.Mark;
-import com.oracle.graal.graph.Graph.NodeChangedListener;
+import com.oracle.graal.graph.Graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -64,6 +63,10 @@
         this.customCanonicalizer = customCanonicalizer;
     }
 
+    public boolean getCanonicalizeReads() {
+        return canonicalizeReads;
+    }
+
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
         new Instance(context, canonicalizeReads, customCanonicalizer).run(graph);
@@ -150,22 +153,26 @@
         }
 
         private void processWorkSet(StructuredGraph graph) {
-            NodeChangedListener nodeChangedListener = new NodeChangedListener() {
+            NodeEventListener listener = new NodeEventListener() {
 
-                @Override
-                public void nodeChanged(Node node) {
+                public void nodeAdded(Node node) {
+                    workList.add(node);
+                }
+
+                public void inputChanged(Node node) {
                     workList.add(node);
                 }
-            };
-            graph.trackInputChange(nodeChangedListener);
-            graph.trackUsagesDroppedZero(nodeChangedListener);
+
+                public void usagesDroppedToZero(Node node) {
+                    workList.add(node);
+                }
 
-            for (Node n : workList) {
-                processNode(n);
+            };
+            try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+                for (Node n : workList) {
+                    processNode(n);
+                }
             }
-
-            graph.stopTrackingInputChange();
-            graph.stopTrackingUsagesDroppedZero();
         }
 
         private void processNode(Node node) {
@@ -177,7 +184,6 @@
                     return;
                 }
                 StructuredGraph graph = (StructuredGraph) node.graph();
-                Mark mark = graph.getMark();
                 if (!GraphUtil.tryKillUnused(node)) {
                     if (!tryCanonicalize(node, nodeClass)) {
                         if (node instanceof ValueNode) {
@@ -196,10 +202,6 @@
                         }
                     }
                 }
-
-                for (Node newNode : graph.getNewNodes(mark)) {
-                    workList.add(newNode);
-                }
             }
         }
 
@@ -227,12 +229,35 @@
             return result;
         }
 
+        private static AutoCloseable getCanonicalizeableContractAssertion(Node node) {
+            boolean needsAssertion = false;
+            assert (needsAssertion = true) == true;
+            if (needsAssertion) {
+                Mark mark = node.graph().getMark();
+                return () -> {
+                    assert mark.equals(node.graph().getMark()) : "new node created while canonicalizing " + node.getClass().getSimpleName() + " " + node + ": " +
+                                    node.graph().getNewNodes(mark).snapshot();
+                };
+            } else {
+                return new AutoCloseable() {
+                    public void close() throws Exception {
+                        // nothing to do
+                    }
+                };
+            }
+        }
+
         public boolean baseTryCanonicalize(final Node node, NodeClass nodeClass) {
             if (nodeClass.isCanonicalizable()) {
                 METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
                 try (Scope s = Debug.scope("CanonicalizeNode", node)) {
-                    Node canonical = node.canonical(tool);
-                    return performReplacement(node, canonical);
+                    Node canonical;
+                    try (AutoCloseable verify = getCanonicalizeableContractAssertion(node)) {
+                        canonical = ((Canonicalizable) node).canonical(tool);
+                    }
+                    if (performReplacement(node, canonical)) {
+                        return true;
+                    }
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
@@ -246,8 +271,9 @@
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
+                return node.isDeleted();
             }
-            return node.isDeleted();
+            return false;
         }
 
 // @formatter:off
@@ -266,17 +292,23 @@
 //                                         --------------------------------------------
 //       X: must not happen (checked with assertions)
 // @formatter:on
-        private boolean performReplacement(final Node node, Node canonical) {
-            if (canonical == node) {
+        private boolean performReplacement(final Node node, Node newCanonical) {
+            if (newCanonical == node) {
                 Debug.log("Canonicalizer: work on %1s", node);
                 return false;
             } else {
+                Node canonical = newCanonical;
                 Debug.log("Canonicalizer: replacing %1s with %1s", node, canonical);
                 METRIC_CANONICALIZED_NODES.increment();
                 StructuredGraph graph = (StructuredGraph) node.graph();
+                if (canonical != null && !canonical.isAlive()) {
+                    assert !canonical.isDeleted();
+                    canonical = graph.addOrUniqueWithInputs(canonical);
+                }
                 if (node instanceof FloatingNode) {
                     if (canonical == null) {
                         // case 1
+                        node.replaceAtUsages(null);
                         graph.removeFloating((FloatingNode) node);
                     } else {
                         // case 2
@@ -301,6 +333,7 @@
                         tool.addToWorkList(fixedWithNext.next());
                         if (canonical == null) {
                             // case 3
+                            node.replaceAtUsages(null);
                             graph.removeFixed(fixedWithNext);
                         } else if (canonical instanceof FloatingNode) {
                             // case 4
@@ -376,6 +409,10 @@
                 workList.add(node);
             }
 
+            public void addToWorkList(Iterable<? extends Node> nodes) {
+                workList.addAll(nodes);
+            }
+
             @Override
             public void removeIfUnused(Node node) {
                 GraphUtil.tryKillUnused(node);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CleanTypeProfileProxyPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CleanTypeProfileProxyPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,7 +30,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         for (TypeProfileProxyNode proxy : graph.getNodes(TypeProfileProxyNode.class)) {
-            graph.replaceFloating(proxy, proxy.getObject());
+            graph.replaceFloating(proxy, proxy.getValue());
         }
         assert graph.getNodes(TypeProfileProxyNode.class).count() == 0;
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -373,16 +373,16 @@
 
             if (isTrue && condition instanceof InstanceOfNode) {
                 InstanceOfNode instanceOf = (InstanceOfNode) condition;
-                ValueNode object = instanceOf.object();
+                ValueNode object = instanceOf.getValue();
                 state.addNullness(false, object);
                 state.addType(instanceOf.type(), object);
             } else if (condition instanceof IsNullNode) {
                 IsNullNode nullCheck = (IsNullNode) condition;
-                state.addNullness(isTrue, nullCheck.object());
+                state.addNullness(isTrue, nullCheck.getValue());
             } else if (condition instanceof ObjectEqualsNode) {
                 ObjectEqualsNode equals = (ObjectEqualsNode) condition;
-                ValueNode x = equals.x();
-                ValueNode y = equals.y();
+                ValueNode x = equals.getX();
+                ValueNode y = equals.getY();
                 if (isTrue) {
                     if (state.isNull(x) && !state.isNull(y)) {
                         metricObjectEqualsRegistered.increment();
@@ -438,8 +438,8 @@
                         }
                     }
                     if (type != null) {
-                        state.addNullness(false, loadHub.object());
-                        state.addType(type, loadHub.object());
+                        state.addNullness(false, loadHub.getValue());
+                        state.addType(type, loadHub.getValue());
                     }
                 }
             }
@@ -452,16 +452,16 @@
                     return null;
                 }
                 IntegerBelowThanNode below = (IntegerBelowThanNode) guard.condition();
-                if (below.x().getKind() == Kind.Int && below.x().isConstant() && !below.y().isConstant()) {
-                    Stamp stamp = StampTool.unsignedCompare(below.x().stamp(), below.y().stamp());
+                if (below.getX().getKind() == Kind.Int && below.getX().isConstant() && !below.getY().isConstant()) {
+                    Stamp stamp = StampTool.unsignedCompare(below.getX().stamp(), below.getY().stamp());
                     if (stamp != null) {
-                        return new GuardedStamp(below.y(), stamp, guard);
+                        return new GuardedStamp(below.getY(), stamp, guard);
                     }
                 }
-                if (below.y().getKind() == Kind.Int && below.y().isConstant() && !below.x().isConstant()) {
-                    Stamp stamp = StampTool.unsignedCompare(below.x().stamp(), below.y().stamp());
+                if (below.getY().getKind() == Kind.Int && below.getY().isConstant() && !below.getX().isConstant()) {
+                    Stamp stamp = StampTool.unsignedCompare(below.getX().stamp(), below.getY().stamp());
                     if (stamp != null) {
-                        return new GuardedStamp(below.x(), stamp, guard);
+                        return new GuardedStamp(below.getX(), stamp, guard);
                     }
                 }
             }
@@ -522,13 +522,13 @@
             GuardNode existingGuard = null;
             if (guard.condition() instanceof IntegerBelowThanNode) {
                 IntegerBelowThanNode below = (IntegerBelowThanNode) guard.condition();
-                IntegerStamp xStamp = (IntegerStamp) below.x().stamp();
-                IntegerStamp yStamp = (IntegerStamp) below.y().stamp();
-                GuardedStamp cstamp = state.valueConstraints.get(below.x());
+                IntegerStamp xStamp = (IntegerStamp) below.getX().stamp();
+                IntegerStamp yStamp = (IntegerStamp) below.getY().stamp();
+                GuardedStamp cstamp = state.valueConstraints.get(below.getX());
                 if (cstamp != null) {
                     xStamp = (IntegerStamp) cstamp.getStamp();
                 } else {
-                    cstamp = state.valueConstraints.get(below.y());
+                    cstamp = state.valueConstraints.get(below.getY());
                     if (cstamp != null) {
                         yStamp = (IntegerStamp) cstamp.getStamp();
                     }
@@ -552,10 +552,10 @@
                 }
             } else if (guard.condition() instanceof IntegerEqualsNode && guard.negated()) {
                 IntegerEqualsNode equals = (IntegerEqualsNode) guard.condition();
-                GuardedStamp cstamp = state.valueConstraints.get(equals.y());
-                if (cstamp != null && equals.x().isConstant()) {
+                GuardedStamp cstamp = state.valueConstraints.get(equals.getY());
+                if (cstamp != null && equals.getX().isConstant()) {
                     IntegerStamp stamp = (IntegerStamp) cstamp.getStamp();
-                    if (!stamp.contains(equals.x().asConstant().asLong())) {
+                    if (!stamp.contains(equals.getX().asConstant().asLong())) {
                         // x != n is true if n is outside the range of the stamp
                         existingGuard = cstamp.getGuard();
                         Debug.log("existing guard %s %1s proves !%1s", existingGuard, existingGuard.condition(), guard.condition());
@@ -620,7 +620,7 @@
             } else {
                 if (condition instanceof InstanceOfNode) {
                     InstanceOfNode instanceOf = (InstanceOfNode) condition;
-                    ValueNode object = instanceOf.object();
+                    ValueNode object = instanceOf.getValue();
                     if (state.isNull(object)) {
                         metricInstanceOfRemoved.increment();
                         return falseValue;
@@ -633,7 +633,7 @@
                     }
                 } else if (condition instanceof IsNullNode) {
                     IsNullNode isNull = (IsNullNode) condition;
-                    ValueNode object = isNull.object();
+                    ValueNode object = isNull.getValue();
                     if (state.isNull(object)) {
                         metricNullCheckRemoved.increment();
                         return trueValue;
@@ -643,8 +643,8 @@
                     }
                 } else if (condition instanceof ObjectEqualsNode) {
                     ObjectEqualsNode equals = (ObjectEqualsNode) condition;
-                    ValueNode x = equals.x();
-                    ValueNode y = equals.y();
+                    ValueNode x = equals.getX();
+                    ValueNode y = equals.getY();
                     if (state.isNull(x) && state.isNonNull(y) || state.isNonNull(x) && state.isNull(y)) {
                         metricObjectEqualsRemoved.increment();
                         return falseValue;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -71,11 +71,11 @@
                     CompareNode compare = (CompareNode) fixedGuard.condition();
                     List<AbstractEndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
 
-                    Constant[] xs = IfNode.constantValues(compare.x(), merge, true);
+                    Constant[] xs = IfNode.constantValues(compare.getX(), merge, true);
                     if (xs == null) {
                         continue;
                     }
-                    Constant[] ys = IfNode.constantValues(compare.y(), merge, true);
+                    Constant[] ys = IfNode.constantValues(compare.getY(), merge, true);
                     if (ys == null) {
                         continue;
                     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -33,7 +33,7 @@
     private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved");
 
     @Override
-    protected void run(StructuredGraph graph) {
+    public void run(StructuredGraph graph) {
         NodeFlood flood = graph.createNodeFlood();
 
         flood.add(graph.start());
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -42,7 +42,7 @@
         CREATE_FLOATING_READS
     }
 
-    public static class MemoryMapImpl extends MemoryMapNode {
+    public static class MemoryMapImpl implements MemoryMap {
 
         private final Map<LocationIdentity, MemoryNode> lastMemorySnapshot;
 
@@ -74,33 +74,13 @@
             }
         }
 
-        public boolean isEmpty() {
-            if (lastMemorySnapshot.size() == 0) {
-                return true;
-            }
-            if (lastMemorySnapshot.size() == 1) {
-                if (lastMemorySnapshot.get(ANY_LOCATION) instanceof StartNode) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
         @Override
-        public Set<LocationIdentity> getLocations() {
+        public Collection<LocationIdentity> getLocations() {
             return lastMemorySnapshot.keySet();
         }
 
-        @Override
-        public boolean replaceLastLocationAccess(MemoryNode oldNode, MemoryNode newNode) {
-            boolean replaced = false;
-            for (Map.Entry<LocationIdentity, MemoryNode> entry : lastMemorySnapshot.entrySet()) {
-                if (entry.getValue() == oldNode) {
-                    entry.setValue(newNode);
-                    replaced = true;
-                }
-            }
-            return replaced;
+        public Map<LocationIdentity, MemoryNode> getMap() {
+            return lastMemorySnapshot;
         }
     }
 
@@ -125,11 +105,11 @@
         }
     }
 
-    public static MemoryMapImpl mergeMemoryMaps(MergeNode merge, List<? extends MemoryMapNode> states) {
+    public static MemoryMapImpl mergeMemoryMaps(MergeNode merge, List<? extends MemoryMap> states) {
         MemoryMapImpl newState = new MemoryMapImpl();
 
         Set<LocationIdentity> keys = new HashSet<>();
-        for (MemoryMapNode other : states) {
+        for (MemoryMap other : states) {
             keys.addAll(other.getLocations());
         }
         assert !keys.contains(FINAL_LOCATION);
@@ -138,7 +118,7 @@
             int mergedStatesCount = 0;
             boolean isPhi = false;
             MemoryNode merged = null;
-            for (MemoryMapNode state : states) {
+            for (MemoryMap state : states) {
                 MemoryNode last = state.getLastLocationAccess(key);
                 if (isPhi) {
                     merged.asMemoryPhi().addInput(ValueNodeUtil.asNode(last));
@@ -243,7 +223,7 @@
             assert MemoryCheckpoint.TypeAssertion.correctType(node) : node;
 
             if (execmode == ExecutionMode.ANALYSIS_ONLY && node instanceof ReturnNode) {
-                ((ReturnNode) node).setMemoryMap(node.graph().unique(new MemoryMapImpl(state)));
+                ((ReturnNode) node).setMemoryMap(node.graph().unique(new MemoryMapNode(state.lastMemorySnapshot)));
             }
             return state;
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -117,7 +117,7 @@
         private void processGuard(Node node) {
             GuardNode guard = (GuardNode) node;
             if (guard.negated() && guard.condition() instanceof IsNullNode && (guard.getSpeculation() == null || guard.getSpeculation().equals(Constant.NULL_OBJECT))) {
-                ValueNode obj = ((IsNullNode) guard.condition()).object();
+                ValueNode obj = ((IsNullNode) guard.condition()).getValue();
                 nullGuarded.put(obj, guard);
             }
         }
@@ -158,7 +158,7 @@
             StructuredGraph graph = guard.graph();
             BeginNode fastPath = graph.add(new BeginNode());
             @SuppressWarnings("deprecation")
-            DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.action(), guard.reason(), useGuardIdAsDebugId ? guard.getId() : 0, guard.getSpeculation()));
+            DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.action(), guard.reason(), useGuardIdAsDebugId ? guard.getId() : 0, guard.getSpeculation(), null));
             BeginNode deoptBranch = BeginNode.begin(deopt);
             BeginNode trueSuccessor;
             BeginNode falseSuccessor;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.phases.common;
 
-import com.oracle.graal.graph.Graph.Mark;
+import com.oracle.graal.graph.Graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.util.*;
@@ -47,19 +47,13 @@
 
     @Override
     protected void run(StructuredGraph graph, C context) {
-        Mark newNodesMark = graph.getMark();
-
-        HashSetNodeChangeListener listener = new HashSetNodeChangeListener();
-        graph.trackInputChange(listener);
-        graph.trackUsagesDroppedZero(listener);
+        HashSetNodeEventListener listener = new HashSetNodeEventListener();
+        try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+            super.run(graph, context);
+        }
 
-        super.run(graph, context);
-
-        graph.stopTrackingInputChange();
-        graph.stopTrackingUsagesDroppedZero();
-
-        if (graph.getMark() != newNodesMark || !listener.getChangedNodes().isEmpty()) {
-            canonicalizer.applyIncremental(graph, context, listener.getChangedNodes(), newNodesMark, false);
+        if (!listener.getNodes().isEmpty()) {
+            canonicalizer.applyIncremental(graph, context, listener.getNodes(), null, false);
         }
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
@@ -43,24 +44,22 @@
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
         ConditionalEliminationPhase eliminate = new ConditionalEliminationPhase(context.getMetaAccess());
-        HashSetNodeChangeListener listener = new HashSetNodeChangeListener();
+        HashSetNodeEventListener listener = new HashSetNodeEventListener.ExceptForAddedNodes();
         int count = 0;
         while (true) {
-            graph.trackInputChange(listener);
-            graph.trackUsagesDroppedZero(listener);
-            eliminate.apply(graph);
-            graph.stopTrackingInputChange();
-            graph.stopTrackingUsagesDroppedZero();
-            if (listener.getChangedNodes().isEmpty()) {
+            try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+                eliminate.apply(graph);
+            }
+            if (listener.getNodes().isEmpty()) {
                 break;
             }
             for (Node node : graph.getNodes()) {
                 if (node instanceof Simplifiable) {
-                    listener.getChangedNodes().add(node);
+                    listener.getNodes().add(node);
                 }
             }
-            canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
-            listener.getChangedNodes().clear();
+            canonicalizer.applyIncremental(graph, context, listener.getNodes());
+            listener.getNodes().clear();
             if (++count > MAX_ITERATIONS) {
                 throw new BailoutException("Number of iterations in ConditionalEliminationPhase phase exceeds " + MAX_ITERATIONS);
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -157,7 +157,7 @@
         IsNullNode isNullNode = (IsNullNode) condition;
         BeginNode nonTrappingContinuation = ifNode.falseSuccessor();
         BeginNode trappingContinuation = ifNode.trueSuccessor();
-        NullCheckNode trappingNullCheck = deopt.graph().add(new NullCheckNode(isNullNode.object()));
+        NullCheckNode trappingNullCheck = deopt.graph().add(new NullCheckNode(isNullNode.getValue()));
         trappingNullCheck.setStateBefore(deopt.stateBefore());
         deopt.graph().replaceSplit(ifNode, trappingNullCheck, nonTrappingContinuation);
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java	Mon Jun 30 12:02:19 2014 +0200
@@ -22,18 +22,16 @@
  */
 package com.oracle.graal.phases.common.cfs;
 
-import com.oracle.graal.api.code.Assumptions;
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.DebugMetric;
-import com.oracle.graal.graph.Node;
-import com.oracle.graal.graph.spi.CanonicalizerTool;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.compiler.common.type.ObjectStamp;
-import com.oracle.graal.phases.graph.SinglePassNodeIterator;
-import com.oracle.graal.phases.tiers.PhaseContext;
-
-import java.util.ArrayList;
+import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.tiers.*;
 
 /**
  * <p>
@@ -140,9 +138,8 @@
      * One of the promises of
      * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
      * is that a "maximally reduced" node is returned. That is achieved in part by leveraging
-     * {@link com.oracle.graal.graph.Node#canonical(com.oracle.graal.graph.spi.CanonicalizerTool)}.
-     * Doing so, in turn, requires this subclass of
-     * {@link com.oracle.graal.graph.spi.CanonicalizerTool}.
+     * {@link Canonicalizable#canonical(com.oracle.graal.graph.spi.CanonicalizerTool)}. Doing so, in
+     * turn, requires this subclass of {@link com.oracle.graal.graph.spi.CanonicalizerTool}.
      * </p>
      */
     public final class Tool implements CanonicalizerTool {
@@ -168,16 +165,6 @@
             return context.getConstantReflection();
         }
 
-        /**
-         * Postpone
-         * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)}
-         * until {@link FlowSensitiveReduction#finished()} for the reasons covered there.
-         */
-        @Override
-        public void removeIfUnused(Node node) {
-            // GraphUtil.tryKillUnused(node);
-        }
-
         @Override
         public boolean canonicalizeReads() {
             return false;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CastCheckExtractor.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CastCheckExtractor.java	Mon Jun 30 12:02:19 2014 +0200
@@ -45,7 +45,7 @@
     private static CastCheckExtractor extractCastCheckInfo(LogicNode x, LogicNode y) {
         if (x instanceof IsNullNode) {
             IsNullNode isNull = (IsNullNode) x;
-            ValueNode subject = isNull.object();
+            ValueNode subject = isNull.getValue();
             if (isInstanceOfCheckOn(y, subject)) {
                 InstanceOfNode iOf = (InstanceOfNode) y;
                 return new CastCheckExtractor(iOf.type(), subject);
@@ -82,6 +82,6 @@
             return false;
         }
         InstanceOfNode io = (InstanceOfNode) cond;
-        return io.object() == subject;
+        return io.getValue() == subject;
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java	Mon Jun 30 12:02:19 2014 +0200
@@ -332,11 +332,20 @@
         }
         FlowUtil.inferStampAndCheck(changed);
         added.add(changed);
-        ValueNode canon = (ValueNode) changed.canonical(tool);
-        // might be already in `added`, no problem adding it again.
-        added.add(canon);
-        rememberSubstitution(f, canon);
-        return canon;
+
+        if (changed instanceof Canonicalizable) {
+            ValueNode canon = (ValueNode) ((Canonicalizable) changed).canonical(tool);
+            if (canon != null && !canon.isAlive()) {
+                assert !canon.isDeleted();
+                canon = graph.addOrUniqueWithInputs(canon);
+            }
+            // might be already in `added`, no problem adding it again.
+            added.add(canon);
+            rememberSubstitution(f, canon);
+            return canon;
+        } else {
+            return changed;
+        }
     }
 
     /**
@@ -445,7 +454,7 @@
      *
      */
     private LogicNode baseCaseInstanceOfNode(InstanceOfNode instanceOf) {
-        ValueNode scrutinee = GraphUtil.unproxify(instanceOf.object());
+        ValueNode scrutinee = GraphUtil.unproxify(instanceOf.getValue());
         if (!FlowUtil.hasLegalObjectStamp(scrutinee)) {
             return instanceOf;
         }
@@ -470,7 +479,7 @@
      *
      */
     private FloatingNode baseCaseIsNullNode(IsNullNode isNu) {
-        ValueNode object = isNu.object();
+        ValueNode object = isNu.getValue();
         if (!FlowUtil.hasLegalObjectStamp(object)) {
             return isNu;
         }
@@ -489,11 +498,11 @@
      *         otherwise the unmodified argument.
      */
     private LogicNode baseCaseObjectEqualsNode(ObjectEqualsNode equals) {
-        if (!FlowUtil.hasLegalObjectStamp(equals.x()) || !FlowUtil.hasLegalObjectStamp(equals.y())) {
+        if (!FlowUtil.hasLegalObjectStamp(equals.getX()) || !FlowUtil.hasLegalObjectStamp(equals.getY())) {
             return equals;
         }
-        ValueNode x = GraphUtil.unproxify(equals.x());
-        ValueNode y = GraphUtil.unproxify(equals.y());
+        ValueNode x = GraphUtil.unproxify(equals.getX());
+        ValueNode y = GraphUtil.unproxify(equals.getY());
         if (state.isNull(x) && state.isNonNull(y) || state.isNonNull(x) && state.isNull(y)) {
             metricObjectEqualsRemoved.increment();
             return falseConstant;
@@ -629,7 +638,7 @@
         }
         TypeProfileProxyNode profile = (TypeProfileProxyNode) object;
         ObjectStamp outgoinStamp = (ObjectStamp) profile.stamp();
-        ObjectStamp payloadStamp = (ObjectStamp) profile.getObject().stamp();
+        ObjectStamp payloadStamp = (ObjectStamp) profile.getValue().stamp();
         if (payloadStamp.nonNull() && !outgoinStamp.nonNull()) {
             profile.setStamp(FlowUtil.asNonNullStamp(outgoinStamp));
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java	Mon Jun 30 12:02:19 2014 +0200
@@ -234,7 +234,7 @@
                 return;
             }
             // it's unwarranted to assume loadHub.object() to be non-null
-            state.trackCC(loadHub.object(), type, begin);
+            state.trackCC(loadHub.getValue(), type, begin);
         }
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java	Mon Jun 30 12:02:19 2014 +0200
@@ -359,7 +359,7 @@
             return false;
         }
         IsNullNode isNull = (IsNullNode) cond;
-        return isNull.object() == subject;
+        return isNull.getValue() == subject;
     }
 
     /**
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/IterativeFlowSensitiveReductionPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/IterativeFlowSensitiveReductionPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
@@ -41,42 +42,28 @@
         this.canonicalizer = canonicalizer;
     }
 
-    public static class CountingListener extends HashSetNodeChangeListener {
-
-        public int count;
-
-        @Override
-        public void nodeChanged(Node node) {
-            super.nodeChanged(node);
-        }
-
-    }
-
     // private Histogram histogram = new Histogram("FSR-");
 
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
         FlowSensitiveReductionPhase eliminate = new FlowSensitiveReductionPhase(context.getMetaAccess());
-        CountingListener listener = new CountingListener();
+        HashSetNodeEventListener listener = new HashSetNodeEventListener.ExceptForAddedNodes();
         int count = 1;
         while (true) {
-            listener.count = count;
-            graph.trackInputChange(listener);
-            graph.trackUsagesDroppedZero(listener);
-            eliminate.apply(graph, context);
-            graph.stopTrackingInputChange();
-            graph.stopTrackingUsagesDroppedZero();
-            if (listener.getChangedNodes().isEmpty()) {
+            try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+                eliminate.apply(graph, context);
+            }
+            if (listener.getNodes().isEmpty()) {
                 // histogram.tick(count);
                 break;
             }
             for (Node node : graph.getNodes()) {
                 if (node instanceof Simplifiable) {
-                    listener.getChangedNodes().add(node);
+                    listener.getNodes().add(node);
                 }
             }
-            canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
-            listener.getChangedNodes().clear();
+            canonicalizer.applyIncremental(graph, context, listener.getNodes());
+            listener.getNodes().clear();
             if (++count > MAX_ITERATIONS) {
                 // System.out.println("Bailing out IterativeFlowSensitiveReductionPhase for graph: "
                 // + graph);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java	Mon Jun 30 12:02:19 2014 +0200
@@ -647,7 +647,7 @@
         }
 
         if (condition instanceof LogicNegationNode) {
-            addFact(!isTrue, ((LogicNegationNode) condition).getInput(), anchor);
+            addFact(!isTrue, ((LogicNegationNode) condition).getValue(), anchor);
         } else if (condition instanceof ShortCircuitOrNode) {
             /*
              * We can register the conditions being or-ed as long as the anchor is a fixed node,
@@ -677,7 +677,7 @@
             addFactInstanceOf(isTrue, (InstanceOfNode) condition, anchor);
         } else if (condition instanceof IsNullNode) {
             IsNullNode nullCheck = (IsNullNode) condition;
-            addNullness(isTrue, nullCheck.object(), anchor);
+            addNullness(isTrue, nullCheck.getValue(), anchor);
         } else if (condition instanceof ObjectEqualsNode) {
             addFactObjectEqualsNode(isTrue, (ObjectEqualsNode) condition, anchor);
         } else {
@@ -692,7 +692,7 @@
      *
      */
     private void addFactInstanceOf(boolean isTrue, InstanceOfNode instanceOf, GuardingNode anchor) {
-        ValueNode object = instanceOf.object();
+        ValueNode object = instanceOf.getValue();
         if (isTrue) {
             if (knownNotToPassInstanceOf(object, instanceOf.type())) {
                 impossiblePath();
@@ -710,15 +710,15 @@
     }
 
     private void addFactObjectEqualsNode(boolean isTrue, ObjectEqualsNode equals, GuardingNode anchor) {
-        if (isDependencyTainted(equals.x(), anchor)) {
+        if (isDependencyTainted(equals.getX(), anchor)) {
             return;
         }
-        if (isDependencyTainted(equals.y(), anchor)) {
+        if (isDependencyTainted(equals.getY(), anchor)) {
             return;
         }
         assert anchor instanceof FixedNode;
-        ValueNode x = GraphUtil.unproxify(equals.x());
-        ValueNode y = GraphUtil.unproxify(equals.y());
+        ValueNode x = GraphUtil.unproxify(equals.getX());
+        ValueNode y = GraphUtil.unproxify(equals.getY());
         if (isTrue) {
             if (isNull(x) && isNonNull(y)) {
                 impossiblePath();
@@ -730,12 +730,12 @@
             }
             if (isNull(x) || isNull(y)) {
                 metricObjectEqualsRegistered.increment();
-                addNullness(true, equals.x(), anchor);
-                addNullness(true, equals.y(), anchor);
+                addNullness(true, equals.getX(), anchor);
+                addNullness(true, equals.getY(), anchor);
             } else if (isNonNull(x) || isNonNull(y)) {
                 metricObjectEqualsRegistered.increment();
-                addNullness(false, equals.x(), anchor);
-                addNullness(false, equals.y(), anchor);
+                addNullness(false, equals.getX(), anchor);
+                addNullness(false, equals.getY(), anchor);
             }
             Witness wx = typeInfo(x);
             Witness wy = typeInfo(y);
@@ -748,8 +748,8 @@
                 if (best != null) {
                     assert !best.isInterface();
                     // type tightening is enough, nullness already taken care of
-                    trackCC(equals.x(), best, anchor);
-                    trackCC(equals.y(), best, anchor);
+                    trackCC(equals.getX(), best, anchor);
+                    trackCC(equals.getY(), best, anchor);
                 }
             } else if (wx == null) {
                 typeRefinements.put(x, new Witness(wy));
@@ -759,10 +759,10 @@
         } else {
             if (isNull(x) && !isNonNull(y)) {
                 metricObjectEqualsRegistered.increment();
-                addNullness(false, equals.y(), anchor);
+                addNullness(false, equals.getY(), anchor);
             } else if (!isNonNull(x) && isNull(y)) {
                 metricObjectEqualsRegistered.increment();
-                addNullness(false, equals.x(), anchor);
+                addNullness(false, equals.getX(), anchor);
             }
         }
     }
@@ -911,20 +911,20 @@
     private Evidence outcomeIsNullNode(boolean isTrue, IsNullNode isNullNode) {
         if (isTrue) {
             // grab an anchor attesting nullness
-            final GuardingNode replacement = nonTrivialNullAnchor(isNullNode.object());
+            final GuardingNode replacement = nonTrivialNullAnchor(isNullNode.getValue());
             if (replacement != null) {
                 return new Evidence(replacement);
             }
-            if (isNonNull(isNullNode.object())) {
+            if (isNonNull(isNullNode.getValue())) {
                 return Evidence.COUNTEREXAMPLE;
             }
         } else {
             // grab an anchor attesting non-nullness
-            final Witness w = typeInfo(isNullNode.object());
+            final Witness w = typeInfo(isNullNode.getValue());
             if (w != null && w.isNonNull()) {
                 return new Evidence(w.guard());
             }
-            if (isNull(isNullNode.object())) {
+            if (isNull(isNullNode.getValue())) {
                 return Evidence.COUNTEREXAMPLE;
             }
         }
@@ -936,9 +936,9 @@
      * Utility method for {@link #outcome(boolean, com.oracle.graal.nodes.LogicNode)}
      */
     private Evidence outcomeInstanceOfNode(boolean isTrue, InstanceOfNode iOf) {
-        final Witness w = typeInfo(iOf.object());
+        final Witness w = typeInfo(iOf.getValue());
         if (isTrue) {
-            if (isNull(iOf.object())) {
+            if (isNull(iOf.getValue())) {
                 return Evidence.COUNTEREXAMPLE;
             }
             // grab an anchor attesting instanceof
@@ -957,7 +957,7 @@
         } else {
             // grab an anchor attesting not-instanceof
             // (1 of 2) attempt determining nullness
-            final GuardingNode nullGuard = nonTrivialNullAnchor(iOf.object());
+            final GuardingNode nullGuard = nonTrivialNullAnchor(iOf.getValue());
             if (nullGuard != null) {
                 return new Evidence(nullGuard);
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -29,9 +29,7 @@
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.policy.GreedyInliningPolicy;
 import com.oracle.graal.phases.common.inlining.policy.InliningPolicy;
-import com.oracle.graal.phases.common.inlining.walker.CallsiteHolder;
 import com.oracle.graal.phases.common.inlining.walker.InliningData;
-import com.oracle.graal.phases.common.inlining.walker.MethodInvocation;
 import com.oracle.graal.phases.tiers.*;
 
 public class InliningPhase extends AbstractInliningPhase {
@@ -72,68 +70,11 @@
     }
 
     /**
-     * <p>
-     * The space of inlining decisions is explored depth-first with the help of a stack realized by
-     * {@link com.oracle.graal.phases.common.inlining.walker.InliningData}. At any point in time,
-     * its topmost element consist of:
-     * <ul>
-     * <li>
-     * one or more {@link CallsiteHolder}s of inlining candidates, all of them corresponding to a
-     * single callsite (details below). For example, "exact inline" leads to a single candidate.</li>
-     * <li>
-     * the callsite (for the targets above) is tracked as a {@link MethodInvocation}. The difference
-     * between {@link com.oracle.graal.phases.common.inlining.walker.MethodInvocation#totalGraphs()}
-     * and {@link MethodInvocation#processedGraphs()} indicates the topmost {@link CallsiteHolder}s
-     * that might be delved-into to explore inlining opportunities.</li>
-     * </ul>
-     * </p>
      *
-     * <p>
-     * The bottom-most element in the stack consists of:
-     * <ul>
-     * <li>
-     * a single {@link CallsiteHolder} (the root one, for the method on which inlining was called)</li>
-     * <li>
-     * a single {@link MethodInvocation} (the
-     * {@link com.oracle.graal.phases.common.inlining.walker.MethodInvocation#isRoot} one, ie the
-     * unknown caller of the root graph)</li>
-     * </ul>
-     *
-     * </p>
+     * This method sets in motion the inlining machinery.
      *
-     * <p>
-     * The stack grows and shrinks as choices are made among the alternatives below:
-     * <ol>
-     * <li>
-     * not worth inlining: pop any remaining graphs not yet delved into, pop the current invocation.
-     * </li>
-     * <li>
-     * process next invoke: delve into one of the callsites hosted in the current candidate graph,
-     * determine whether any inlining should be performed in it</li>
-     * <li>
-     * try to inline: move past the current inlining candidate (remove it from the topmost element).
-     * If that was the last one then try to inline the callsite that is (still) in the topmost
-     * element of {@link com.oracle.graal.phases.common.inlining.walker.InliningData}, and then
-     * remove such callsite.</li>
-     * </ol>
-     * </p>
-     *
-     * <p>
-     * Some facts about the alternatives above:
-     * <ul>
-     * <li>
-     * the first step amounts to backtracking, the 2nd one to delving, and the 3rd one also involves
-     * backtracking (however after may-be inlining).</li>
-     * <li>
-     * the choice of abandon-and-backtrack or delve-into is depends on
-     * {@link InliningPolicy#isWorthInlining} and {@link InliningPolicy#continueInlining}.</li>
-     * <li>
-     * the 3rd choice is picked when both of the previous ones aren't picked</li>
-     * <li>
-     * as part of trying-to-inline, {@link InliningPolicy#isWorthInlining} again sees use, but
-     * that's another story.</li>
-     * </ul>
-     * </p>
+     * @see InliningData
+     * @see InliningData#moveForward()
      *
      */
     @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Mon Jun 30 12:02:19 2014 +0200
@@ -223,8 +223,10 @@
      * @param inlineGraph the graph that the invoke will be replaced with
      * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings,
      *            false if no such check is required
+     * @param canonicalizedNodes if non-null then append to this list any nodes which should be
+     *            canonicalized after inlining
      */
-    public static Map<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
+    public static Map<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, List<Node> canonicalizedNodes) {
         final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
         FixedNode invokeNode = invoke.asNode();
         StructuredGraph graph = invokeNode.graph();
@@ -289,7 +291,6 @@
                 stateAtExceptionEdge = obj.stateAfter();
                 UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
                 obj.replaceAtUsages(unwindDuplicate.exception());
-                unwindDuplicate.clearInputs();
                 Node n = obj.next();
                 obj.setNext(null);
                 unwindDuplicate.replaceAndDelete(n);
@@ -332,7 +333,6 @@
                 ReturnNode returnNode = (ReturnNode) duplicates.get(returnNodes.get(0));
                 Node returnValue = returnNode.result();
                 invokeNode.replaceAtUsages(returnValue);
-                returnNode.clearInputs();
                 returnNode.replaceAndDelete(n);
             } else {
                 ArrayList<ReturnNode> returnDuplicates = new ArrayList<>(returnNodes.size());
@@ -341,7 +341,7 @@
                 }
                 MergeNode merge = graph.add(new MergeNode());
                 merge.setStateAfter(stateAfter);
-                ValueNode returnValue = mergeReturns(merge, returnDuplicates);
+                ValueNode returnValue = mergeReturns(merge, returnDuplicates, canonicalizedNodes);
                 invokeNode.replaceAtUsages(returnValue);
                 merge.setNext(n);
             }
@@ -440,7 +440,7 @@
         }
     }
 
-    public static ValueNode mergeReturns(MergeNode merge, List<? extends ReturnNode> returnNodes) {
+    public static ValueNode mergeReturns(MergeNode merge, List<? extends ReturnNode> returnNodes, List<Node> canonicalizedNodes) {
         PhiNode returnValuePhi = null;
 
         for (ReturnNode returnNode : returnNodes) {
@@ -451,10 +451,12 @@
             if (returnNode.result() != null) {
                 if (returnValuePhi == null) {
                     returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(returnNode.result().stamp().unrestricted(), merge));
+                    if (canonicalizedNodes != null) {
+                        canonicalizedNodes.add(returnValuePhi);
+                    }
                 }
                 returnValuePhi.addInput(returnNode.result());
             }
-            returnNode.clearInputs();
             returnNode.replaceAndDelete(endNode);
 
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,10 +28,12 @@
 import com.oracle.graal.api.meta.ResolvedJavaMethod;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
 import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
 import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
 import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
+import com.oracle.graal.phases.tiers.HighTierContext;
 
 public abstract class AbstractInlineInfo implements InlineInfo {
 
@@ -52,22 +54,22 @@
     }
 
     protected static Collection<Node> inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) {
-        Collection<Node> parameterUsages = new ArrayList<>();
+        List<Node> canonicalizeNodes = new ArrayList<>();
         if (inlineable instanceof InlineableGraph) {
             StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
-            Map<Node, Node> duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck);
-            getInlinedParameterUsages(parameterUsages, calleeGraph, duplicateMap);
+            Map<Node, Node> duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck, canonicalizeNodes);
+            getInlinedParameterUsages(canonicalizeNodes, calleeGraph, duplicateMap);
         } else {
             assert inlineable instanceof InlineableMacroNode;
 
             Class<? extends FixedWithNextNode> macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass();
             FixedWithNextNode macroNode = InliningUtil.inlineMacroNode(invoke, concrete, macroNodeClass);
-            parameterUsages.add(macroNode);
+            canonicalizeNodes.add(macroNode);
         }
 
         InliningUtil.InlinedBytecodes.add(concrete.getCodeSize());
         assumptions.recordMethodContents(concrete);
-        return parameterUsages;
+        return canonicalizeNodes;
     }
 
     public static void getInlinedParameterUsages(Collection<Node> parameterUsages, StructuredGraph calleeGraph, Map<Node, Node> duplicateMap) {
@@ -80,4 +82,22 @@
             }
         }
     }
+
+    public final void populateInlinableElements(HighTierContext context, Assumptions calleeAssumptions, CanonicalizerPhase canonicalizer) {
+        for (int i = 0; i < numberOfMethods(); i++) {
+            Inlineable elem = Inlineable.getInlineableElement(methodAt(i), invoke, context.replaceAssumptions(calleeAssumptions), canonicalizer);
+            setInlinableElement(i, elem);
+        }
+    }
+
+    public final int determineNodeCount() {
+        int nodes = 0;
+        for (int i = 0; i < numberOfMethods(); i++) {
+            Inlineable elem = inlineableElementAt(i);
+            if (elem != null) {
+                nodes += elem.getNodeCount();
+            }
+        }
+        return nodes;
+    }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,7 +30,9 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.Invoke;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.tiers.HighTierContext;
 import com.oracle.graal.phases.util.Providers;
 
 /**
@@ -82,4 +84,8 @@
     void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions);
 
     boolean shouldInline();
+
+    void populateInlinableElements(HighTierContext context, Assumptions calleeAssumptions, CanonicalizerPhase canonicalizer);
+
+    int determineNodeCount();
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Mon Jun 30 12:02:19 2014 +0200
@@ -222,9 +222,7 @@
 
         ArrayList<GuardedValueNode> replacementNodes = new ArrayList<>();
 
-        Collection<Node> parameterUsages = new ArrayList<>();
-
-        // do the actual inlining for every invoke
+        // prepare the anchors for the invokes
         for (int i = 0; i < numberOfMethods; i++) {
             BeginNode node = successors[i];
             Invoke invokeForInlining = (Invoke) node.next();
@@ -241,8 +239,7 @@
             GuardedValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, node, commonType, receiver, exact);
             invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
 
-            parameterUsages.addAll(inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false));
-
+            assert !anchoredReceiver.isDeleted() : anchoredReceiver;
             replacementNodes.add(anchoredReceiver);
         }
         if (shouldFallbackToInvoke()) {
@@ -274,7 +271,17 @@
                 TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, phaseContext, canonicalizer);
             }
         }
-        return parameterUsages;
+
+        Collection<Node> canonicalizeNodes = new ArrayList<>();
+        // do the actual inlining for every invoke
+        for (int i = 0; i < numberOfMethods; i++) {
+            Invoke invokeForInlining = (Invoke) successors[i].next();
+            canonicalizeNodes.addAll(inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false));
+        }
+        if (returnValuePhi != null) {
+            canonicalizeNodes.add(returnValuePhi);
+        }
+        return canonicalizeNodes;
     }
 
     private int getTypeCount(int concreteMethodIndex) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,6 +32,8 @@
 public interface Inlineable {
 
     static Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer) {
+        assert method != null;
+        assert invoke != null;
         Class<? extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(context.getReplacements(), method);
         if (macroNodeClass != null) {
             return new InlineableMacroNode(macroNodeClass);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Mon Jun 30 12:02:19 2014 +0200
@@ -32,11 +32,26 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
+import com.oracle.graal.phases.common.cfs.FlowUtil;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
 import com.oracle.graal.phases.tiers.HighTierContext;
 
 import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer;
 
+/**
+ * <p>
+ * Represents a feasible concrete target for inlining, whose graph has been copied already and thus
+ * can be modified without affecting the original (usually cached) version.
+ * </p>
+ *
+ * <p>
+ * Instances of this class don't make sense in isolation but as part of an
+ * {@link com.oracle.graal.phases.common.inlining.info.InlineInfo InlineInfo}.
+ * </p>
+ *
+ * @see com.oracle.graal.phases.common.inlining.walker.InliningData#moveForward()
+ * @see com.oracle.graal.phases.common.inlining.walker.CallsiteHolderExplorable
+ */
 public class InlineableGraph implements Inlineable {
 
     private final StructuredGraph graph;
@@ -73,6 +88,7 @@
         try (Debug.Scope s = Debug.scope("InlineGraph", graph)) {
 
             ArrayList<Node> parameterUsages = replaceParamsWithMoreInformativeArguments(invoke, context);
+            parameterUsages = rewireParamsForDuplicateArguments(invoke, parameterUsages);
             if (parameterUsages != null && OptCanonicalizer.getValue()) {
                 assert !parameterUsages.isEmpty() : "The caller didn't have more information about arguments after all";
                 canonicalizer.applyIncremental(graph, context, parameterUsages);
@@ -89,16 +105,62 @@
         }
     }
 
-    private static boolean isArgMoreInformativeThanParam(ValueNode arg, ParameterNode param) {
-        if (arg.isConstant()) {
-            return true;
-        } else {
-            Stamp joinedStamp = param.stamp().join(arg.stamp());
-            if (joinedStamp != null && !joinedStamp.equals(param.stamp())) {
-                return true;
+    /**
+     * This method detects duplicate arguments (therefore corresponding to different
+     * {@link ParameterNode}s) and updates the graph to make all of their usages refer to the first
+     * one of them.
+     *
+     * @return a (possibly updated) list of nodes for incremental canonicalization.
+     */
+    private ArrayList<Node> rewireParamsForDuplicateArguments(Invoke invoke, ArrayList<Node> parameterUsages0) {
+        ArrayList<Node> parameterUsages = parameterUsages0;
+        ArrayList<ParameterNode> params = new ArrayList<>();
+        List<ValueNode> originalArgs = invoke.callTarget().arguments();
+        List<ValueNode> argsInEffect = new ArrayList<>();
+        // some param-nodes might have been deleted by replaceParamsWithMoreInformativeArguments()
+        // that's why we obtain an up-to-date list
+        for (ParameterNode p : graph.getNodes(ParameterNode.class)) {
+            if (!FlowUtil.lacksUsages(p)) {
+                params.add(p);
+                argsInEffect.add(originalArgs.get(p.index()));
             }
         }
-        return false;
+        // argsInEffect and params paired by position
+        assert params.size() == argsInEffect.size();
+        int argIdx = 0;
+        for (ValueNode arg : argsInEffect) {
+            int firstOccurrrence = argsInEffect.indexOf(arg);
+            assert firstOccurrrence >= 0;
+            if (firstOccurrrence < argIdx) {
+                ParameterNode survivingParam = params.get(firstOccurrrence);
+                assert survivingParam.isAlive();
+                ParameterNode duplicateParam = params.get(argIdx);
+                assert duplicateParam.isAlive();
+                assert survivingParam != duplicateParam;
+                assert !isArgMoreInformativeThanParam(arg, survivingParam);
+                parameterUsages = trackParameterUsages(duplicateParam, parameterUsages);
+                // replaceFloating() deletes the duplicate param, unlike replaceAtUsages()
+                graph.replaceFloating(duplicateParam, survivingParam);
+            }
+            argIdx++;
+        }
+        return parameterUsages;
+    }
+
+    private static boolean isArgMoreInformativeThanParam(ValueNode arg, ParameterNode param) {
+        return arg.isConstant() || canStampBeImproved(arg, param);
+    }
+
+    private static boolean canStampBeImproved(ValueNode arg, ParameterNode param) {
+        return improvedStamp(arg, param) != null;
+    }
+
+    private static Stamp improvedStamp(ValueNode arg, ParameterNode param) {
+        Stamp joinedStamp = param.stamp().join(arg.stamp());
+        if (joinedStamp == null || joinedStamp.equals(param.stamp())) {
+            return null;
+        }
+        return joinedStamp;
     }
 
     /**
@@ -140,9 +202,9 @@
                     graph.replaceFloating(param, ConstantNode.forConstant(constant, context.getMetaAccess(), graph));
                     // param-node gone, leaving a gap in the sequence given by param.index()
                 } else {
-                    Stamp joinedStamp = param.stamp().join(arg.stamp());
-                    if (joinedStamp != null && !joinedStamp.equals(param.stamp())) {
-                        param.setStamp(joinedStamp);
+                    Stamp impro = improvedStamp(arg, param);
+                    if (impro != null) {
+                        param.setStamp(impro);
                         parameterUsages = trackParameterUsages(param, parameterUsages);
                     } else {
                         assert !isArgMoreInformativeThanParam(arg, param);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java	Mon Jun 30 12:02:19 2014 +0200
@@ -100,17 +100,6 @@
         return size;
     }
 
-    protected static int determineNodeCount(InlineInfo info) {
-        int nodes = 0;
-        for (int i = 0; i < info.numberOfMethods(); i++) {
-            Inlineable elem = info.inlineableElementAt(i);
-            if (elem != null) {
-                nodes += elem.getNodeCount();
-            }
-        }
-        return nodes;
-    }
-
     protected static double determineInvokeProbability(ToDoubleFunction<FixedNode> probabilities, InlineInfo info) {
         double invokeProbability = 0;
         for (int i = 0; i < info.numberOfMethods(); i++) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
 import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.inlining.walker.MethodInvocation;
 
 import java.util.Map;
 import java.util.function.ToDoubleFunction;
@@ -54,8 +55,12 @@
     }
 
     @Override
-    public boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
-                    boolean fullyProcessed) {
+    public boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) {
+
+        final InlineInfo info = invocation.callee();
+        final double probability = invocation.probability();
+        final double relevance = invocation.relevance();
+
         if (InlineEverything.getValue()) {
             InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
             return true;
@@ -72,7 +77,7 @@
         }
 
         double inliningBonus = getInliningBonus(info);
-        int nodes = determineNodeCount(info);
+        int nodes = info.determineNodeCount();
         int lowLevelGraphSize = previousLowLevelGraphSize(info);
 
         if (SmallCompiledLowLevelGraphSize.getValue() > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue() * inliningBonus) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java	Mon Jun 30 12:02:19 2014 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.FixedNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.spi.Replacements;
-import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.inlining.walker.MethodInvocation;
 
 import java.util.function.ToDoubleFunction;
 
@@ -41,8 +41,7 @@
         return true;
     }
 
-    public boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
-                    boolean fullyProcessed) {
+    public boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) {
         return true;
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InliningPolicy.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InliningPolicy.java	Mon Jun 30 12:02:19 2014 +0200
@@ -25,7 +25,7 @@
 import com.oracle.graal.nodes.FixedNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.spi.Replacements;
-import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.inlining.walker.MethodInvocation;
 
 import java.util.function.ToDoubleFunction;
 
@@ -33,5 +33,5 @@
 
     boolean continueInlining(StructuredGraph graph);
 
-    boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed);
+    boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed);
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolder.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolder.java	Mon Jun 30 12:02:19 2014 +0200
@@ -22,105 +22,31 @@
  */
 package com.oracle.graal.phases.common.inlining.walker;
 
-import com.oracle.graal.api.meta.MetaUtil;
 import com.oracle.graal.api.meta.ResolvedJavaMethod;
-import com.oracle.graal.nodes.FixedNode;
-import com.oracle.graal.nodes.Invoke;
 import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.phases.graph.FixedNodeProbabilityCache;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.function.ToDoubleFunction;
-
-import static com.oracle.graal.compiler.common.GraalOptions.CapInheritedRelevance;
 
 /**
  * Information about a graph that will potentially be inlined. This includes tracking the
  * invocations in graph that will subject to inlining themselves.
  */
-public class CallsiteHolder {
-
-    private final StructuredGraph graph;
-    private final LinkedList<Invoke> remainingInvokes;
-    private final double probability;
-    private final double relevance;
-
-    private final ToDoubleFunction<FixedNode> probabilities;
-    private final ComputeInliningRelevance computeInliningRelevance;
-
-    public CallsiteHolder(StructuredGraph graph, double probability, double relevance) {
-        this.graph = graph;
-        this.probability = probability;
-        this.relevance = relevance;
-        if (graph == null) {
-            remainingInvokes = new LinkedList<>();
-            probabilities = null;
-            computeInliningRelevance = null;
-        } else {
-            remainingInvokes = new InliningIterator(graph).apply();
-            assert remainingInvokes.size() == count(graph.getInvokes());
-            if (remainingInvokes.isEmpty()) {
-                probabilities = null;
-                computeInliningRelevance = null;
-            } else {
-                probabilities = new FixedNodeProbabilityCache();
-                computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
-                computeProbabilities();
-            }
-        }
-    }
-
-    private static int count(Iterable<Invoke> invokes) {
-        int count = 0;
-        Iterator<Invoke> iterator = invokes.iterator();
-        while (iterator.hasNext()) {
-            iterator.next();
-            count++;
-        }
-        return count;
-    }
+public abstract class CallsiteHolder {
 
     /**
      * Gets the method associated with the {@linkplain #graph() graph} represented by this object.
      */
-    public ResolvedJavaMethod method() {
-        return graph == null ? null : graph.method();
-    }
+    public abstract ResolvedJavaMethod method();
 
-    public boolean hasRemainingInvokes() {
-        return !remainingInvokes.isEmpty();
-    }
+    /**
+     * The stack realized by {@link InliningData} grows upon {@link InliningData#moveForward()}
+     * deciding to explore (depth-first) a callsite of the graph associated to this
+     * {@link CallsiteHolder}. The list of not-yet-considered callsites is managed by
+     * {@link CallsiteHolderExplorable}, and this method reports whether any such candidates remain.
+     */
+    public abstract boolean hasRemainingInvokes();
 
     /**
      * The graph about which this object contains inlining information.
      */
-    public StructuredGraph graph() {
-        return graph;
-    }
-
-    public Invoke popInvoke() {
-        return remainingInvokes.removeFirst();
-    }
-
-    public void pushInvoke(Invoke invoke) {
-        remainingInvokes.push(invoke);
-    }
+    public abstract StructuredGraph graph();
 
-    public void computeProbabilities() {
-        computeInliningRelevance.compute();
-    }
-
-    public double invokeProbability(Invoke invoke) {
-        return probability * probabilities.applyAsDouble(invoke.asNode());
-    }
-
-    public double invokeRelevance(Invoke invoke) {
-        return Math.min(CapInheritedRelevance.getValue(), relevance) * computeInliningRelevance.getRelevance(invoke);
-    }
-
-    @Override
-    public String toString() {
-        return (graph != null ? MetaUtil.format("%H.%n(%p)", method()) : "<null method>") + remainingInvokes;
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderDummy.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.inlining.walker;
+
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.StructuredGraph;
+
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
+
+/**
+ * A {@link CallsiteHolder} that stands for an {@link InlineableMacroNode} in the stack realized by
+ * {@link InliningData}.
+ */
+public final class CallsiteHolderDummy extends CallsiteHolder {
+
+    public static final CallsiteHolderDummy DUMMY_CALLSITE_HOLDER = new CallsiteHolderDummy();
+
+    private CallsiteHolderDummy() {
+        // no instances other than the singleton
+    }
+
+    @Override
+    public ResolvedJavaMethod method() {
+        return null;
+    }
+
+    @Override
+    public boolean hasRemainingInvokes() {
+        return false;
+    }
+
+    @Override
+    public StructuredGraph graph() {
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return "<macro-node>";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderExplorable.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.inlining.walker;
+
+import com.oracle.graal.api.meta.MetaUtil;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.graph.FixedNodeProbabilityCache;
+
+import java.util.*;
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.CapInheritedRelevance;
+
+/**
+ * <p>
+ * A {@link CallsiteHolder} whose graph has been copied already and thus can be modified without
+ * affecting the original (usually cached) version.
+ * </p>
+ *
+ * <p>
+ * An instance of this class is derived from an
+ * {@link com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph InlineableGraph} and
+ * contains a subset of the information there: just the {@link Invoke} nodes from it. Such nodes are
+ * candidates for depth-first search of further inlining opportunities (thus the adjective
+ * "explorable" given to this class)
+ * </p>
+ *
+ * @see InliningData#moveForward()
+ */
+public final class CallsiteHolderExplorable extends CallsiteHolder {
+
+    /**
+     * Graph in which inlining may be performed at one or more of the callsites containined in
+     * {@link #remainingInvokes}
+     */
+    private final StructuredGraph graph;
+
+    private final LinkedList<Invoke> remainingInvokes;
+    private final double probability;
+    private final double relevance;
+
+    /**
+     * @see #getFixedParams()
+     */
+    private final Set<ParameterNode> fixedParams;
+
+    private final ToDoubleFunction<FixedNode> probabilities;
+    private final ComputeInliningRelevance computeInliningRelevance;
+
+    public CallsiteHolderExplorable(StructuredGraph graph, double probability, double relevance, BitSet freshlyInstantiatedArguments) {
+        assert graph != null;
+        this.graph = graph;
+        this.probability = probability;
+        this.relevance = relevance;
+        this.fixedParams = fixedParamsAt(freshlyInstantiatedArguments);
+        remainingInvokes = new InliningIterator(graph).apply();
+        if (remainingInvokes.isEmpty()) {
+            probabilities = null;
+            computeInliningRelevance = null;
+        } else {
+            probabilities = new FixedNodeProbabilityCache();
+            computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
+            computeProbabilities();
+        }
+        assert repOK();
+    }
+
+    /**
+     * @see #getFixedParams()
+     */
+    @SuppressWarnings("unchecked")
+    private Set<ParameterNode> fixedParamsAt(BitSet freshlyInstantiatedArguments) {
+        if (freshlyInstantiatedArguments == null || freshlyInstantiatedArguments.isEmpty()) {
+            return Collections.EMPTY_SET;
+        }
+        Set<ParameterNode> result = new HashSet<>();
+        for (ParameterNode p : graph.getNodes(ParameterNode.class)) {
+            if (freshlyInstantiatedArguments.get(p.index())) {
+                result.add(p);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * <p>
+     * Parameters for which the callsite targeting {@link #graph()} provides "fixed" arguments. That
+     * callsite isn't referenced by this instance. Instead, it belongs to the graph of the caller of
+     * this {@link CallsiteHolderExplorable}
+     * </p>
+     *
+     * <p>
+     * Constant arguments don't contribute to fixed-params: those params have been removed already,
+     * see {@link com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph}.
+     * </p>
+     *
+     * <p>
+     * Instead, fixed-params are those receiving freshly instantiated arguments (possibly
+     * instantiated several levels up in the call-hierarchy)
+     * </p>
+     * */
+    public Set<ParameterNode> getFixedParams() {
+        return fixedParams;
+    }
+
+    public boolean repOK() {
+        for (Invoke invoke : remainingInvokes) {
+            if (!invoke.asNode().isAlive() || !containsInvoke(invoke)) {
+                assert false;
+                return false;
+            }
+            if (!allArgsNonNull(invoke)) {
+                assert false;
+                return false;
+            }
+        }
+        for (ParameterNode fixedParam : fixedParams) {
+            if (!containsParam(fixedParam)) {
+                assert false;
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public ResolvedJavaMethod method() {
+        return graph == null ? null : graph.method();
+    }
+
+    @Override
+    public boolean hasRemainingInvokes() {
+        return !remainingInvokes.isEmpty();
+    }
+
+    @Override
+    public StructuredGraph graph() {
+        return graph;
+    }
+
+    public Invoke popInvoke() {
+        return remainingInvokes.removeFirst();
+    }
+
+    public void pushInvoke(Invoke invoke) {
+        remainingInvokes.push(invoke);
+    }
+
+    public static boolean allArgsNonNull(Invoke invoke) {
+        for (ValueNode arg : invoke.callTarget().arguments()) {
+            if (arg == null) {
+                assert false;
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public boolean containsInvoke(Invoke invoke) {
+        for (Invoke i : graph().getInvokes()) {
+            if (i == invoke) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean containsParam(ParameterNode param) {
+        for (ParameterNode p : graph.getNodes(ParameterNode.class)) {
+            if (p == param) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void computeProbabilities() {
+        computeInliningRelevance.compute();
+    }
+
+    public double invokeProbability(Invoke invoke) {
+        return probability * probabilities.applyAsDouble(invoke.asNode());
+    }
+
+    public double invokeRelevance(Invoke invoke) {
+        return Math.min(CapInheritedRelevance.getValue(), relevance) * computeInliningRelevance.getRelevance(invoke);
+    }
+
+    @Override
+    public String toString() {
+        return (graph != null ? MetaUtil.format("%H.%n(%p)", method()) : "<null method>") + remainingInvokes;
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Mon Jun 30 12:02:19 2014 +0200
@@ -34,7 +34,10 @@
 import com.oracle.graal.graph.Graph;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.AbstractNewObjectNode;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
+import com.oracle.graal.nodes.virtual.AllocatedObjectNode;
+import com.oracle.graal.nodes.virtual.VirtualObjectNode;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
@@ -51,14 +54,37 @@
 import java.util.function.ToDoubleFunction;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.phases.common.inlining.walker.CallsiteHolderDummy.DUMMY_CALLSITE_HOLDER;
 
 /**
- * Holds the data for building the callee graphs recursively: graphs and invocations (each
- * invocation can have multiple graphs).
+ * <p>
+ * The space of inlining decisions is explored depth-first with the help of a stack realized by
+ * {@link InliningData}. At any point in time, the topmost element of that stack consists of:
+ * <ul>
+ * <li>the callsite under consideration is tracked as a {@link MethodInvocation}.</li>
+ * <li>
+ * one or more {@link CallsiteHolder}s, all of them associated to the callsite above. Why more than
+ * one? Depending on the type-profile for the receiver more than one concrete method may be feasible
+ * target.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * The bottom element in the stack consists of:
+ * <ul>
+ * <li>
+ * a single {@link MethodInvocation} (the
+ * {@link com.oracle.graal.phases.common.inlining.walker.MethodInvocation#isRoot root} one, ie the
+ * unknown caller of the root graph)</li>
+ * <li>
+ * a single {@link CallsiteHolder} (the root one, for the method on which inlining was called)</li>
+ * </ul>
+ * </p>
+ *
+ * @see #moveForward()
  */
 public class InliningData {
 
-    private static final CallsiteHolder DUMMY_CALLSITE_HOLDER = new CallsiteHolder(null, 1.0, 1.0);
     // Metrics
     private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
     private static final DebugMetric metricInliningRuns = Debug.metric("InliningRuns");
@@ -87,8 +113,12 @@
         this.maxGraphs = 1;
 
         Assumptions rootAssumptions = context.getAssumptions();
-        invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
-        pushGraph(rootGraph, 1.0, 1.0);
+        invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0, null));
+        graphQueue.push(new CallsiteHolderExplorable(rootGraph, 1.0, 1.0, null));
+    }
+
+    public static boolean isFreshInstantiation(ValueNode arg) {
+        return (arg instanceof AbstractNewObjectNode) || (arg instanceof AllocatedObjectNode) || (arg instanceof VirtualObjectNode);
     }
 
     private String checkTargetConditionsHelper(ResolvedJavaMethod method) {
@@ -336,7 +366,7 @@
         return new ExactInlineInfo(invoke, targetMethod);
     }
 
-    private void doInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInvocation, Assumptions callerAssumptions) {
+    private void doInline(CallsiteHolderExplorable callerCallsiteHolder, MethodInvocation calleeInvocation, Assumptions callerAssumptions) {
         StructuredGraph callerGraph = callerCallsiteHolder.graph();
         InlineInfo calleeInfo = calleeInvocation.callee();
         try {
@@ -376,15 +406,27 @@
     }
 
     /**
+     *
+     * This method attempts:
+     * <ol>
+     * <li>
+     * to inline at the callsite given by <code>calleeInvocation</code>, where that callsite belongs
+     * to the {@link CallsiteHolderExplorable} at the top of the {@link #graphQueue} maintained in
+     * this class.</li>
+     * <li>
+     * otherwise, to devirtualize the callsite in question.</li>
+     * </ol>
+     *
      * @return true iff inlining was actually performed
      */
-    private boolean tryToInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInvocation, MethodInvocation parentInvocation, int inliningDepth) {
+    private boolean tryToInline(MethodInvocation calleeInvocation, MethodInvocation parentInvocation, int inliningDepth) {
+        CallsiteHolderExplorable callerCallsiteHolder = (CallsiteHolderExplorable) currentGraph();
         InlineInfo calleeInfo = calleeInvocation.callee();
-        assert iterContains(callerCallsiteHolder.graph().getInvokes(), calleeInfo.invoke());
+        assert callerCallsiteHolder.containsInvoke(calleeInfo.invoke());
         Assumptions callerAssumptions = parentInvocation.assumptions();
         metricInliningConsidered.increment();
 
-        if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), calleeInfo, inliningDepth, calleeInvocation.probability(), calleeInvocation.relevance(), true)) {
+        if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), calleeInvocation, inliningDepth, true)) {
             doInline(callerCallsiteHolder, calleeInvocation, callerAssumptions);
             return true;
         }
@@ -396,62 +438,94 @@
         return false;
     }
 
-    private static <T> boolean iterContains(Iterable<T> in, T elem) {
-        for (T i : in) {
-            if (i == elem) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /**
-     * Process the next invoke and enqueue all its graphs for processing.
+     * This method picks one of the callsites belonging to the current
+     * {@link CallsiteHolderExplorable}. Provided the callsite qualifies to be analyzed for
+     * inlining, this method prepares a new stack top in {@link InliningData} for such callsite,
+     * which comprises:
+     * <ul>
+     * <li>preparing a summary of feasible targets, ie preparing an {@link InlineInfo}</li>
+     * <li>based on it, preparing the stack top proper which consists of:</li>
+     * <ul>
+     * <li>one {@link MethodInvocation}</li>
+     * <li>a {@link CallsiteHolder} for each feasible target</li>
+     * </ul>
+     * </ul>
+     *
+     * <p>
+     * The thus prepared "stack top" is needed by {@link #moveForward()} to explore the space of
+     * inlining decisions (each decision one of: backtracking, delving, inlining).
+     * </p>
+     *
+     * <p>
+     * The {@link InlineInfo} used to get things rolling is kept around in the
+     * {@link MethodInvocation}, it will be needed in case of inlining, see
+     * {@link InlineInfo#inline(Providers, Assumptions)}
+     * </p>
      */
     private void processNextInvoke() {
-        CallsiteHolder callsiteHolder = currentGraph();
+        CallsiteHolderExplorable callsiteHolder = (CallsiteHolderExplorable) currentGraph();
         Invoke invoke = callsiteHolder.popInvoke();
         MethodInvocation callerInvocation = currentInvocation();
         Assumptions parentAssumptions = callerInvocation.assumptions();
-        Assumptions calleeAssumptions = new Assumptions(parentAssumptions.useOptimisticAssumptions());
-        InlineInfo info = populateInlineInfo(invoke, parentAssumptions, calleeAssumptions);
+        InlineInfo info = getInlineInfo(invoke, parentAssumptions);
 
         if (info != null) {
+            Assumptions calleeAssumptions = new Assumptions(parentAssumptions.useOptimisticAssumptions());
+            info.populateInlinableElements(context, calleeAssumptions, canonicalizer);
             double invokeProbability = callsiteHolder.invokeProbability(invoke);
             double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
-            MethodInvocation methodInvocation = new MethodInvocation(info, calleeAssumptions, invokeProbability, invokeRelevance);
+            MethodInvocation methodInvocation = new MethodInvocation(info, calleeAssumptions, invokeProbability, invokeRelevance, freshlyInstantiatedArguments(invoke, callsiteHolder.getFixedParams()));
             pushInvocationAndGraphs(methodInvocation);
         }
     }
 
-    private InlineInfo populateInlineInfo(Invoke invoke, Assumptions parentAssumptions, Assumptions calleeAssumptions) {
-        InlineInfo info = getInlineInfo(invoke, parentAssumptions);
-        if (info == null) {
-            return null;
+    /**
+     * <p>
+     * A freshly instantiated argument is either:
+     * <uL>
+     * <li>an {@link InliningData#isFreshInstantiation(com.oracle.graal.nodes.ValueNode)}</li>
+     * <li>a fixed-param, ie a {@link ParameterNode} receiving a freshly instantiated argument</li>
+     * </uL>
+     * </p>
+     *
+     * @return the positions of freshly instantiated arguments in the argument list of the
+     *         <code>invoke</code>, or null if no such positions exist.
+     */
+    public static BitSet freshlyInstantiatedArguments(Invoke invoke, Set<ParameterNode> fixedParams) {
+        assert fixedParams != null;
+        assert paramsAndInvokeAreInSameGraph(invoke, fixedParams);
+        BitSet result = null;
+        int argIdx = 0;
+        for (ValueNode arg : invoke.callTarget().arguments()) {
+            assert arg != null;
+            if (isFreshInstantiation(arg) || fixedParams.contains(arg)) {
+                if (result == null) {
+                    result = new BitSet();
+                }
+                result.set(argIdx);
+            }
+            argIdx++;
         }
-        for (int i = 0; i < info.numberOfMethods(); i++) {
-            Inlineable elem = Inlineable.getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeAssumptions), canonicalizer);
-            info.setInlinableElement(i, elem);
+        return result;
+    }
+
+    private static boolean paramsAndInvokeAreInSameGraph(Invoke invoke, Set<ParameterNode> fixedParams) {
+        if (fixedParams.isEmpty()) {
+            return true;
         }
-        return info;
+        for (ParameterNode p : fixedParams) {
+            if (p.graph() != invoke.asNode().graph()) {
+                return false;
+            }
+        }
+        return true;
     }
 
     public int graphCount() {
         return graphQueue.size();
     }
 
-    private void pushGraph(StructuredGraph graph, double probability, double relevance) {
-        assert graph != null;
-        assert !contains(graph);
-        graphQueue.push(new CallsiteHolder(graph, probability, relevance));
-        assert graphQueue.size() <= maxGraphs;
-    }
-
-    private void pushDummyGraph() {
-        graphQueue.push(DUMMY_CALLSITE_HOLDER);
-        assert graphQueue.size() <= maxGraphs;
-    }
-
     public boolean hasUnprocessedGraphs() {
         return !graphQueue.isEmpty();
     }
@@ -498,16 +572,11 @@
         InlineInfo info = methodInvocation.callee();
         maxGraphs += info.numberOfMethods();
         assert graphQueue.size() <= maxGraphs;
-        double invokeProbability = methodInvocation.probability();
-        double invokeRelevance = methodInvocation.relevance();
         for (int i = 0; i < info.numberOfMethods(); i++) {
-            Inlineable elem = info.inlineableElementAt(i);
-            if (elem instanceof InlineableGraph) {
-                pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
-            } else {
-                assert elem instanceof InlineableMacroNode;
-                pushDummyGraph();
-            }
+            CallsiteHolder ch = methodInvocation.buildCallsiteHolderForElement(i);
+            assert (ch == DUMMY_CALLSITE_HOLDER) || !contains(ch.graph());
+            graphQueue.push(ch);
+            assert graphQueue.size() <= maxGraphs;
         }
     }
 
@@ -555,6 +624,7 @@
     }
 
     private boolean contains(StructuredGraph graph) {
+        assert graph != null;
         for (CallsiteHolder info : graphQueue) {
             if (info.graph() == graph) {
                 return true;
@@ -564,14 +634,56 @@
     }
 
     /**
+     * <p>
+     * The stack realized by {@link InliningData} grows and shrinks as choices are made among the
+     * alternatives below:
+     * <ol>
+     * <li>
+     * not worth inlining: pop stack top, which comprises:
+     * <ul>
+     * <li>pop any remaining graphs not yet delved into</li>
+     * <li>pop the current invocation</li>
+     * </ul>
+     * </li>
+     * <li>
+     * {@link #processNextInvoke() delve} into one of the callsites hosted in the current graph,
+     * such callsite is explored next by {@link #moveForward()}</li>
+     * <li>
+     * {@link #tryToInline(MethodInvocation, MethodInvocation, int) try to inline}: move past the
+     * current graph (remove it from the topmost element).
+     * <ul>
+     * <li>
+     * If that was the last one then {@link #tryToInline(MethodInvocation, MethodInvocation, int)
+     * try to inline} the callsite under consideration (ie, the "current invocation").</li>
+     * <li>
+     * Whether inlining occurs or not, that callsite is removed from the top of {@link InliningData}
+     * .</li>
+     * </ul>
+     * </li>
+     * </ol>
+     * </p>
+     *
+     * <p>
+     * Some facts about the alternatives above:
+     * <ul>
+     * <li>
+     * the first step amounts to backtracking, the 2nd one to depth-search, and the 3rd one also
+     * involves backtracking (however possibly after inlining).</li>
+     * <li>
+     * the choice of abandon-and-backtrack or delve-into depends on
+     * {@link InliningPolicy#isWorthInlining} and {@link InliningPolicy#continueInlining}.</li>
+     * <li>
+     * the 3rd choice is picked whenever none of the previous choices are made</li>
+     * </ul>
+     * </p>
+     *
      * @return true iff inlining was actually performed
      */
     public boolean moveForward() {
 
         final MethodInvocation currentInvocation = currentInvocation();
 
-        final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), currentInvocation.callee(), inliningDepth(),
-                        currentInvocation.probability(), currentInvocation.relevance(), false));
+        final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), currentInvocation, inliningDepth(), false));
         if (backtrack) {
             int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs();
             assert remainingGraphs > 0;
@@ -602,7 +714,7 @@
             popInvocation();
             final MethodInvocation parentInvoke = currentInvocation();
             try (Debug.Scope s = Debug.scope("Inlining", inliningContext())) {
-                return tryToInline(currentGraph(), currentInvocation, parentInvoke, inliningDepth() + 1);
+                return tryToInline(currentInvocation, parentInvoke, inliningDepth() + 1);
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningIterator.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningIterator.java	Mon Jun 30 12:02:19 2014 +0200
@@ -29,6 +29,7 @@
 
 import java.util.ArrayDeque;
 import java.util.Deque;
+import java.util.Iterator;
 import java.util.LinkedList;
 
 /**
@@ -81,6 +82,7 @@
             }
         }
 
+        assert invokes.size() == count(start.graph().getInvokes());
         return invokes;
     }
 
@@ -127,4 +129,14 @@
         }
         return true;
     }
+
+    private static int count(Iterable<Invoke> invokes) {
+        int count = 0;
+        Iterator<Invoke> iterator = invokes.iterator();
+        while (iterator.hasNext()) {
+            iterator.next();
+            count++;
+        }
+        return count;
+    }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,7 +28,23 @@
 import com.oracle.graal.nodes.CallTargetNode;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
 
+import java.util.BitSet;
+
+/**
+ * <p>
+ * An instance of this class denotes a callsite being analyzed for inlining.
+ * </p>
+ * <p>
+ * Each element of the {@link InliningData} stack contains one such instance, the accompanying
+ * {@link CallsiteHolder}s in that element represent feasible targets for the callsite in question.
+ * </p>
+ *
+ * @see InliningData#moveForward()
+ */
 public class MethodInvocation {
 
     private final InlineInfo callee;
@@ -38,11 +54,39 @@
 
     private int processedGraphs;
 
-    public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
+    /**
+     * <p>
+     * The immutable positions of freshly instantiated arguments (ie, positions in
+     * <code>callee.invoke.callTarget.arguments</code>).
+     * </p>
+     *
+     * <p>
+     * A freshly instantiated argument is either:
+     * <uL>
+     * <li>an {@link InliningData#isFreshInstantiation(com.oracle.graal.nodes.ValueNode)}</li>
+     * <li>a fixed-param of the graph containing the callsite (ie, of <code>callee.graph()</code>
+     * that contains <code>callee.invoke</code>)</li>
+     * </uL>
+     * </p>
+     *
+     * <p>
+     * Given those positions, the
+     * {@link com.oracle.graal.phases.common.inlining.walker.CallsiteHolderExplorable} instantiated
+     * in {@link #buildCallsiteHolderForElement(int)} can determine which of <i>its</i> parameters
+     * are fixed.
+     * </p>
+     */
+    private final BitSet freshlyInstantiatedArguments;
+
+    private final int sizeFreshArgs;
+
+    public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance, BitSet freshlyInstantiatedArguments) {
         this.callee = info;
         this.assumptions = assumptions;
         this.probability = probability;
         this.relevance = relevance;
+        this.freshlyInstantiatedArguments = freshlyInstantiatedArguments;
+        this.sizeFreshArgs = freshlyInstantiatedArguments == null ? 0 : freshlyInstantiatedArguments.cardinality();
     }
 
     public void incrementProcessedGraphs() {
@@ -79,6 +123,27 @@
         return callee == null;
     }
 
+    public BitSet getFreshlyInstantiatedArguments() {
+        return freshlyInstantiatedArguments;
+    }
+
+    public int getSizeFreshArgs() {
+        return sizeFreshArgs;
+    }
+
+    public CallsiteHolder buildCallsiteHolderForElement(int index) {
+        Inlineable elem = callee.inlineableElementAt(index);
+        if (elem instanceof InlineableGraph) {
+            InlineableGraph ig = (InlineableGraph) elem;
+            final double invokeProbability = probability * callee.probabilityAt(index);
+            final double invokeRelevance = relevance * callee.relevanceAt(index);
+            return new CallsiteHolderExplorable(ig.getGraph(), invokeProbability, invokeRelevance, freshlyInstantiatedArguments);
+        } else {
+            assert elem instanceof InlineableMacroNode;
+            return CallsiteHolderDummy.DUMMY_CALLSITE_HOLDER;
+        }
+    }
+
     @Override
     public String toString() {
         if (isRoot()) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/util/HashSetNodeChangeListener.java	Mon Jun 30 08:50:26 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2013, 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.phases.common.util;
-
-import java.util.*;
-
-import com.oracle.graal.graph.Graph.NodeChangedListener;
-import com.oracle.graal.graph.*;
-
-/**
- * A simple {@link NodeChangedListener} implementation that accumulates the changed nodes in a
- * {@link HashSet}.
- */
-public class HashSetNodeChangeListener implements NodeChangedListener {
-
-    private final Set<Node> changedNodes;
-
-    public HashSetNodeChangeListener() {
-        this.changedNodes = new HashSet<>();
-    }
-
-    @Override
-    public void nodeChanged(Node node) {
-        changedNodes.add(node);
-    }
-
-    public Set<Node> getChangedNodes() {
-        return changedNodes;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/util/HashSetNodeEventListener.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013, 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.phases.common.util;
+
+import java.util.*;
+
+import com.oracle.graal.graph.Graph.NodeEventListener;
+import com.oracle.graal.graph.*;
+
+/**
+ * A simple {@link NodeEventListener} implementation that accumulates event nodes in a
+ * {@link HashSet}.
+ */
+public class HashSetNodeEventListener implements NodeEventListener {
+
+    /**
+     * Accumulates all node events except for {@link NodeEventListener#nodeAdded(Node) node
+     * additions}.
+     */
+    public static class ExceptForAddedNodes extends HashSetNodeEventListener {
+        @Override
+        public void nodeAdded(Node node) {
+        }
+    }
+
+    private final Set<Node> nodes;
+
+    public HashSetNodeEventListener() {
+        this.nodes = new HashSet<>();
+    }
+
+    public void nodeAdded(Node node) {
+        nodes.add(node);
+    }
+
+    public void inputChanged(Node node) {
+        nodes.add(node);
+    }
+
+    public void usagesDroppedToZero(Node node) {
+        nodes.add(node);
+    }
+
+    /**
+     * Gets the set of nodes that were communicated to this listener.
+     */
+    public Set<Node> getNodes() {
+        return nodes;
+    }
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -94,12 +94,15 @@
 
     public final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) {
         try (TimerCloseable a = timer.start(); Scope s = Debug.scope(getClass(), this); Closeable c = memUseTracker.start()) {
-            BasePhase.this.run(graph, context);
+            this.run(graph, context);
             executionCount.increment();
             inputNodesCount.add(graph.getNodeCount());
             if (dumpGraph && Debug.isDumpEnabled()) {
                 Debug.dump(graph, "After phase %s", getName());
             }
+            if (Debug.isVerifyEnabled()) {
+                Debug.verify(graph, this, "After phase " + getName());
+            }
             assert graph.verify();
         } catch (Throwable t) {
             throw Debug.handle(t);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java	Mon Jun 30 12:02:19 2014 +0200
@@ -67,8 +67,8 @@
     protected boolean verify(StructuredGraph graph, PhaseContext context) {
         for (ObjectEqualsNode cn : graph.getNodes().filter(ObjectEqualsNode.class)) {
             // bail out if we compare an object of type klass with == or != (except null checks)
-            if (checkUsage(cn.x(), cn.y(), context.getMetaAccess()) && checkUsage(cn.y(), cn.x(), context.getMetaAccess())) {
-                throw new VerificationError("Verification of " + klass.getName() + " usage failed: Comparing " + cn.x() + " and " + cn.y() + " in " + graph.method() +
+            if (checkUsage(cn.getX(), cn.getY(), context.getMetaAccess()) && checkUsage(cn.getY(), cn.getX(), context.getMetaAccess())) {
+                throw new VerificationError("Verification of " + klass.getName() + " usage failed: Comparing " + cn.getX() + " and " + cn.getY() + " in " + graph.method() +
                                 " must use .equals() for object equality, not '==' or '!='");
             }
         }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -299,6 +299,7 @@
             for (Position pos : directInputPositions) {
                 writeByte(pos.getSubIndex() == NodeClass.NOT_ITERABLE ? 0 : 1);
                 writePoolObject(nodeClass.getName(pos));
+                writePoolObject(nodeClass.getInputType(pos));
             }
             Collection<Position> directSuccessorPositions = nodeClass.getFirstLevelSuccessorPositions();
             writeShort((char) directSuccessorPositions.size());
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -532,7 +532,7 @@
     }
 
     private void printInterval(Interval interval) {
-        out.printf("%s %s ", interval.operand, (isRegister(interval.operand) ? "fixed" : interval.kind().name()));
+        out.printf("%s %s ", interval.operand, (isRegister(interval.operand) ? "fixed" : interval.kind()));
         if (isRegister(interval.operand)) {
             out.printf("\"[%s|%c]\"", interval.operand, interval.operand.getKind().getTypeChar());
         } else {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java	Mon Jun 30 12:02:19 2014 +0200
@@ -34,10 +34,17 @@
 
 public class DebugEnvironment {
 
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean assertionsEnabled = false;
+        assert assertionsEnabled = true;
+        return assertionsEnabled;
+    }
+
     public static GraalDebugConfig initialize(PrintStream log) {
 
         // Ensure Graal runtime is initialized prior to Debug being initialized as the former
-        // included processing command line options used by the latter.
+        // may include processing command line options used by the latter.
         Graal.getRuntime();
 
         if (!Debug.isEnabled()) {
@@ -55,7 +62,16 @@
         if (DecompileAfterPhase.getValue() != null) {
             dumpHandlers.add(new DecompilerDebugDumpHandler());
         }
-        GraalDebugConfig debugConfig = new GraalDebugConfig(Log.getValue(), Meter.getValue(), TrackMemUse.getValue(), Time.getValue(), Dump.getValue(), MethodFilter.getValue(), log, dumpHandlers);
+        List<DebugVerifyHandler> verifyHandlers = new ArrayList<>();
+        String verifyFilter = Verify.getValue();
+        if (verifyFilter == null && assertionsEnabled()) {
+            verifyFilter = "";
+        }
+        if (verifyFilter != null) {
+            verifyHandlers.add(new NoDeadCodeVerifyHandler());
+        }
+        GraalDebugConfig debugConfig = new GraalDebugConfig(Log.getValue(), Meter.getValue(), TrackMemUse.getValue(), Time.getValue(), Dump.getValue(), verifyFilter, MethodFilter.getValue(), log,
+                        dumpHandlers, verifyHandlers);
         Debug.setConfig(debugConfig);
         return debugConfig;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/NoDeadCodeVerifyHandler.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,89 @@
+/*
+ * 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.printer;
+
+import static com.oracle.graal.printer.NoDeadCodeVerifyHandler.Options.*;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.options.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+
+/**
+ * Verifies that graphs have no dead code.
+ */
+public class NoDeadCodeVerifyHandler implements DebugVerifyHandler {
+
+    // The options below will be removed once all phases clean up their own dead code.
+
+    private static final int OFF = 0;
+    private static final int INFO = 1;
+    private static final int VERBOSE = 2;
+    private static final int FATAL = 3;
+
+    static class Options {
+        // @formatter:off
+        @Option(help = "Run level for NoDeadCodeVerifyHandler (0 = off, 1 = info, 2 = verbose, 3 = fatal)")
+        public static final OptionValue<Integer> NDCV = new OptionValue<>(0);
+        // @formatter:on
+    }
+
+    private static final Map<Class<?>, Boolean> discovered = new ConcurrentHashMap<>();
+
+    public void verify(Object object, Object... context) {
+        if (NDCV.getValue() != OFF) {
+            StructuredGraph graph = extract(StructuredGraph.class, object);
+            BasePhase<?> phase = extract(BasePhase.class, context);
+            assert phase != null : "a Phase context is required by " + getClass().getSimpleName();
+            if (graph != null) {
+                List<Node> before = graph.getNodes().snapshot();
+                new DeadCodeEliminationPhase().run(graph);
+                List<Node> after = graph.getNodes().snapshot();
+                assert after.size() <= before.size();
+                if (before.size() != after.size()) {
+                    before.removeAll(after);
+                    if (discovered.put(phase.getClass(), Boolean.TRUE) == null) {
+                        String message = extract(String.class, context);
+                        String prefix = message == null ? "" : message + ": ";
+                        String phaseClass = phase.getClass().getName();
+                        GraalInternalError error = new GraalInternalError("%sfound dead nodes in %s (phase class=%s): %s", prefix, graph, phaseClass, before);
+                        if (NDCV.getValue() == INFO) {
+                            System.out.println(error.getMessage());
+                        } else if (NDCV.getValue() == VERBOSE) {
+                            error.printStackTrace(System.out);
+                        } else {
+                            assert NDCV.getValue() == FATAL;
+                            throw error;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -197,12 +197,12 @@
     }
 
     @Override
-    public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) {
-        if (!(platformKind instanceof Kind)) {
+    public boolean canStoreValue(RegisterCategory category, PlatformKind lirKind) {
+        if (!(lirKind instanceof Kind)) {
             return false;
         }
 
-        Kind kind = (Kind) platformKind;
+        Kind kind = (Kind) lirKind;
         if (category == REG) {
             switch (kind) {
                 case Boolean:
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Mon Jun 30 12:02:19 2014 +0200
@@ -181,8 +181,8 @@
             StructuredGraph graph = convert.graph();
 
             Arguments args = new Arguments(key, graph.getGuardsStage(), tool.getLoweringStage());
-            args.add("input", convert.getInput());
-            args.add("result", graph.unique(new AMD64FloatConvertNode(convert.stamp(), convert.getOp(), convert.getInput())));
+            args.add("input", convert.getValue());
+            args.add("result", graph.unique(new AMD64FloatConvertNode(convert.stamp(), convert.getOp(), convert.getValue())));
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getOp(), graph, convert, template, args);
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -36,15 +37,13 @@
  * of the {@link FloatConvertNode} which, on AMD64 needs a {@link AMD64FloatConvertNode} plus some
  * fixup code that handles the corner cases that differ between AMD64 and Java.
  */
-public class AMD64FloatConvertNode extends FloatingNode implements ArithmeticLIRLowerable {
+public class AMD64FloatConvertNode extends UnaryNode implements ArithmeticLIRLowerable {
 
     private final FloatConvert op;
-    @Input private ValueNode value;
 
     public AMD64FloatConvertNode(Stamp stamp, FloatConvert op, ValueNode value) {
-        super(stamp);
+        super(stamp, value);
         this.op = op;
-        this.value = value;
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -52,7 +51,13 @@
         throw GraalInternalError.shouldNotReachHere();
     }
 
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        // nothing to do
+        return this;
+    }
+
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitFloatConvert(op, builder.operand(value)));
+        builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -123,7 +123,7 @@
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (getParameter().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(getParameter().asConstant()), graph());
+            return ConstantNode.forPrimitive(evalConst(getParameter().asConstant()));
         }
         return this;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/BitOpNodesTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2012, 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.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class BitOpNodesTest extends GraalCompilerTest {
+
+    private static final int INT_CONSTANT_1 = 0x80100010;
+    private static final int INT_CONSTANT_2 = 0x00011110;
+    private static final int INT_CONSTANT_3 = 0x00000000;
+
+    private static final long LONG_CONSTANT_1 = 0x8000000000100010L;
+    private static final long LONG_CONSTANT_2 = 0x0000000000011110L;
+    private static final long LONG_CONSTANT_3 = 0x0000000000000000L;
+
+    public static long dummyField;
+
+    /*
+     * Tests for BitCountNode canonicalizations.
+     */
+
+    public static int bitCountIntConstantSnippet() {
+        return Integer.bitCount(INT_CONSTANT_1) + Integer.bitCount(INT_CONSTANT_2) + Integer.bitCount(INT_CONSTANT_3);
+    }
+
+    @Test
+    public void testBitCountIntConstant() {
+        ValueNode result = parseAndInline("bitCountIntConstantSnippet");
+        Assert.assertEquals(7, result.asConstant().asInt());
+    }
+
+    public static int bitCountLongConstantSnippet() {
+        return Long.bitCount(LONG_CONSTANT_1) + Long.bitCount(LONG_CONSTANT_2) + Long.bitCount(LONG_CONSTANT_3);
+    }
+
+    public static int bitCountIntSnippet(int v) {
+        return Integer.bitCount(v & 0xFFFFFF | 0xFF);
+    }
+
+    @Test
+    public void testBitCountInt() {
+        ValueNode result = parseAndInline("bitCountIntSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 8, 24), result.stamp());
+    }
+
+    public static int bitCountIntEmptySnippet(int v) {
+        return Integer.bitCount(v & 0xFFFFFF);
+    }
+
+    @Test
+    public void testBitCountIntEmpty() {
+        ValueNode result = parseAndInline("bitCountIntEmptySnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 0, 24), result.stamp());
+    }
+
+    @Test
+    public void testBitCountLongConstant() {
+        ValueNode result = parseAndInline("bitCountLongConstantSnippet");
+        Assert.assertEquals(7, result.asConstant().asInt());
+    }
+
+    public static int bitCountLongSnippet(long v) {
+        return Long.bitCount(v & 0xFFFFFFFFFFL | 0xFFL);
+    }
+
+    @Test
+    public void testBitCountLong() {
+        ValueNode result = parseAndInline("bitCountLongSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 8, 40), result.stamp());
+    }
+
+    public static int bitCountLongEmptySnippet(long v) {
+        return Long.bitCount(v & 0xFFFFFFFFFFL);
+    }
+
+    @Test
+    public void testBitCountLongEmpty() {
+        ValueNode result = parseAndInline("bitCountLongEmptySnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 0, 40), result.stamp());
+    }
+
+    /*
+     * Tests for BitScanForwardNode
+     */
+
+    public static int scanForwardIntConstantSnippet() {
+        return Integer.numberOfTrailingZeros(INT_CONSTANT_1) + Integer.numberOfTrailingZeros(INT_CONSTANT_2) + Integer.numberOfTrailingZeros(INT_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanForwardIntConstant() {
+        ValueNode result = parseAndInline("scanForwardIntConstantSnippet");
+        Assert.assertEquals(40, result.asConstant().asInt());
+    }
+
+    public static int scanForwardIntSnippet(int v) {
+        return Integer.numberOfTrailingZeros(v & 0xFFF0 | 0xFF00);
+    }
+
+    @Test
+    public void testScanForwardInt() {
+        ValueNode result = parseAndInline("scanForwardIntSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 4, 8), result.stamp());
+    }
+
+    public static int scanForwardLongConstantSnippet() {
+        return Long.numberOfTrailingZeros(LONG_CONSTANT_1) + Long.numberOfTrailingZeros(LONG_CONSTANT_2) + Long.numberOfTrailingZeros(LONG_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanForwardLongConstant() {
+        ValueNode result = parseAndInline("scanForwardLongConstantSnippet");
+        Assert.assertEquals(72, result.asConstant().asInt());
+    }
+
+    public static int scanForwardLongSnippet(long v) {
+        return Long.numberOfTrailingZeros(v & 0xFFFF000000L | 0xFF00000000L);
+    }
+
+    @Test
+    public void testScanForwardLong() {
+        ValueNode result = parseAndInline("scanForwardLongSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 24, 32), result.stamp());
+    }
+
+    public static int scanForwardLongEmptySnippet(long v) {
+        int result = Long.numberOfTrailingZeros(v & 0xFFFF000000L);
+        dummyField = result;
+        return result;
+    }
+
+    @Test
+    public void testScanForwardLongEmpty() {
+        ValueNode result = parseAndInline("scanForwardLongEmptySnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, -1, 64), result.stamp());
+    }
+
+    /*
+     * Tests for BitScanReverseNode
+     */
+
+    public static int scanReverseIntConstantSnippet() {
+        return Integer.numberOfLeadingZeros(INT_CONSTANT_1) + Integer.numberOfLeadingZeros(INT_CONSTANT_2) + Integer.numberOfLeadingZeros(INT_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanReverseIntConstant() {
+        ValueNode result = parseAndInline("scanReverseIntConstantSnippet");
+        Assert.assertEquals(47, result.asConstant().asInt());
+    }
+
+    public static int scanReverseIntSnippet(int v) {
+        return Integer.numberOfLeadingZeros(v & 0xFFF0 | 0xFF0);
+    }
+
+    @Test
+    public void testScanReverseInt() {
+        ValueNode result = parseAndInline("scanReverseIntSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 16, 20), result.stamp());
+    }
+
+    public static int scanReverseLongConstantSnippet() {
+        return Long.numberOfLeadingZeros(LONG_CONSTANT_1) + Long.numberOfLeadingZeros(LONG_CONSTANT_2) + Long.numberOfLeadingZeros(LONG_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanReverseLongConstant() {
+        ValueNode result = parseAndInline("scanReverseLongConstantSnippet");
+        Assert.assertEquals(111, result.asConstant().asInt());
+    }
+
+    public static int scanReverseLongSnippet(long v) {
+        int result = Long.numberOfLeadingZeros(v & 0xFFF0);
+        dummyField = result;
+        return result;
+    }
+
+    @Test
+    public void testScanReverseLong() {
+        ValueNode result = parseAndInline("scanReverseLongSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 48, 64), result.stamp());
+    }
+
+    public static int scanReverseLongEmptySnippet(long v) {
+        int result = Long.numberOfLeadingZeros(v & 0xFFFF000000L);
+        dummyField = result;
+        return result;
+    }
+
+    @Test
+    public void testScanReverseLongEmpty() {
+        ValueNode result = parseAndInline("scanReverseLongEmptySnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 24, 64), result.stamp());
+    }
+
+    private ValueNode parseAndInline(String name) {
+        StructuredGraph graph = parse(name);
+        HighTierContext context = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE);
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+        canonicalizer.apply(graph, context);
+        new InliningPhase(canonicalizer).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        Assert.assertEquals(1, graph.getNodes(ReturnNode.class).count());
+        return graph.getNodes(ReturnNode.class).first().result();
+    }
+}
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -50,7 +50,7 @@
     protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) {
         InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first();
         if (ion != null) {
-            InstanceOfNode ionNew = graph.unique(new InstanceOfNode(ion.type(), ion.object(), profile));
+            InstanceOfNode ionNew = graph.unique(new InstanceOfNode(ion.type(), ion.getValue(), profile));
             graph.replaceFloating(ion, ionNew);
         }
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -114,7 +114,7 @@
             SignExtendNode convert = (SignExtendNode) location.getIndex();
             Assert.assertEquals(convert.getInputBits(), 32);
             Assert.assertEquals(convert.getResultBits(), 64);
-            Assert.assertEquals(graph.getParameter(1), convert.getInput());
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
         } else {
             Assert.assertEquals(graph.getParameter(1), location.getIndex());
         }
@@ -138,7 +138,7 @@
             SignExtendNode convert = (SignExtendNode) location.getIndex();
             Assert.assertEquals(convert.getInputBits(), 32);
             Assert.assertEquals(convert.getResultBits(), 64);
-            Assert.assertEquals(graph.getParameter(1), convert.getInput());
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
         } else {
             Assert.assertEquals(graph.getParameter(1), location.getIndex());
         }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -125,7 +125,7 @@
             SignExtendNode convert = (SignExtendNode) location.getIndex();
             Assert.assertEquals(convert.getInputBits(), 32);
             Assert.assertEquals(convert.getResultBits(), 64);
-            Assert.assertEquals(graph.getParameter(1), convert.getInput());
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
         } else {
             Assert.assertEquals(graph.getParameter(1), location.getIndex());
         }
@@ -154,7 +154,7 @@
             SignExtendNode convert = (SignExtendNode) location.getIndex();
             Assert.assertEquals(convert.getInputBits(), 32);
             Assert.assertEquals(convert.getResultBits(), 64);
-            Assert.assertEquals(graph.getParameter(1), convert.getInput());
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
         } else {
             Assert.assertEquals(graph.getParameter(1), location.getIndex());
         }
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java	Mon Jun 30 12:02:19 2014 +0200
@@ -124,6 +124,7 @@
 
     private void findConstructor(TypeElement nodeClass, TypeMirror[] signature, ExecutableElement intrinsicMethod, AnnotationMirror intrinsicAnnotation) {
         List<ExecutableElement> constructors = ElementFilter.constructorsIn(nodeClass.getEnclosedElements());
+        List<String> failureReasons = new ArrayList<>();
 
         nextConstructor: for (ExecutableElement constructor : constructors) {
             int sIdx = 0;
@@ -141,13 +142,16 @@
                     TypeMirror varargsType = ((ArrayType) paramType).getComponentType();
                     while (sIdx < signature.length) {
                         if (!isTypeCompatible(varargsType, signature[sIdx++])) {
+                            failureReasons.add(String.format("Constructor %s failed because the types of argument %d are incompatible: %s != %s", constructor, sIdx, varargsType, signature[sIdx - 1]));
                             continue nextConstructor;
                         }
                     }
                 } else if (sIdx >= signature.length) {
                     // too many arguments in intrinsic method
+                    failureReasons.add(String.format("Too many arguments for %s", constructor));
                     continue nextConstructor;
                 } else if (!isTypeCompatible(paramType, signature[sIdx++])) {
+                    failureReasons.add(String.format("Constructor %s failed because the types of argument %d are incompatible: %s != %s", constructor, sIdx, paramType, signature[sIdx - 1]));
                     continue nextConstructor;
                 }
             }
@@ -158,10 +162,17 @@
             }
 
             // too many arguments in constructor
+            failureReasons.add(String.format("Not enough arguments for %s", constructor));
         }
 
         // not found
-        env.getMessager().printMessage(Kind.ERROR, "Could not find matching constructor for node intrinsic.", intrinsicMethod, intrinsicAnnotation);
+        if (failureReasons.isEmpty()) {
+            env.getMessager().printMessage(Kind.ERROR, "Could not find matching constructor for node intrinsic.", intrinsicMethod, intrinsicAnnotation);
+        } else {
+            for (String reason : failureReasons) {
+                env.getMessager().printMessage(Kind.ERROR, reason, intrinsicMethod, intrinsicAnnotation);
+            }
+        }
     }
 
     private boolean isTypeCompatible(TypeMirror originalType, TypeMirror substitutionType) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java	Mon Jun 30 12:02:19 2014 +0200
@@ -34,6 +34,11 @@
 
     @MethodSubstitution
     public static Object newInstance(Class<?> componentType, int length) throws NegativeArraySizeException {
+        // The error cases must be handled here since DynamicNewArrayNode can only deoptimize the
+        // caller in response to exceptions.
+        if (componentType == void.class) {
+            throw new IllegalArgumentException();
+        }
         return DynamicNewArrayNode.newArray(GuardingPiNode.guardingNonNull(componentType), length);
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.replacements;
 
+import static com.oracle.graal.api.code.BytecodeFrame.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -129,15 +131,15 @@
                 FrameState frameState = stateSplit.stateAfter();
                 if (frameState != null) {
                     if (stateSplit.hasSideEffect()) {
-                        stateSplit.setStateAfter(createInvalidFrameState(node));
+                        setStateAfter(node.graph(), stateSplit, INVALID_FRAMESTATE_BCI, false);
                         state = state.addSideEffect(stateSplit);
                     } else if (currentState.invalid) {
-                        stateSplit.setStateAfter(createInvalidFrameState(node));
+                        setStateAfter(node.graph(), stateSplit, INVALID_FRAMESTATE_BCI, false);
                     } else {
                         stateSplit.setStateAfter(null);
-                    }
-                    if (frameState.usages().isEmpty()) {
-                        GraphUtil.killWithUnusedFloatingInputs(frameState);
+                        if (frameState.usages().isEmpty()) {
+                            GraphUtil.killWithUnusedFloatingInputs(frameState);
+                        }
                     }
                 }
             }
@@ -176,18 +178,14 @@
             for (Node returnSideEffect : returnSideEffects) {
                 if (!unwindSideEffects.contains(returnSideEffect) && !maskedSideEffects.contains(returnSideEffect)) {
                     StateSplit split = (StateSplit) returnSideEffect;
-                    if (split.stateAfter() != null) {
-                        split.setStateAfter(graph.add(new FrameState(BytecodeFrame.AFTER_BCI)));
-                    }
+                    setStateAfter(graph, split, AFTER_BCI, true);
                 }
             }
 
             for (Node unwindSideEffect : unwindSideEffects) {
                 if (!returnSideEffects.contains(unwindSideEffect) && !maskedSideEffects.contains(unwindSideEffect)) {
                     StateSplit split = (StateSplit) unwindSideEffect;
-                    if (split.stateAfter() != null) {
-                        split.setStateAfter(graph.add(new FrameState(BytecodeFrame.AFTER_EXCEPTION_BCI)));
-                    }
+                    setStateAfter(graph, split, AFTER_EXCEPTION_BCI, true);
                 }
             }
         }
@@ -207,15 +205,34 @@
             }
 
             if (isNowInvalid) {
-                loop.setStateAfter(createInvalidFrameState(loop));
+                setStateAfter(loop.graph(), loop, INVALID_FRAMESTATE_BCI, false);
             }
 
             IterationState endState = IterationState.merge(loop, info.endStates.values(), isNowInvalid);
             return ReentrantNodeIterator.processLoop(this, loop, endState).exitStates;
         }
 
-        private static FrameState createInvalidFrameState(FixedNode node) {
-            return node.graph().add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
+        /**
+         * Creates and sets a special frame state for a node. If the existing frame state is
+         * non-null and has no other usages, it is deleted via
+         * {@link GraphUtil#killWithUnusedFloatingInputs(Node)}.
+         *
+         * @param graph the graph context
+         * @param node the node whose frame state is updated
+         * @param bci {@link BytecodeFrame#AFTER_BCI}, {@link BytecodeFrame#AFTER_EXCEPTION_BCI} or
+         *            {@link BytecodeFrame#INVALID_FRAMESTATE_BCI}
+         * @param replaceOnly only perform the update if the node currently has a non-null frame
+         *            state
+         */
+        private static void setStateAfter(StructuredGraph graph, StateSplit node, int bci, boolean replaceOnly) {
+            assert bci == AFTER_BCI || bci == AFTER_EXCEPTION_BCI || bci == INVALID_FRAMESTATE_BCI;
+            FrameState currentStateAfter = node.stateAfter();
+            if (currentStateAfter != null || !replaceOnly) {
+                node.setStateAfter(graph.add(new FrameState(bci)));
+                if (currentStateAfter != null && currentStateAfter.usages().isEmpty()) {
+                    GraphUtil.killWithUnusedFloatingInputs(currentStateAfter);
+                }
+            }
         }
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Mon Jun 30 12:02:19 2014 +0200
@@ -109,7 +109,7 @@
         StructuredGraph graph = loadField.graph();
         ResolvedJavaField field = loadField.field();
         ValueNode object = loadField.isStatic() ? staticFieldBase(graph, field) : loadField.object();
-        Stamp loadStamp = loadStamp(loadField.stamp(), field.getKind(), true);
+        Stamp loadStamp = loadStamp(loadField.stamp(), field.getKind());
         ConstantLocationNode location = createFieldLocation(graph, field, false);
         assert location != null : "Field that is loaded must not be eliminated";
 
@@ -158,7 +158,7 @@
         StructuredGraph graph = loadIndexed.graph();
         Kind elementKind = loadIndexed.elementKind();
         LocationNode location = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
-        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind, true);
+        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
 
         ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), location, loadStamp, BarrierType.NONE));
         ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
@@ -223,7 +223,7 @@
         if (graph.getGuardsStage().ordinal() < StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) {
             return;
         }
-        ValueNode hub = createReadHub(graph, loadHub.object(), loadHub.getGuard());
+        ValueNode hub = createReadHub(graph, loadHub.getValue(), loadHub.getGuard());
         graph.replaceFloating(loadHub, hub);
     }
 
@@ -273,7 +273,7 @@
     }
 
     protected ReadNode createUnsafeRead(StructuredGraph graph, UnsafeLoadNode load, GuardingNode guard) {
-        boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
+        boolean compressible = load.accessKind() == Kind.Object;
         Kind readKind = load.accessKind();
         LocationNode location = createLocation(load);
         Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible);
@@ -503,6 +503,10 @@
 
     protected abstract LocationIdentity initLocationIdentity();
 
+    public Stamp loadStamp(Stamp stamp, Kind kind) {
+        return loadStamp(stamp, kind, true);
+    }
+
     protected Stamp loadStamp(Stamp stamp, Kind kind, @SuppressWarnings("unused") boolean compressible) {
         switch (kind) {
             case Boolean:
@@ -580,21 +584,21 @@
             SignExtendNode extend = (SignExtendNode) offset;
             if (extend.getResultBits() == 64) {
                 signExtend = true;
-                offset = extend.getInput();
+                offset = extend.getValue();
             }
         }
         if (offset instanceof IntegerAddNode) {
             IntegerAddNode integerAddNode = (IntegerAddNode) offset;
-            if (integerAddNode.y() instanceof ConstantNode) {
-                displacement = integerAddNode.y().asConstant().asLong();
-                offset = integerAddNode.x();
+            if (integerAddNode.getY() instanceof ConstantNode) {
+                displacement = integerAddNode.getY().asConstant().asLong();
+                offset = integerAddNode.getX();
             }
         }
 
         if (offset instanceof LeftShiftNode) {
             LeftShiftNode leftShiftNode = (LeftShiftNode) offset;
-            if (leftShiftNode.y() instanceof ConstantNode) {
-                long shift = leftShiftNode.y().asConstant().asLong();
+            if (leftShiftNode.getY() instanceof ConstantNode) {
+                long shift = leftShiftNode.getY().asConstant().asLong();
                 if (shift >= 1 && shift <= 3) {
                     if (shift == 1) {
                         indexScaling = 2;
@@ -603,7 +607,7 @@
                     } else {
                         indexScaling = 8;
                     }
-                    offset = leftShiftNode.x();
+                    offset = leftShiftNode.getX();
                 }
             }
         }
@@ -622,13 +626,15 @@
     protected GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
         StructuredGraph graph = n.graph();
         ValueNode array = n.array();
-        ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection());
+        ValueNode arrayLength = readArrayLength(array, tool.getConstantReflection());
         if (arrayLength == null) {
             Stamp stamp = StampFactory.positiveInt();
             ReadNode readArrayLength = graph.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, arrayLengthOffset(), graph), stamp, BarrierType.NONE));
             graph.addBeforeFixed(n, readArrayLength);
             readArrayLength.setGuard(createNullCheck(array, readArrayLength, tool));
             arrayLength = readArrayLength;
+        } else {
+            arrayLength = arrayLength.isAlive() ? arrayLength : graph.addOrUniqueWithInputs(arrayLength);
         }
 
         if (arrayLength.isConstant() && n.index().isConstant()) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Mon Jun 30 12:02:19 2014 +0200
@@ -208,7 +208,7 @@
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
         ReplacementsImpl repl = new ReplacementsImpl(providers, snippetReflection, new Assumptions(false), providers.getCodeCache().getTarget());
         StructuredGraph calleeGraph = repl.makeGraph(method, null, method, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
-        InliningUtil.inline(invoke, calleeGraph, false);
+        InliningUtil.inline(invoke, calleeGraph, false, null);
     }
 
     protected void pushStructure(Structure structure) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Mon Jun 30 12:02:19 2014 +0200
@@ -141,7 +141,7 @@
                 assert testValue.isConstant();
                 return LogicConstantNode.forBoolean(result.asConstant().equals(testValue.asConstant()), result.graph());
             }
-            if (condition == null || condition.y() != testValue) {
+            if (condition == null || condition.getY() != testValue) {
                 // Re-use previously generated condition if the trueValue for the test is the same
                 condition = createCompareNode(result.graph(), Condition.EQ, result, testValue);
             }
@@ -208,7 +208,7 @@
         }
 
         @Override
-        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMapNode mmap) {
+        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap) {
             assert newNode instanceof PhiNode;
             assert oldNode == instanceOf;
             newNode.inferStamp();
@@ -234,19 +234,17 @@
         public void replaceUsingInstantiation() {
             ValueNode newValue = instantiation.asMaterialization(usage.graph(), trueValue, falseValue);
             usage.replaceAtUsages(newValue);
-            usage.clearInputs();
             assert usage.usages().isEmpty();
             GraphUtil.killWithUnusedFloatingInputs(usage);
         }
 
         @Override
-        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMapNode mmap) {
+        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap) {
             assert newNode instanceof PhiNode;
             assert oldNode == instanceOf;
             newNode.inferStamp();
             instantiation.initialize(newNode, trueValue, falseValue);
             usage.replaceAtUsages(newNode);
-            usage.clearInputs();
             assert usage.usages().isEmpty();
             GraphUtil.killWithUnusedFloatingInputs(usage);
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntegerSubstitutions.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntegerSubstitutions.java	Mon Jun 30 12:02:19 2014 +0200
@@ -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
@@ -23,6 +23,7 @@
 package com.oracle.graal.replacements;
 
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @ClassSubstitution(Integer.class)
@@ -53,4 +54,14 @@
     public static int bitCount(int i) {
         return BitCountNode.bitCount(i);
     }
+
+    @MethodSubstitution
+    public static int divideUnsigned(int dividend, int divisor) {
+        return UnsignedDivNode.unsignedDivide(dividend, divisor);
+    }
+
+    @MethodSubstitution
+    public static int remainderUnsigned(int dividend, int divisor) {
+        return UnsignedRemNode.unsignedRemainder(dividend, divisor);
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/LongSubstitutions.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/LongSubstitutions.java	Mon Jun 30 12:02:19 2014 +0200
@@ -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
@@ -23,6 +23,7 @@
 package com.oracle.graal.replacements;
 
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @ClassSubstitution(Long.class)
@@ -53,4 +54,14 @@
     public static int bitCount(long i) {
         return BitCountNode.bitCount(i);
     }
+
+    @MethodSubstitution
+    public static long divideUnsigned(long dividend, long divisor) {
+        return UnsignedDivNode.unsignedDivide(dividend, divisor);
+    }
+
+    @MethodSubstitution
+    public static long remainderUnsigned(long dividend, long divisor) {
+        return UnsignedRemNode.unsignedRemainder(dividend, divisor);
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Jun 30 12:02:19 2014 +0200
@@ -483,7 +483,10 @@
             if (!SnippetTemplate.hasConstantParameter(method)) {
                 NodeIntrinsificationVerificationPhase.verify(graph);
             }
+            int sideEffectCount = 0;
+            assert (sideEffectCount = graph.getNodes().filter(e -> e instanceof StateSplit && ((StateSplit) e).hasSideEffect()).count()) >= 0;
             new ConvertDeoptimizeToGuardPhase().apply(graph);
+            assert sideEffectCount == graph.getNodes().filter(e -> e instanceof StateSplit && ((StateSplit) e).hasSideEffect()).count() : "deleted side effecting node";
 
             switch (frameStateProcessing) {
                 case Removal:
@@ -586,7 +589,7 @@
                         if (isInlinable(substitutedMethod)) {
                             final StructuredGraph originalGraph = buildInitialGraph(substitutedMethod);
                             Mark mark = graph.getMark();
-                            InliningUtil.inline(callTarget.invoke(), originalGraph, true);
+                            InliningUtil.inline(callTarget.invoke(), originalGraph, true, null);
                             for (MethodCallTargetNode inlinedCallTarget : graph.getNewNodes(mark).filter(MethodCallTargetNode.class)) {
                                 if (doNotInline == null) {
                                     doNotInline = new HashSet<>();
@@ -620,7 +623,7 @@
                                     targetGraph = parseGraph(callee, policy, inliningDepth + 1);
                                 }
                                 Object beforeInlineData = beforeInline(callTarget, targetGraph);
-                                InliningUtil.inline(callTarget.invoke(), targetGraph, true);
+                                InliningUtil.inline(callTarget.invoke(), targetGraph, true, null);
                                 Debug.dump(graph, "after inlining %s", callee);
                                 afterInline(graph, targetGraph, beforeInlineData);
                             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsUtil.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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 com.oracle.graal.replacements.nodes.*;
+
+public class ReplacementsUtil {
+    private ReplacementsUtil() {
+        // empty
+    }
+
+    private static final boolean REPLACEMENTS_ASSERTIONS_ENABLED;
+
+    static {
+        boolean assertionsEnabled = false;
+        assert (assertionsEnabled = true) != false;
+        REPLACEMENTS_ASSERTIONS_ENABLED = assertionsEnabled;
+    }
+
+    /**
+     * Asserts that condition evaluates to true by the time compilation is finished. This is
+     * intended to be used within snippets or stubs, and will lead to a compile error if the
+     * assertion fails.
+     */
+    public static void staticAssert(boolean condition, String message) {
+        if (REPLACEMENTS_ASSERTIONS_ENABLED) {
+            AssertionNode.assertion(true, condition, message);
+        }
+    }
+
+    /**
+     * Asserts that condition evaluates to true at runtime. This is intended to be used within
+     * snippets or stubs, and will lead to a VM error if it fails.
+     */
+    public static void runtimeAssert(boolean condition, String message) {
+        if (REPLACEMENTS_ASSERTIONS_ENABLED) {
+            AssertionNode.assertion(false, condition, message);
+        }
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Jun 30 12:02:19 2014 +0200
@@ -35,6 +35,7 @@
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
+import java.util.stream.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -364,7 +365,7 @@
         }
 
         public ValueNode length() {
-            return ConstantNode.forInt(varargs.length, graph());
+            return ConstantNode.forInt(varargs.length);
         }
     }
 
@@ -618,6 +619,7 @@
                     Mark mark = snippetCopy.getMark();
                     LoopTransformations.fullUnroll(loop, phaseContext, new CanonicalizerPhase(true));
                     new CanonicalizerPhase(true).applyIncremental(snippetCopy, phaseContext, mark);
+                    loop.deleteUnusedNodes();
                 }
                 GraphUtil.removeFixedWithUnusedInputs(explodeLoop);
                 exploded = true;
@@ -676,38 +678,33 @@
 
         Debug.dump(snippet, "SnippetTemplate after fixing memory anchoring");
 
-        List<ReturnNode> returnNodes = new ArrayList<>(4);
-        List<MemoryMapNode> memMaps = new ArrayList<>(4);
         StartNode entryPointNode = snippet.start();
-        boolean anchorUsed = false;
-        for (ReturnNode retNode : snippet.getNodes(ReturnNode.class)) {
-            MemoryMapNode memMap = retNode.getMemoryMap();
-            anchorUsed |= memMap.replaceLastLocationAccess(snippetCopy.start(), memoryAnchor);
-            memMaps.add(memMap);
-            retNode.setMemoryMap(null);
-            returnNodes.add(retNode);
-            if (memMap.usages().isEmpty()) {
-                memMap.safeDelete();
-            }
-        }
-        if (memoryAnchor.usages().isEmpty() && !anchorUsed) {
+        if (memoryAnchor.usages().isEmpty()) {
             memoryAnchor.safeDelete();
         } else {
             snippetCopy.addAfterFixed(snippetCopy.start(), memoryAnchor);
         }
-        assert snippet.getNodes().filter(MemoryMapNode.class).isEmpty();
+        List<ReturnNode> returnNodes = snippet.getNodes(ReturnNode.class).snapshot();
         if (returnNodes.isEmpty()) {
             this.returnNode = null;
             this.memoryMap = null;
         } else if (returnNodes.size() == 1) {
             this.returnNode = returnNodes.get(0);
-            this.memoryMap = memMaps.get(0);
+            this.memoryMap = returnNode.getMemoryMap();
         } else {
             MergeNode merge = snippet.add(new MergeNode());
-            ValueNode returnValue = InliningUtil.mergeReturns(merge, returnNodes);
+            List<MemoryMapNode> memMaps = returnNodes.stream().map(n -> n.getMemoryMap()).collect(Collectors.toList());
+            ValueNode returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
             this.returnNode = snippet.add(new ReturnNode(returnValue));
-            this.memoryMap = FloatingReadPhase.mergeMemoryMaps(merge, memMaps);
+            MemoryMapImpl mmap = FloatingReadPhase.mergeMemoryMaps(merge, memMaps);
+            this.memoryMap = snippet.unique(new MemoryMapNode(mmap.getMap()));
             merge.setNext(this.returnNode);
+
+            for (MemoryMapNode mm : memMaps) {
+                if (mm.isAlive()) {
+                    mm.safeDelete();
+                }
+            }
         }
 
         this.sideEffectNodes = curSideEffectNodes;
@@ -797,7 +794,7 @@
     private final ArrayList<Node> nodes;
 
     /**
-     * map of killing locations to memory checkpoints (nodes).
+     * Map of killing locations to memory checkpoints (nodes).
      */
     private final MemoryMapNode memoryMap;
 
@@ -896,7 +893,7 @@
         /**
          * Replaces all usages of {@code oldNode} with direct or indirect usages of {@code newNode}.
          */
-        void replace(ValueNode oldNode, ValueNode newNode, MemoryMapNode mmap);
+        void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap);
     }
 
     /**
@@ -918,7 +915,7 @@
         }
 
         @Override
-        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMapNode mmap) {
+        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap) {
             if (mmap != null) {
                 for (Node usage : oldNode.usages().snapshot()) {
                     LocationIdentity identity = getLocationIdentity(usage);
@@ -960,12 +957,12 @@
             // no floating reads yet, ignore locations created while lowering
             return true;
         }
-        if (memoryMap == null || ((MemoryMapImpl) memoryMap).isEmpty()) {
-            // there're no kills in the snippet graph
+        if (memoryMap == null || memoryMap.isEmpty()) {
+            // there are no kills in the snippet graph
             return true;
         }
 
-        Set<LocationIdentity> kills = new HashSet<>(((MemoryMapImpl) memoryMap).getLocations());
+        Set<LocationIdentity> kills = new HashSet<>(memoryMap.getLocations());
 
         if (replacee instanceof MemoryCheckpoint.Single) {
             // check if some node in snippet graph also kills the same location
@@ -1009,10 +1006,10 @@
         return true;
     }
 
-    private class DuplicateMapper extends MemoryMapNode {
+    private class DuplicateMapper implements MemoryMap {
 
         private final Map<Node, Node> duplicates;
-        @Input private StartNode replaceeStart;
+        private StartNode replaceeStart;
 
         public DuplicateMapper(Map<Node, Node> duplicates, StartNode replaceeStart) {
             this.duplicates = duplicates;
@@ -1032,14 +1029,9 @@
         }
 
         @Override
-        public Set<LocationIdentity> getLocations() {
+        public Collection<LocationIdentity> getLocations() {
             return memoryMap.getLocations();
         }
-
-        @Override
-        public boolean replaceLastLocationAccess(MemoryNode oldNode, MemoryNode newNode) {
-            throw GraalInternalError.shouldNotReachHere();
-        }
     }
 
     /**
@@ -1133,7 +1125,7 @@
             if (returnNode != null && !(replacee instanceof ControlSinkNode)) {
                 ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode);
                 returnValue = returnDuplicate.result();
-                MemoryMapNode mmap = new DuplicateMapper(duplicates, replaceeGraph.start());
+                MemoryMap mmap = new DuplicateMapper(duplicates, replaceeGraph.start());
                 if (returnValue == null && replacee.usages().isNotEmpty() && replacee instanceof MemoryCheckpoint) {
                     replacer.replace(replacee, null, mmap);
                 } else {
@@ -1147,14 +1139,11 @@
                         next = fwn.next();
                         fwn.setNext(null);
                     }
-                    returnDuplicate.clearInputs();
                     returnDuplicate.replaceAndDelete(next);
                 }
             }
 
             // Remove the replacee from its graph
-            replacee.clearInputs();
-            replacee.replaceAtUsages(null);
             GraphUtil.killCFG(replacee);
 
             Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this);
@@ -1241,7 +1230,6 @@
             replacer.replace(replacee, returnValue, new DuplicateMapper(duplicates, replaceeGraph.start()));
 
             if (returnDuplicate.isAlive()) {
-                returnDuplicate.clearInputs();
                 returnDuplicate.replaceAndDelete(next);
             }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsignedMathSubstitutions.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsignedMathSubstitutions.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -26,10 +26,7 @@
 import static com.oracle.graal.nodes.calc.ConditionalNode.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.nodes.calc.*;
 
 /**
@@ -101,7 +98,7 @@
      */
     @MethodSubstitution
     public static int divide(int a, int b) {
-        return unsignedDivide(Kind.Int, a, b);
+        return UnsignedDivNode.unsignedDivide(a, b);
     }
 
     /**
@@ -109,7 +106,7 @@
      */
     @MethodSubstitution
     public static int remainder(int a, int b) {
-        return unsignedRemainder(Kind.Int, a, b);
+        return UnsignedRemNode.unsignedRemainder(a, b);
     }
 
     /**
@@ -117,7 +114,7 @@
      */
     @MethodSubstitution
     public static long divide(long a, long b) {
-        return unsignedDivide(Kind.Long, a, b);
+        return UnsignedDivNode.unsignedDivide(a, b);
     }
 
     /**
@@ -125,18 +122,6 @@
      */
     @MethodSubstitution
     public static long remainder(long a, long b) {
-        return unsignedRemainder(Kind.Long, a, b);
+        return UnsignedRemNode.unsignedRemainder(a, b);
     }
-
-    @NodeIntrinsic(UnsignedDivNode.class)
-    private static native int unsignedDivide(@ConstantNodeParameter Kind kind, int a, int b);
-
-    @NodeIntrinsic(UnsignedDivNode.class)
-    private static native long unsignedDivide(@ConstantNodeParameter Kind kind, long a, long b);
-
-    @NodeIntrinsic(UnsignedRemNode.class)
-    private static native int unsignedRemainder(@ConstantNodeParameter Kind kind, int a, int b);
-
-    @NodeIntrinsic(UnsignedRemNode.class)
-    private static native long unsignedRemainder(@ConstantNodeParameter Kind kind, long a, long b);
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -26,7 +26,6 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
@@ -67,7 +66,7 @@
             return null;
         }
         if (GraphUtil.unproxify(array1) == GraphUtil.unproxify(array2)) {
-            return ConstantNode.forBoolean(true, graph());
+            return ConstantNode.forBoolean(true);
         }
         return this;
     }
@@ -130,8 +129,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        Variable result = gen.newVariable(Kind.Int);
-        gen.emitArrayEquals(kind, result, gen.operand(array1), gen.operand(array2), gen.operand(length));
+        Value result = gen.getLIRGeneratorTool().emitArrayEquals(kind, gen.operand(array1), gen.operand(array2), gen.operand(length));
         gen.setResult(this, result);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,87 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Assertion nodes will go away as soon as the value evaluates to true. Compile-time assertions will
+ * fail if this has not happened by the time the node is lowered to LIR, while runtime assertions
+ * may need to insert a check.
+ */
+public class AssertionNode extends FixedWithNextNode implements Lowerable, Canonicalizable, LIRLowerable {
+
+    @Input private ValueNode value;
+
+    private final boolean compileTimeAssertion;
+    private final String message;
+
+    public AssertionNode(boolean compileTimeAssertion, ValueNode value, String message) {
+        super(StampFactory.forVoid());
+        this.value = value;
+        this.compileTimeAssertion = compileTimeAssertion;
+        this.message = message;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    public String message() {
+        return message;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value.isConstant() && value.asConstant().asInt() != 0) {
+            return null;
+        }
+        return this;
+    }
+
+    public void lower(LoweringTool tool) {
+        if (!compileTimeAssertion) {
+            tool.getLowerer().lower(this, tool);
+        }
+    }
+
+    public void generate(NodeLIRBuilderTool generator) {
+        assert compileTimeAssertion;
+        if (value.isConstant() && value.asConstant().asInt() == 0) {
+            throw new GraalInternalError("failed compile-time assertion: %s", message);
+        } else {
+            throw new GraalInternalError("failed compile-time assertion (value %s): %s", value, message);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static void assertion(@ConstantNodeParameter boolean compileTimeAssertion, boolean value, @ConstantNodeParameter String message) {
+        assert value : message;
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -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
@@ -24,31 +24,31 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class BitCountNode extends FloatingNode implements LIRLowerable, Canonicalizable {
-
-    @Input private ValueNode value;
+public class BitCountNode extends UnaryNode implements LIRLowerable {
 
     public BitCountNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()));
-        this.value = value;
+        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        assert value.getKind() == Kind.Int || value.getKind() == Kind.Long;
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            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());
-            }
+    public boolean inferStamp() {
+        IntegerStamp valueStamp = (IntegerStamp) getValue().stamp();
+        assert (valueStamp.downMask() & IntegerStamp.defaultMask(valueStamp.getBits())) == valueStamp.downMask();
+        assert (valueStamp.upMask() & IntegerStamp.defaultMask(valueStamp.getBits())) == valueStamp.upMask();
+        return updateStamp(StampFactory.forInteger(Kind.Int, bitCount(valueStamp.downMask()), bitCount(valueStamp.upMask())));
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            Constant c = forValue.asConstant();
+            return ConstantNode.forInt(forValue.getKind() == Kind.Int ? bitCount(c.asInt()) : bitCount(c.asLong()));
         }
         return this;
     }
@@ -65,8 +65,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        Variable result = gen.newVariable(Kind.Int);
-        gen.emitBitCount(result, gen.operand(value));
+        Value result = gen.getLIRGeneratorTool().emitBitCount(gen.operand(getValue()));
         gen.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,31 +24,46 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class BitScanForwardNode extends FloatingNode implements LIRLowerable, Canonicalizable {
-
-    @Input private ValueNode value;
+/**
+ * Determines the index of the least significant "1" bit. Note that the result is undefined if the
+ * input is zero.
+ */
+public class BitScanForwardNode extends UnaryNode implements LIRLowerable {
 
     public BitScanForwardNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()));
-        this.value = value;
+        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        assert value.getKind() == Kind.Int || value.getKind() == Kind.Long;
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            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());
-            }
+    public boolean inferStamp() {
+        IntegerStamp valueStamp = (IntegerStamp) getValue().stamp();
+        int min;
+        int max;
+        long mask = IntegerStamp.defaultMask(valueStamp.getBits());
+        int firstAlwaysSetBit = scan(valueStamp.downMask() & mask);
+        if (firstAlwaysSetBit == -1) {
+            int lastMaybeSetBit = BitScanReverseNode.scan(valueStamp.upMask() & mask);
+            min = -1;
+            max = lastMaybeSetBit;
+        } else {
+            int firstMaybeSetBit = scan(valueStamp.upMask() & mask);
+            min = firstMaybeSetBit;
+            max = firstAlwaysSetBit;
+        }
+        return updateStamp(StampFactory.forInteger(Kind.Int, min, max));
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            Constant c = forValue.asConstant();
+            return ConstantNode.forInt(forValue.getKind() == Kind.Int ? scan(c.asInt()) : scan(c.asLong()));
         }
         return this;
     }
@@ -72,8 +87,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        Variable result = gen.newVariable(Kind.Int);
-        gen.emitBitScanForward(result, gen.operand(value));
+        Value result = gen.getLIRGeneratorTool().emitBitScanForward(gen.operand(getValue()));
         gen.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,31 +24,44 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class BitScanReverseNode extends FloatingNode implements LIRLowerable, Canonicalizable {
-
-    @Input private ValueNode value;
+/**
+ * Determines the index of the most significant "1" bit. Note that the result is undefined if the
+ * input is zero.
+ */
+public class BitScanReverseNode extends UnaryNode implements LIRLowerable {
 
     public BitScanReverseNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()));
-        this.value = value;
+        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        assert value.getKind() == Kind.Int || value.getKind() == Kind.Long;
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            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());
-            }
+    public boolean inferStamp() {
+        IntegerStamp valueStamp = (IntegerStamp) getValue().stamp();
+        int min;
+        int max;
+        long mask = IntegerStamp.defaultMask(valueStamp.getBits());
+        int lastAlwaysSetBit = scan(valueStamp.downMask() & mask);
+        if (lastAlwaysSetBit == -1) {
+            min = -1;
+        } else {
+            min = lastAlwaysSetBit;
+        }
+        int lastMaybeSetBit = scan(valueStamp.upMask() & mask);
+        max = lastMaybeSetBit;
+        return updateStamp(StampFactory.forInteger(Kind.Int, min, max));
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            Constant c = forValue.asConstant();
+            return ConstantNode.forInt(forValue.getKind() == Kind.Int ? scan(c.asInt()) : scan(c.asLong()));
         }
         return this;
     }
@@ -79,8 +92,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        Variable result = gen.newVariable(Kind.Int);
-        gen.getLIRGeneratorTool().emitBitScanReverse(result, gen.operand(value));
+        Value result = gen.getLIRGeneratorTool().emitBitScanReverse(gen.operand(getValue()));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -45,9 +45,14 @@
         this.readKind = readKind;
     }
 
+    protected ValueNode getAddress() {
+        return address;
+    }
+
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, gen.operand(address), null));
+        LIRKind kind = gen.getLIRGeneratorTool().target().getLIRKind(readKind);
+        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(kind, gen.operand(address), null));
     }
 
     @SuppressWarnings("unchecked")
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -50,7 +50,16 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         Value v = gen.operand(value);
-        gen.getLIRGeneratorTool().emitStore(kind, gen.operand(address), v, null);
+        LIRKind lirKind = gen.getLIRGeneratorTool().target().getLIRKind(kind);
+        gen.getLIRGeneratorTool().emitStore(lirKind, gen.operand(address), v, null);
+    }
+
+    protected ValueNode getAddress() {
+        return address;
+    }
+
+    protected ValueNode getValue() {
+        return value;
     }
 
     /*
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/LoadSnippetVarargParameterNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/LoadSnippetVarargParameterNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -35,18 +35,18 @@
 
     @Input private ValueNode index;
 
-    private final ParameterNode[] parameters;
+    @Input private final NodeInputList<ParameterNode> parameters;
 
     public LoadSnippetVarargParameterNode(ParameterNode[] locals, ValueNode index, Stamp stamp) {
         super(stamp);
         this.index = index;
-        this.parameters = locals;
+        this.parameters = new NodeInputList<>(this, locals);
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (index.isConstant()) {
-            return parameters[index.asConstant().asInt()];
+            return parameters.get(index.asConstant().asInt());
         }
         return this;
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -142,7 +142,7 @@
                     ((Lowerable) nonNullReceiver).lower(tool);
                 }
             }
-            InliningUtil.inline(invoke, replacementGraph, false);
+            InliningUtil.inline(invoke, replacementGraph, false, null);
             Debug.dump(graph(), "After inlining replacement %s", replacementGraph);
         } else {
             invoke.lower(tool);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -25,16 +25,14 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class MathIntrinsicNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
+public class MathIntrinsicNode extends UnaryNode implements ArithmeticLIRLowerable {
 
-    @Input private ValueNode x;
     private final Operation operation;
 
     public enum Operation {
@@ -47,24 +45,19 @@
         TAN
     }
 
-    public ValueNode x() {
-        return x;
-    }
-
     public Operation operation() {
         return operation;
     }
 
-    public MathIntrinsicNode(ValueNode x, Operation op) {
-        super(StampFactory.forKind(Kind.Double));
-        assert x.stamp() instanceof FloatStamp && PrimitiveStamp.getBits(x.stamp()) == 64;
-        this.x = x;
+    public MathIntrinsicNode(ValueNode value, Operation op) {
+        super(StampFactory.forKind(Kind.Double), value);
+        assert value.stamp() instanceof FloatStamp && PrimitiveStamp.getBits(value.stamp()) == 64;
         this.operation = op;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value input = builder.operand(x());
+        Value input = builder.operand(getValue());
         Value result;
         switch (operation()) {
             case ABS:
@@ -100,9 +93,9 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant()), graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(forValue.asConstant()));
         }
         return this;
     }
@@ -112,7 +105,7 @@
         return doCompute(value, op);
     }
 
-    private static double doCompute(double value, Operation op) throws GraalInternalError {
+    private static double doCompute(double value, Operation op) {
         switch (op) {
             case ABS:
                 return Math.abs(value);
@@ -128,7 +121,8 @@
                 return Math.cos(value);
             case TAN:
                 return Math.tan(value);
+            default:
+                throw new GraalInternalError("unknown op %s", op);
         }
-        throw new GraalInternalError("unknown op %s", op);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -52,7 +52,7 @@
             if (param.isConstant()) {
                 Constant constant = evaluate(param.asConstant(), tool.getMetaAccess());
                 if (constant != null) {
-                    return ConstantNode.forConstant(constant, tool.getMetaAccess(), graph());
+                    return ConstantNode.forConstant(constant, tool.getMetaAccess());
                 }
             }
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, 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
@@ -75,7 +75,8 @@
 
     @Override
     public void generate(NodeLIRBuilderTool generator) {
-        Value result = register.asValue(getKind());
+        LIRKind kind = generator.getLIRGeneratorTool().getLIRKind(stamp());
+        Value result = register.asValue(kind);
         if (incoming) {
             generator.getLIRGeneratorTool().emitIncomingValues(new Value[]{result});
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -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
@@ -24,32 +24,39 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
-public class ReverseBytesNode extends FloatingNode implements LIRLowerable, Canonicalizable {
-
-    @Input private ValueNode value;
+public class ReverseBytesNode extends UnaryNode implements LIRLowerable {
 
     public ReverseBytesNode(ValueNode value) {
-        super(StampFactory.forKind(value.getKind()));
-        assert getKind().isNumericInteger();
-        this.value = value;
+        super(StampFactory.forKind(value.getKind()), value);
+        assert getKind() == Kind.Int || getKind() == Kind.Long;
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            long v = value.asConstant().asLong();
-            if (getKind().getStackKind() == Kind.Int) {
-                return ConstantNode.forInt(Integer.reverseBytes((int) v), graph());
-            } else if (getKind() == Kind.Long) {
-                return ConstantNode.forLong(Long.reverseBytes(v), graph());
-            }
+    public boolean inferStamp() {
+        IntegerStamp valueStamp = (IntegerStamp) getValue().stamp();
+        Stamp newStamp;
+        if (getKind() == Kind.Int) {
+            long mask = IntegerStamp.defaultMask(Kind.Int.getBitCount());
+            newStamp = StampTool.stampForMask(valueStamp.getBits(), reverse((int) valueStamp.downMask()) & mask, reverse((int) valueStamp.upMask()) & mask);
+        } else if (getKind() == Kind.Long) {
+            newStamp = StampTool.stampForMask(valueStamp.getBits(), reverse(valueStamp.downMask()), reverse(valueStamp.upMask()));
+        } else {
+            return false;
+        }
+        return updateStamp(newStamp);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            Constant c = forValue.asConstant();
+            return ConstantNode.forIntegerKind(getKind(), getKind() == Kind.Int ? reverse(c.asInt()) : reverse(c.asLong()));
         }
         return this;
     }
@@ -66,8 +73,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        Variable result = gen.newVariable(value.getKind());
-        gen.getLIRGeneratorTool().emitByteSwap(result, gen.operand(value));
+        Value result = gen.getLIRGeneratorTool().emitByteSwap(gen.operand(getValue()));
         gen.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -54,7 +54,7 @@
     @Override
     public void generate(NodeLIRBuilderTool generator) {
         Value val = generator.operand(value);
-        generator.getLIRGeneratorTool().emitMove(register.asValue(val.getKind()), val);
+        generator.getLIRGeneratorTool().emitMove(register.asValue(val.getLIRKind()), val);
     }
 
     @Override
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Mon Jun 30 12:02:19 2014 +0200
@@ -36,7 +36,6 @@
 public class SPARC extends Architecture {
 
     public static final RegisterCategory CPU = new RegisterCategory("CPU");
-    public static final RegisterCategory FPU = new RegisterCategory("FPU");
 
     // General purpose registers
     public static final Register r0 = new Register(0, 0, "g0", CPU);
@@ -123,6 +122,8 @@
     };
     // @formatter:on
 
+    public static final RegisterCategory FPU = new RegisterCategory("FPU", cpuRegisters.length);
+
     // Floating point registers
     public static final Register f0 = new Register(32, 0, "f0", FPU);
     public static final Register f1 = new Register(33, 1, "f1", FPU);
@@ -194,12 +195,12 @@
     }
 
     @Override
-    public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) {
-        if (!(platformKind instanceof Kind)) {
+    public boolean canStoreValue(RegisterCategory category, PlatformKind lirKind) {
+        if (!(lirKind instanceof Kind)) {
             return false;
         }
 
-        Kind kind = (Kind) platformKind;
+        Kind kind = (Kind) lirKind;
         if (category == CPU) {
             switch (kind) {
                 case Boolean:
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Mon Jun 30 12:02:19 2014 +0200
@@ -246,9 +246,7 @@
 
     @SlowPath
     public Iterable<FrameInstance> getStackTrace() {
-        if (stackIntrospection == null) {
-            stackIntrospection = Graal.getRequiredCapability(StackIntrospection.class);
-        }
+        initStackIntrospection();
         final Iterator<InspectedFrame> frames = stackIntrospection.getStackTrace(anyFrameMethod, anyFrameMethod, 1).iterator();
         class FrameIterator implements Iterator<FrameInstance> {
 
@@ -276,10 +274,15 @@
         };
     }
 
-    public FrameInstance getCurrentFrame() {
+    private void initStackIntrospection() {
         if (stackIntrospection == null) {
             stackIntrospection = Graal.getRequiredCapability(StackIntrospection.class);
         }
+    }
+
+    @SlowPath
+    public FrameInstance getCurrentFrame() {
+        initStackIntrospection();
         Iterator<InspectedFrame> frames = stackIntrospection.getStackTrace(callTargetMethod, callTargetMethod, 0).iterator();
         if (frames.hasNext()) {
             return new HotSpotFrameInstance.CallTargetFrame(frames.next(), true);
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -120,6 +120,7 @@
                             }
                         }
                     }
+                    loopsData.deleteUnusedNodes();
                 } while (unrolled);
             }
 
@@ -138,7 +139,7 @@
 
             @Override
             public int compare(LoopEx o1, LoopEx o2) {
-                return o2.lirLoop().getDepth() - o1.lirLoop().getDepth();
+                return o2.loop().getDepth() - o1.loop().getDepth();
             }
         });
         return sortedLoops;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultInliningPolicy.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultInliningPolicy.java	Mon Jun 30 12:02:19 2014 +0200
@@ -34,9 +34,8 @@
         return profile.getFrequency() / profile.getDeepNodeCount();
     }
 
-    public boolean isAllowed(TruffleInliningProfile profile, int currentBudgetLeft) {
+    public boolean isAllowed(TruffleInliningProfile profile, int currentNodeCount) {
         if (profile.isRecursiveCall()) {
-            // recursive call found
             profile.setFailedReason(REASON_RECURSION);
             return false;
         }
@@ -45,7 +44,7 @@
             return true;
         }
 
-        if (currentBudgetLeft - profile.getDeepNodeCount() < 0) {
+        if (currentNodeCount + profile.getDeepNodeCount() > TruffleInliningMaxCallerSize.getValue()) {
             profile.setFailedReason(REASON_MAXIMUM_TOTAL_NODE_COUNT);
             return false;
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Mon Jun 30 12:02:19 2014 +0200
@@ -121,6 +121,7 @@
     @Override
     public void invalidate() {
         this.runtime.invalidateInstalledCode(this);
+        invalidateInlining();
     }
 
     protected void invalidate(Node oldNode, Node newNode, CharSequence reason) {
@@ -133,6 +134,23 @@
         cancelInstalledTask(oldNode, newNode, reason);
     }
 
+    public void invalidateInlining() {
+        if (inliningPerformed) {
+            inliningPerformed = false;
+            getRootNode().accept(new NodeVisitor() {
+                public boolean visit(Node node) {
+                    if (node instanceof OptimizedDirectCallNode) {
+                        OptimizedDirectCallNode callNode = (OptimizedDirectCallNode) node;
+                        if (callNode.isInlined()) {
+                            callNode.resetInlining();
+                        }
+                    }
+                    return true;
+                }
+            });
+        }
+    }
+
     private void cancelInstalledTask(Node oldNode, Node newNode, CharSequence reason) {
         if (this.runtime.cancelInstalledTask(this)) {
             logOptimizingUnqueued(this, oldNode, newNode, reason);
@@ -242,19 +260,19 @@
             return;
         }
         TruffleInliningHandler handler = new TruffleInliningHandler(new DefaultInliningPolicy());
-        TruffleInliningResult result = handler.decideInlining(this, 0);
+        TruffleInliningDecision result = handler.decideInlining(this, 0);
         performInlining(result);
         logInliningDecision(result);
     }
 
-    private static void performInlining(TruffleInliningResult result) {
+    private static void performInlining(TruffleInliningDecision result) {
         if (result.getCallTarget().inliningPerformed) {
             return;
         }
         result.getCallTarget().inliningPerformed = true;
         for (TruffleInliningProfile profile : result) {
             profile.getCallNode().inline();
-            TruffleInliningResult recursiveResult = profile.getRecursiveResult();
+            TruffleInliningDecision recursiveResult = profile.getRecursiveResult();
             if (recursiveResult != null) {
                 performInlining(recursiveResult);
             }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Mon Jun 30 12:02:19 2014 +0200
@@ -53,7 +53,7 @@
     private OptimizedCallTargetLog() {
     }
 
-    public static void logInliningDecision(TruffleInliningResult result) {
+    public static void logInliningDecision(TruffleInliningDecision result) {
         if (!TraceTruffleInlining.getValue()) {
             return;
         }
@@ -63,7 +63,7 @@
         logInliningDone(result.getCallTarget());
     }
 
-    private static void logInliningDecisionRecursive(TruffleInliningResult result, int depth) {
+    private static void logInliningDecisionRecursive(TruffleInliningDecision result, int depth) {
         List<OptimizedDirectCallNode> callNodes = searchCallNodes(result.getCallTarget());
         for (OptimizedDirectCallNode callNode : callNodes) {
             TruffleInliningProfile profile = result.getProfiles().get(callNode);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -72,6 +72,14 @@
         }
     }
 
+    public void resetInlining() {
+        CompilerAsserts.neverPartOfCompilation();
+        if (inlined) {
+            inlined = false;
+            getCurrentCallTarget().invalidateInlining();
+        }
+    }
+
     @Override
     public boolean isInlinable() {
         return true;
@@ -219,4 +227,5 @@
     public static OptimizedDirectCallNode create(OptimizedCallTarget target) {
         return new OptimizedDirectCallNode(target);
     }
+
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Mon Jun 30 12:02:19 2014 +0200
@@ -214,7 +214,7 @@
                                     expansionLogger.preExpand(methodCallTargetNode, inlineGraph);
                                 }
                                 List<Node> canonicalizedNodes = methodCallTargetNode.invoke().asNode().usages().snapshot();
-                                Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false);
+                                Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false, canonicalizedNodes);
                                 if (TraceTruffleExpansion.getValue()) {
                                     expansionLogger.postExpand(inlined);
                                 }
@@ -280,6 +280,7 @@
                             break;
                         }
                     }
+                    loopsData.deleteUnusedNodes();
                 } while (unrolled);
             } catch (Throwable e) {
                 throw Debug.handle(e);
@@ -297,7 +298,7 @@
 
             @Override
             public int compare(LoopEx o1, LoopEx o2) {
-                return o2.lirLoop().getDepth() - o1.lirLoop().getDepth();
+                return o2.loop().getDepth() - o1.loop().getDepth();
             }
         });
         return sortedLoops;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Mon Jun 30 12:02:19 2014 +0200
@@ -49,7 +49,7 @@
                                 loadFieldNode.field().getAnnotation(CompilerDirectives.CompilationFinal.class) != null) {
                     Constant constant = loadFieldNode.field().readValue(loadFieldNode.object().asConstant());
                     assert verifyFieldValue(loadFieldNode.field(), constant);
-                    return ConstantNode.forConstant(constant, metaAccess, loadFieldNode.graph());
+                    return ConstantNode.forConstant(constant, metaAccess);
                 }
             }
         } else if (node instanceof LoadIndexedNode) {
@@ -59,7 +59,7 @@
 
                 Constant constant = constantReflection.readArrayElement(loadIndexedNode.array().asConstant(), index);
                 if (constant != null) {
-                    return ConstantNode.forConstant(constant, metaAccess, loadIndexedNode.graph());
+                    return ConstantNode.forConstant(constant, metaAccess);
                 }
             }
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Mon Jun 30 12:02:19 2014 +0200
@@ -64,7 +64,12 @@
     private final HashMap<List<Object>, StructuredGraph> cache = new HashMap<>();
     private final HashMap<List<Object>, Long> lastUsed = new HashMap<>();
     private final StructuredGraph markerGraph = new StructuredGraph();
+
     private final ResolvedJavaType stringBuilderClass;
+    private final ResolvedJavaType runtimeExceptionClass;
+    private final ResolvedJavaType assertionErrorClass;
+    private final ResolvedJavaType controlFlowExceptionClass;
+
     private final ResolvedJavaMethod callBoundaryMethod;
     private long counter;
 
@@ -73,7 +78,12 @@
         this.config = config;
         this.configForRootGraph = configForRootGraph;
         this.optimisticOptimizations = optimisticOptimizations;
+
         this.stringBuilderClass = providers.getMetaAccess().lookupJavaType(StringBuilder.class);
+        this.runtimeExceptionClass = providers.getMetaAccess().lookupJavaType(RuntimeException.class);
+        this.assertionErrorClass = providers.getMetaAccess().lookupJavaType(AssertionError.class);
+        this.controlFlowExceptionClass = providers.getMetaAccess().lookupJavaType(ControlFlowException.class);
+
         try {
             callBoundaryMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("callRoot", Object[].class));
         } catch (NoSuchMethodException ex) {
@@ -244,15 +254,17 @@
                             ", must annotate such calls with @CompilerDirectives.SlowPath!"));
         }
         Invoke invoke = methodCallTargetNode.invoke();
-        InliningUtil.inline(invoke, inlineGraph, true);
+        InliningUtil.inline(invoke, inlineGraph, true, null);
     }
 
     private boolean tryCutOffRuntimeExceptions(MethodCallTargetNode methodCallTargetNode) {
         if (methodCallTargetNode.targetMethod().isConstructor()) {
-            ResolvedJavaType runtimeException = providers.getMetaAccess().lookupJavaType(RuntimeException.class);
-            ResolvedJavaType controlFlowException = providers.getMetaAccess().lookupJavaType(ControlFlowException.class);
+            ResolvedJavaType declaringClass = methodCallTargetNode.targetMethod().getDeclaringClass();
             ResolvedJavaType exceptionType = Objects.requireNonNull(StampTool.typeOrNull(methodCallTargetNode.receiver().stamp()));
-            if (runtimeException.isAssignableFrom(methodCallTargetNode.targetMethod().getDeclaringClass()) && !controlFlowException.isAssignableFrom(exceptionType)) {
+
+            boolean removeAllocation = runtimeExceptionClass.isAssignableFrom(declaringClass) || assertionErrorClass.isAssignableFrom(declaringClass);
+            boolean isCFGException = controlFlowExceptionClass.isAssignableFrom(exceptionType);
+            if (removeAllocation && !isCFGException) {
                 DeoptimizeNode deoptNode = methodCallTargetNode.graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode));
                 FixedNode invokeNode = methodCallTargetNode.invoke().asNode();
                 invokeNode.replaceAtPredecessor(deoptNode);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Mon Jun 30 12:02:19 2014 +0200
@@ -50,6 +50,7 @@
 import com.oracle.graal.truffle.nodes.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
 
 /**
  * Implementation of the Truffle compiler using Graal.
@@ -110,8 +111,11 @@
     public void compileMethodImpl(final OptimizedCallTarget compilable) {
         final StructuredGraph graph;
 
-        if (TraceTruffleCompilation.getValue()) {
+        if (TraceTruffleCompilation.getValue() || TraceTruffleCompilationAST.getValue()) {
             OptimizedCallTargetLog.logOptimizingStart(compilable);
+            if (TraceTruffleCompilationAST.getValue()) {
+                NodeUtil.printCompactTree(OptimizedCallTarget.OUT, compilable.getRootNode());
+            }
         }
 
         long timeCompilationStarted = System.nanoTime();
@@ -150,7 +154,7 @@
     }
 
     private static String formatSourceSection(SourceSection sourceSection) {
-        return sourceSection != null ? sourceSection.toString() : "n/a";
+        return sourceSection != null ? sourceSection.getShortDescription() : "n/a";
     }
 
     public CompilationResult compileMethodHelper(StructuredGraph graph, Assumptions assumptions, String name, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Mon Jun 30 12:02:19 2014 +0200
@@ -87,6 +87,8 @@
     public static final OptionValue<Boolean> TraceTruffleCompilationHistogram = new OptionValue<>(false);
     @Option(help = "Prints out all polymorphic and generic nodes after compilation.")
     public static final OptionValue<Boolean> TraceTruffleCompilationPolymorphism = new OptionValue<>(false);
+    @Option(help = "Prints out all polymorphic and generic nodes after compilation.")
+    public static final OptionValue<Boolean> TraceTruffleCompilationAST = new OptionValue<>(false);
     @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleExpansion = new OptionValue<>(false);
     @Option(help = "")
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Mon Jun 30 12:02:19 2014 +0200
@@ -50,7 +50,7 @@
         int sourceMethodBci = callTarget.invoke().bci();
         ResolvedJavaMethod targetMethod = callTarget.targetMethod();
         ResolvedJavaType targetReceiverType = null;
-        if (!sourceMethod.isStatic() && callTarget.receiver().isConstant()) {
+        if (!sourceMethod.isStatic() && callTarget.receiver() != null && callTarget.receiver().isConstant()) {
             targetReceiverType = providers.getMetaAccess().lookupJavaType(callTarget.arguments().first().asConstant());
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningDecision.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import java.util.*;
+
+public final class TruffleInliningDecision implements Iterable<TruffleInliningProfile> {
+
+    private final OptimizedCallTarget callTarget;
+    private final Map<OptimizedDirectCallNode, TruffleInliningProfile> profiles;
+    private final Set<TruffleInliningProfile> inlined;
+    private final int nodeCount;
+
+    public TruffleInliningDecision(OptimizedCallTarget callTarget, List<TruffleInliningProfile> profiles, Set<TruffleInliningProfile> inlined, int nodeCount) {
+        this.callTarget = callTarget;
+        this.profiles = new HashMap<>();
+        for (TruffleInliningProfile profile : profiles) {
+            this.profiles.put(profile.getCallNode(), profile);
+        }
+        this.nodeCount = nodeCount;
+        this.inlined = inlined;
+    }
+
+    public Map<OptimizedDirectCallNode, TruffleInliningProfile> getProfiles() {
+        return profiles;
+    }
+
+    public int getNodeCount() {
+        return nodeCount;
+    }
+
+    public OptimizedCallTarget getCallTarget() {
+        return callTarget;
+    }
+
+    public boolean isInlined(OptimizedDirectCallNode path) {
+        return inlined.contains(profiles.get(path));
+    }
+
+    public int size() {
+        return inlined.size();
+    }
+
+    public Iterator<TruffleInliningProfile> iterator() {
+        return Collections.unmodifiableSet(inlined).iterator();
+    }
+
+    @Override
+    public String toString() {
+        return inlined.toString();
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,68 +31,62 @@
     private static final int MAXIMUM_RECURSIVE_DEPTH = 15;
     private static final ProfileScoreComparator INLINING_SCORE = new ProfileScoreComparator();
     private final TruffleInliningPolicy policy;
-    private final Map<OptimizedCallTarget, TruffleInliningResult> resultCache;
+    private final Map<OptimizedCallTarget, TruffleInliningDecision> resultCache;
 
     public TruffleInliningHandler(TruffleInliningPolicy policy) {
         this.policy = policy;
         this.resultCache = new HashMap<>();
     }
 
-    public TruffleInliningResult decideInlining(OptimizedCallTarget target, int depth) {
+    public TruffleInliningDecision decideInlining(OptimizedCallTarget target, int depth) {
         if (resultCache.containsKey(target)) {
             return resultCache.get(target);
         }
-        resultCache.put(target, null);
-        TruffleInliningResult result = decideInliningImpl(target, depth);
+        resultCache.put(target, null); // important for recursion detection
+        TruffleInliningDecision result = createInliningDecision(target, depth);
         resultCache.put(target, result);
         return result;
     }
 
-    private TruffleInliningResult decideInliningImpl(OptimizedCallTarget target, int depth) {
-        List<TruffleInliningProfile> profiles = lookupProfiles(target, depth);
+    private TruffleInliningDecision createInliningDecision(OptimizedCallTarget target, int depth) {
+        List<TruffleInliningProfile> profiles = createProfiles(target, depth);
         Set<TruffleInliningProfile> inlined = new HashSet<>();
         Collections.sort(profiles, INLINING_SCORE);
-        int budget = TruffleCompilerOptions.TruffleInliningMaxCallerSize.getValue() - OptimizedCallUtils.countNonTrivialNodes(target, true);
+        int deepNodeCount = OptimizedCallUtils.countNonTrivialNodes(target, true);
         int index = 0;
+
         for (TruffleInliningProfile profile : profiles) {
             profile.setQueryIndex(index++);
-            if (policy.isAllowed(profile, budget)) {
+            if (policy.isAllowed(profile, deepNodeCount)) {
                 inlined.add(profile);
-                budget -= profile.getDeepNodeCount();
+                deepNodeCount += profile.getDeepNodeCount();
             }
         }
 
-        int deepNodeCount = TruffleCompilerOptions.TruffleInliningMaxCallerSize.getValue() - budget;
-        return new TruffleInliningResult(target, profiles, inlined, deepNodeCount);
+        return new TruffleInliningDecision(target, profiles, inlined, deepNodeCount);
     }
 
-    private List<TruffleInliningProfile> lookupProfiles(final OptimizedCallTarget target, int depth) {
-        final List<OptimizedDirectCallNode> callNodes = new ArrayList<>();
+    private List<TruffleInliningProfile> createProfiles(final OptimizedCallTarget target, final int depth) {
+        final List<TruffleInliningProfile> profiles = new ArrayList<>();
         target.getRootNode().accept(new NodeVisitor() {
             public boolean visit(Node node) {
                 if (node instanceof OptimizedDirectCallNode) {
-                    callNodes.add((OptimizedDirectCallNode) node);
+                    profiles.add(createProfile(target, (OptimizedDirectCallNode) node, depth));
                 }
                 return true;
             }
         });
-        final List<TruffleInliningProfile> profiles = new ArrayList<>();
-        for (OptimizedDirectCallNode callNode : callNodes) {
-            profiles.add(lookupProfile(target, callNode, depth));
-        }
         return profiles;
     }
 
-    public TruffleInliningProfile lookupProfile(OptimizedCallTarget parentTarget, OptimizedDirectCallNode ocn, int depth) {
+    public TruffleInliningProfile createProfile(OptimizedCallTarget parentTarget, OptimizedDirectCallNode ocn, int depth) {
         OptimizedCallTarget target = ocn.getCurrentCallTarget();
 
-        int callSites = ocn.getCurrentCallTarget().getKnownCallSiteCount();
         int nodeCount = OptimizedCallUtils.countNonTrivialNodes(target, false);
         double frequency = calculateFrequency(parentTarget, ocn);
-        boolean forced = ocn.isInliningForced();
 
         int deepNodeCount;
-        TruffleInliningResult recursiveResult;
+        TruffleInliningDecision recursiveResult;
         boolean recursiveCall = false;
         if (target.inliningPerformed || depth > MAXIMUM_RECURSIVE_DEPTH) {
             deepNodeCount = OptimizedCallUtils.countNonTrivialNodes(target, true);
@@ -107,7 +101,7 @@
             }
         }
 
-        TruffleInliningProfile profile = new TruffleInliningProfile(ocn, callSites, nodeCount, deepNodeCount, frequency, forced, recursiveCall, recursiveResult);
+        TruffleInliningProfile profile = new TruffleInliningProfile(ocn, nodeCount, deepNodeCount, frequency, recursiveCall, recursiveResult);
         profile.setScore(policy.calculateScore(profile));
         return profile;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningPolicy.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningPolicy.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,7 +24,7 @@
 
 public interface TruffleInliningPolicy {
 
-    boolean isAllowed(TruffleInliningProfile profile, int currentBudgetLeft);
+    boolean isAllowed(TruffleInliningProfile profile, int currentNodeCount);
 
     double calculateScore(TruffleInliningProfile profile);
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Mon Jun 30 12:02:19 2014 +0200
@@ -29,25 +29,20 @@
     private final OptimizedDirectCallNode callNode;
     private final int nodeCount;
     private final int deepNodeCount;
-    private final int callSites;
     private final double frequency;
-    private final boolean forced;
     private final boolean recursiveCall;
-    private final TruffleInliningResult recursiveResult;
+    private final TruffleInliningDecision recursiveResult;
 
     private String failedReason;
     private int queryIndex = -1;
     private double score;
 
-    public TruffleInliningProfile(OptimizedDirectCallNode callNode, int callSites, int nodeCount, int deepNodeCount, double frequency, boolean forced, boolean recursiveCall,
-                    TruffleInliningResult recursiveResult) {
+    public TruffleInliningProfile(OptimizedDirectCallNode callNode, int nodeCount, int deepNodeCount, double frequency, boolean recursiveCall, TruffleInliningDecision recursiveResult) {
         this.callNode = callNode;
-        this.callSites = callSites;
         this.nodeCount = nodeCount;
         this.deepNodeCount = deepNodeCount;
         this.frequency = frequency;
         this.recursiveCall = recursiveCall;
-        this.forced = forced;
         this.recursiveResult = recursiveResult;
     }
 
@@ -60,14 +55,14 @@
     }
 
     public int getCallSites() {
-        return callSites;
+        return callNode.getCurrentCallTarget().getKnownCallSiteCount();
     }
 
     public int getNodeCount() {
         return nodeCount;
     }
 
-    public TruffleInliningResult getRecursiveResult() {
+    public TruffleInliningDecision getRecursiveResult() {
         return recursiveResult;
     }
 
@@ -96,7 +91,7 @@
     }
 
     public boolean isForced() {
-        return forced;
+        return callNode.isInliningForced();
     }
 
     public double getFrequency() {
@@ -112,7 +107,7 @@
         properties.put("nodeCount", String.format("%5d/%5d", deepNodeCount, nodeCount));
         properties.put("frequency", frequency);
         properties.put("score", String.format("%8.4f", getScore()));
-        properties.put(String.format("index=%3d, force=%s, callSites=%2d", queryIndex, (forced ? "Y" : "N"), callSites), "");
+        properties.put(String.format("index=%3d, force=%s, callSites=%2d", queryIndex, (isForced() ? "Y" : "N"), getCallSites()), "");
         properties.put("reason", failedReason);
         return properties;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningResult.java	Mon Jun 30 08:50:26 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle;
-
-import java.util.*;
-
-public final class TruffleInliningResult implements Iterable<TruffleInliningProfile> {
-
-    private final OptimizedCallTarget callTarget;
-    private final Map<OptimizedDirectCallNode, TruffleInliningProfile> profiles;
-    private final Set<TruffleInliningProfile> inlined;
-    private final int nodeCount;
-
-    public TruffleInliningResult(OptimizedCallTarget callTarget, List<TruffleInliningProfile> profiles, Set<TruffleInliningProfile> inlined, int nodeCount) {
-        this.callTarget = callTarget;
-        this.profiles = new HashMap<>();
-        for (TruffleInliningProfile profile : profiles) {
-            this.profiles.put(profile.getCallNode(), profile);
-        }
-        this.nodeCount = nodeCount;
-        this.inlined = inlined;
-    }
-
-    public Map<OptimizedDirectCallNode, TruffleInliningProfile> getProfiles() {
-        return profiles;
-    }
-
-    public int getNodeCount() {
-        return nodeCount;
-    }
-
-    public OptimizedCallTarget getCallTarget() {
-        return callTarget;
-    }
-
-    public boolean isInlined(OptimizedDirectCallNode path) {
-        return inlined.contains(profiles.get(path));
-    }
-
-    public int size() {
-        return inlined.size();
-    }
-
-    public Iterator<TruffleInliningProfile> iterator() {
-        return Collections.unmodifiableSet(inlined).iterator();
-    }
-
-    @Override
-    public String toString() {
-        return inlined.toString();
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/LoadIndexedFinalNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/LoadIndexedFinalNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -38,7 +38,7 @@
 
     /**
      * Creates a new {@link LoadIndexedFinalNode}.
-     * 
+     *
      * @param array the instruction producing the array
      * @param index the instruction producing the index
      * @param elementKind the element type
@@ -52,7 +52,7 @@
         if (array().isConstant() && index().isConstant()) {
             Constant constant = tool.getConstantReflection().readArrayElement(array().asConstant(), index().asConstant().asInt());
             if (constant != null) {
-                return ConstantNode.forConstant(constant, tool.getMetaAccess(), graph());
+                return ConstantNode.forConstant(constant, tool.getMetaAccess());
             }
         }
         return this;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -36,42 +35,42 @@
  * Node representing an exact integer addition that will throw an {@link ArithmeticException} in
  * case the addition would overflow the 32 bit range.
  */
-public class IntegerAddExactNode extends IntegerAddNode implements Canonicalizable, IntegerExactArithmeticNode {
+public class IntegerAddExactNode extends IntegerAddNode implements IntegerExactArithmeticNode {
 
     public IntegerAddExactNode(ValueNode x, ValueNode y) {
-        super(x.stamp().unrestricted(), x, y);
+        super(x, y);
         assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
     }
 
     @Override
     public boolean inferStamp() {
-        // TODO Should probably use a specialised version which understands that it can't overflow
-        return updateStamp(StampTool.add(x().stamp(), y().stamp()));
+        // TODO Should probably use a specialized version which understands that it can't overflow
+        return updateStamp(StampTool.add(getX().stamp(), getY().stamp()));
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new IntegerAddExactNode(y(), x()));
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new IntegerAddExactNode(forY, forX);
         }
-        if (x().isConstant()) {
-            Constant xConst = x().asConstant();
-            Constant yConst = y().asConstant();
+        if (forX.isConstant()) {
+            Constant xConst = forX.asConstant();
+            Constant yConst = forY.asConstant();
             assert xConst.getKind() == yConst.getKind();
             try {
                 if (xConst.getKind() == Kind.Int) {
-                    return ConstantNode.forInt(ExactMath.addExact(xConst.asInt(), yConst.asInt()), graph());
+                    return ConstantNode.forInt(ExactMath.addExact(xConst.asInt(), yConst.asInt()));
                 } else {
                     assert xConst.getKind() == Kind.Long;
-                    return ConstantNode.forLong(ExactMath.addExact(xConst.asLong(), yConst.asLong()), graph());
+                    return ConstantNode.forLong(ExactMath.addExact(xConst.asLong(), yConst.asLong()));
                 }
             } catch (ArithmeticException ex) {
                 // The operation will result in an overflow exception, so do not canonicalize.
             }
-        } else if (y().isConstant()) {
-            long c = y().asConstant().asLong();
+        } else if (forY.isConstant()) {
+            long c = forY.asConstant().asLong();
             if (c == 0) {
-                return x();
+                return forX;
             }
         }
         return this;
@@ -79,7 +78,7 @@
 
     @Override
     public IntegerExactArithmeticSplitNode createSplit(BeginNode next, BeginNode deopt) {
-        return graph().add(new IntegerAddExactSplitNode(stamp(), x(), y(), next, deopt));
+        return graph().add(new IntegerAddExactSplitNode(stamp(), getX(), getY(), next, deopt));
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -35,39 +34,39 @@
  * Node representing an exact integer multiplication that will throw an {@link ArithmeticException}
  * in case the addition would overflow the 32 bit range.
  */
-public class IntegerMulExactNode extends IntegerMulNode implements Canonicalizable, IntegerExactArithmeticNode {
+public class IntegerMulExactNode extends IntegerMulNode implements IntegerExactArithmeticNode {
 
     public IntegerMulExactNode(ValueNode x, ValueNode y) {
-        super(x.stamp().unrestricted(), x, y);
+        super(x, y);
         assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && !y().isConstant()) {
-            return graph().unique(new IntegerMulExactNode(y(), x()));
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new IntegerMulExactNode(forY, forX);
         }
-        if (x().isConstant()) {
-            Constant xConst = x().asConstant();
-            Constant yConst = y().asConstant();
+        if (forX.isConstant()) {
+            Constant xConst = forX.asConstant();
+            Constant yConst = forY.asConstant();
             assert xConst.getKind() == yConst.getKind();
             try {
                 if (xConst.getKind() == Kind.Int) {
-                    return ConstantNode.forInt(ExactMath.multiplyExact(xConst.asInt(), yConst.asInt()), graph());
+                    return ConstantNode.forInt(ExactMath.multiplyExact(xConst.asInt(), yConst.asInt()));
                 } else {
                     assert xConst.getKind() == Kind.Long;
-                    return ConstantNode.forLong(ExactMath.multiplyExact(xConst.asLong(), yConst.asLong()), graph());
+                    return ConstantNode.forLong(ExactMath.multiplyExact(xConst.asLong(), yConst.asLong()));
                 }
             } catch (ArithmeticException ex) {
                 // The operation will result in an overflow exception, so do not canonicalize.
             }
-        } else if (y().isConstant()) {
-            long c = y().asConstant().asLong();
+        } else if (forY.isConstant()) {
+            long c = forY.asConstant().asLong();
             if (c == 1) {
-                return x();
+                return forX;
             }
             if (c == 0) {
-                return ConstantNode.forIntegerStamp(stamp(), 0, graph());
+                return ConstantNode.forIntegerStamp(stamp(), 0);
             }
         }
         return this;
@@ -75,7 +74,7 @@
 
     @Override
     public IntegerExactArithmeticSplitNode createSplit(BeginNode next, BeginNode deopt) {
-        return graph().add(new IntegerMulExactSplitNode(stamp(), x(), y(), next, deopt));
+        return graph().add(new IntegerMulExactSplitNode(stamp(), getX(), getY(), next, deopt));
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -22,10 +22,13 @@
  */
 package com.oracle.graal.truffle.nodes.arithmetic;
 
+import java.util.function.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -56,10 +59,45 @@
         }
     }
 
+    /**
+     * Determines the minimum and maximum result of this node for the given inputs and returns the
+     * result of the given BiFunction on the minimum and maximum values.
+     */
+    private <T> T processExtremes(ValueNode forX, ValueNode forY, BiFunction<Long, Long, T> op) {
+        IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+        IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+
+        Kind kind = getKind();
+        assert kind == Kind.Int || kind == Kind.Long;
+        long[] xExtremes = {xStamp.lowerBound(), xStamp.upperBound()};
+        long[] yExtremes = {yStamp.lowerBound(), yStamp.upperBound()};
+        long min = Long.MAX_VALUE;
+        long max = Long.MIN_VALUE;
+        for (long a : xExtremes) {
+            for (long b : yExtremes) {
+                long result = kind == Kind.Int ? ExactMath.multiplyHigh((int) a, (int) b) : ExactMath.multiplyHigh(a, b);
+                min = Math.min(min, result);
+                max = Math.max(max, result);
+            }
+        }
+        return op.apply(min, max);
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(processExtremes(getX(), getY(), (min, max) -> StampFactory.forInteger(getKind(), min, max)));
+    }
+
+    @SuppressWarnings("cast")
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        return processExtremes(forX, forY, (min, max) -> min == (long) max ? ConstantNode.forIntegerKind(getKind(), min) : this);
+    }
+
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value a = builder.operand(x());
-        Value b = builder.operand(y());
+        Value a = builder.operand(getX());
+        Value b = builder.operand(getY());
         builder.setResult(this, gen.emitMulHigh(a, b));
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -24,54 +24,54 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 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.graal.nodes.util.*;
 import com.oracle.truffle.api.*;
 
 /**
  * Node representing an exact integer substraction that will throw an {@link ArithmeticException} in
  * case the addition would overflow the 32 bit range.
  */
-public class IntegerSubExactNode extends IntegerSubNode implements Canonicalizable, IntegerExactArithmeticNode {
+public class IntegerSubExactNode extends IntegerSubNode implements IntegerExactArithmeticNode {
 
     public IntegerSubExactNode(ValueNode x, ValueNode y) {
-        super(StampTool.sub(x.stamp(), y.stamp()), x, y);
+        super(x, y);
         assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
     }
 
     @Override
     public boolean inferStamp() {
-        // TODO Should probably use a specialised version which understands that it can't overflow
-        return updateStamp(StampTool.sub(x().stamp(), y().stamp()));
+        // TODO Should probably use a specialized version which understands that it can't overflow
+        return updateStamp(StampTool.sub(getX().stamp(), getY().stamp()));
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return ConstantNode.forIntegerStamp(stamp(), 0, graph());
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return ConstantNode.forIntegerStamp(stamp(), 0);
         }
-        if (x().isConstant() && y().isConstant()) {
-            Constant xConst = x().asConstant();
-            Constant yConst = y().asConstant();
+        if (forX.isConstant() && forY.isConstant()) {
+            Constant xConst = forX.asConstant();
+            Constant yConst = forY.asConstant();
             assert xConst.getKind() == yConst.getKind();
             try {
                 if (xConst.getKind() == Kind.Int) {
-                    return ConstantNode.forInt(ExactMath.subtractExact(xConst.asInt(), yConst.asInt()), graph());
+                    return ConstantNode.forInt(ExactMath.subtractExact(xConst.asInt(), yConst.asInt()));
                 } else {
                     assert xConst.getKind() == Kind.Long;
-                    return ConstantNode.forLong(ExactMath.subtractExact(xConst.asLong(), yConst.asLong()), graph());
+                    return ConstantNode.forLong(ExactMath.subtractExact(xConst.asLong(), yConst.asLong()));
                 }
             } catch (ArithmeticException ex) {
                 // The operation will result in an overflow exception, so do not canonicalize.
             }
-        } else if (y().isConstant()) {
-            long c = y().asConstant().asLong();
+        } else if (forY.isConstant()) {
+            long c = forY.asConstant().asLong();
             if (c == 0) {
-                return x();
+                return forX;
             }
         }
         return this;
@@ -79,7 +79,7 @@
 
     @Override
     public IntegerExactArithmeticSplitNode createSplit(BeginNode next, BeginNode deopt) {
-        return graph().add(new IntegerSubExactSplitNode(stamp(), x(), y(), next, deopt));
+        return graph().add(new IntegerSubExactSplitNode(stamp(), getX(), getY(), next, deopt));
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -22,10 +22,13 @@
  */
 package com.oracle.graal.truffle.nodes.arithmetic;
 
+import java.util.function.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -56,10 +59,49 @@
         }
     }
 
+    /**
+     * Determines the minimum and maximum result of this node for the given inputs and returns the
+     * result of the given BiFunction on the minimum and maximum values. Note that the minima and
+     * maxima are calculated using signed min/max functions, while the values themselves are
+     * unsigned.
+     */
+    private <T> T processExtremes(ValueNode forX, ValueNode forY, BiFunction<Long, Long, T> op) {
+        IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+        IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+
+        Kind kind = getKind();
+        assert kind == Kind.Int || kind == Kind.Long;
+        long[] xExtremes = {xStamp.lowerBound(), xStamp.upperBound()};
+        long[] yExtremes = {yStamp.lowerBound(), yStamp.upperBound()};
+        long min = Long.MAX_VALUE;
+        long max = Long.MIN_VALUE;
+        for (long a : xExtremes) {
+            for (long b : yExtremes) {
+                long result = kind == Kind.Int ? ExactMath.multiplyHighUnsigned((int) a, (int) b) : ExactMath.multiplyHighUnsigned(a, b);
+                min = Math.min(min, result);
+                max = Math.max(max, result);
+            }
+        }
+        return op.apply(min, max);
+    }
+
+    @SuppressWarnings("cast")
+    @Override
+    public boolean inferStamp() {
+        // if min is negative, then the value can reach into the unsigned range
+        return updateStamp(processExtremes(getX(), getY(), (min, max) -> (min == (long) max || min >= 0) ? StampFactory.forInteger(getKind(), min, max) : StampFactory.forKind(getKind())));
+    }
+
+    @SuppressWarnings("cast")
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        return processExtremes(forX, forY, (min, max) -> min == (long) max ? ConstantNode.forIntegerKind(getKind(), min) : this);
+    }
+
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value a = builder.operand(x());
-        Value b = builder.operand(y());
+        Value a = builder.operand(getX());
+        Value b = builder.operand(getY());
         builder.setResult(this, gen.emitUMulHigh(a, b));
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -59,7 +59,7 @@
     public Node canonical(CanonicalizerTool tool) {
         if (object.isConstant() && !object.isNullConstant() && offset.isConstant() && condition.isConstant() && condition.asConstant().asInt() == 1) {
             Constant constant = tool.getConstantReflection().readUnsafeConstant(accessKind, object.asConstant(), offset.asConstant().asLong());
-            return ConstantNode.forConstant(constant, tool.getMetaAccess(), graph());
+            return ConstantNode.forConstant(constant, tool.getMetaAccess());
         }
         return this;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -62,10 +62,9 @@
             } else {
                 locationIdentity = ObjectLocationIdentity.create(locationArgument.asConstant());
             }
-            CompareNode compare = CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()));
+            CompareNode compare = CompareNode.createCompareNode(Condition.EQ, conditionArgument, ConstantNode.forBoolean(true));
             Kind returnKind = this.getTargetMethod().getSignature().getReturnKind();
-            Node result = graph().add(new UnsafeLoadNode(objectArgument, offsetArgument, returnKind, locationIdentity, compare));
-            return result;
+            return new UnsafeLoadNode(objectArgument, offsetArgument, returnKind, locationIdentity, compare);
         }
         return this;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -61,10 +61,7 @@
                 locationIdentity = ObjectLocationIdentity.create(locationArgument.asConstant());
             }
 
-            UnsafeStoreNode unsafeStoreNode = graph().add(
-                            new UnsafeStoreNode(objectArgument, offsetArgument, valueArgument, this.getTargetMethod().getSignature().getParameterKind(VALUE_ARGUMENT_INDEX), locationIdentity));
-            unsafeStoreNode.setStateAfter(this.stateAfter());
-            return unsafeStoreNode;
+            return new UnsafeStoreNode(objectArgument, offsetArgument, valueArgument, this.getTargetMethod().getSignature().getParameterKind(VALUE_ARGUMENT_INDEX), locationIdentity, stateAfter());
         }
         return this;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -25,17 +25,17 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.truffle.nodes.asserts.*;
 import com.oracle.truffle.api.*;
 
 /**
  * Macro node for method {@link CompilerDirectives#unsafeCast(Object, Class, boolean, boolean)}.
  */
-public class UnsafeTypeCastMacroNode extends NeverPartOfCompilationNode implements Canonicalizable {
+public class UnsafeTypeCastMacroNode extends NeverPartOfCompilationNode implements Simplifiable {
 
     private static final int OBJECT_ARGUMENT_INDEX = 0;
     private static final int CLASS_ARGUMENT_INDEX = 1;
@@ -49,22 +49,25 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public void simplify(SimplifierTool tool) {
         ValueNode classArgument = arguments.get(CLASS_ARGUMENT_INDEX);
         ValueNode nonNullArgument = arguments.get(NONNULL_ARGUMENT_INDEX);
         if (classArgument.isConstant() && nonNullArgument.isConstant()) {
             ValueNode objectArgument = arguments.get(OBJECT_ARGUMENT_INDEX);
             ValueNode conditionArgument = arguments.get(CONDITION_ARGUMENT_INDEX);
             ResolvedJavaType lookupJavaType = tool.getConstantReflection().asJavaType(classArgument.asConstant());
+            tool.addToWorkList(usages());
             if (lookupJavaType == null) {
-                return objectArgument;
+                replaceAtUsages(objectArgument);
+                GraphUtil.removeFixedWithUnusedInputs(this);
+            } else {
+                Stamp stamp = StampFactory.declared(lookupJavaType, nonNullArgument.asConstant().asInt() != 0);
+                ConditionAnchorNode valueAnchorNode = graph().add(
+                                new ConditionAnchorNode(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()))));
+                PiNode piCast = graph().unique(new PiNode(objectArgument, stamp, valueAnchorNode));
+                replaceAtUsages(piCast);
+                graph().replaceFixedWithFixed(this, valueAnchorNode);
             }
-            Stamp stamp = StampFactory.declared(lookupJavaType, nonNullArgument.asConstant().asInt() != 0);
-            ConditionAnchorNode valueAnchorNode = graph().add(new ConditionAnchorNode(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()))));
-            PiNode piCast = graph().unique(new PiNode(objectArgument, stamp, valueAnchorNode));
-            this.replaceAtUsages(piCast);
-            return valueAnchorNode;
         }
-        return this;
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -54,7 +54,7 @@
                     } else {
                         StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTarget.targetMethod());
                         if (inlineGraph != null) {
-                            InliningUtil.inline(methodCallTarget.invoke(), inlineGraph, true);
+                            InliningUtil.inline(methodCallTarget.invoke(), inlineGraph, true, null);
                             Debug.dump(graph, "After inlining %s", methodCallTarget.targetMethod().toString());
                         }
                     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerAssertsSubstitutions.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerAssertsSubstitutions.java	Mon Jun 30 12:02:19 2014 +0200
@@ -33,6 +33,9 @@
     @MacroSubstitution(macro = NeverPartOfCompilationNode.class, isStatic = true)
     public static native void neverPartOfCompilation();
 
+    @MacroSubstitution(macro = NeverPartOfCompilationNode.class, isStatic = true)
+    public static native void neverPartOfCompilation(String message);
+
     @MacroSubstitution(macro = CompilationConstantNode.class, isStatic = true)
     public static native boolean compilationConstant(boolean value);
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
@@ -90,12 +91,10 @@
                 }
 
                 // apply the effects collected during this iteration
-                HashSetNodeChangeListener listener = new HashSetNodeChangeListener();
-                graph.trackInputChange(listener);
-                graph.trackUsagesDroppedZero(listener);
-                closure.applyEffects();
-                graph.stopTrackingInputChange();
-                graph.stopTrackingUsagesDroppedZero();
+                HashSetNodeEventListener listener = new HashSetNodeEventListener.ExceptForAddedNodes();
+                try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+                    closure.applyEffects();
+                }
 
                 if (Debug.isDumpEnabled()) {
                     Debug.dump(graph, "after " + getName() + " iteration");
@@ -103,7 +102,7 @@
 
                 new DeadCodeEliminationPhase().apply(graph);
 
-                Set<Node> changedNodes = listener.getChangedNodes();
+                Set<Node> changedNodes = listener.getNodes();
                 for (Node node : graph.getNodes()) {
                     if (node instanceof Simplifiable) {
                         changedNodes.add(node);
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -71,7 +71,12 @@
         assert getKind() != input.getKind();
         assert generator.getLIRGeneratorTool().target().getSizeInBytes(getKind()) == generator.getLIRGeneratorTool().target().getSizeInBytes(input.getKind());
 
-        AllocatableValue result = generator.getLIRGeneratorTool().newVariable(getKind());
+        LIRKind kind = generator.getLIRGeneratorTool().getLIRKind(stamp());
+        if (kind.isValue()) {
+            kind = kind.makeDerivedReference();
+        }
+
+        AllocatableValue result = generator.getLIRGeneratorTool().newVariable(kind);
         generator.getLIRGeneratorTool().emitMove(result, generator.operand(input));
         generator.setResult(this, result);
     }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -134,9 +134,9 @@
      * Fold constant field reads, e.g. enum constants.
      */
     protected void rewriteLoadField(StructuredGraph graph, LoadFieldNode node) {
-        ConstantNode constant = node.asConstant(metaAccess);
+        ConstantNode constant = node.asConstant(metaAccess, node.object());
         if (constant != null) {
-            node.replaceAtUsages(constant);
+            node.replaceAtUsages(graph.unique(constant));
             graph.removeFixed(node);
         }
     }
@@ -199,7 +199,7 @@
                 ValueNode left = arguments.get(0);
                 ValueNode right = operation.rightOperandIsInt() ? toUnsigned(graph, arguments.get(1), Kind.Int) : fromSigned(graph, arguments.get(1));
 
-                ValueNode replacement = graph.addOrUnique(createBinaryNodeInstance(operation.node(), wordKind, left, right));
+                ValueNode replacement = graph.addOrUnique(createBinaryNodeInstance(operation.node(), left, right));
                 if (replacement instanceof FixedWithNextNode) {
                     graph.addBeforeFixed(invoke.asNode(), (FixedWithNextNode) replacement);
                 }
@@ -213,7 +213,7 @@
 
             case NOT:
                 assert arguments.size() == 1;
-                replace(invoke, graph.unique(new XorNode(StampFactory.forKind(wordKind), arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph))));
+                replace(invoke, graph.unique(new XorNode(arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph))));
                 break;
 
             case READ_POINTER:
@@ -333,10 +333,10 @@
      * called for all Word operations which are annotated with @Operation(node = ...) and
      * encapsulates the reflective allocation of the node.
      */
-    private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, Kind kind, ValueNode left, ValueNode right) {
+    private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right) {
         try {
-            Constructor<? extends ValueNode> constructor = nodeClass.getConstructor(Stamp.class, ValueNode.class, ValueNode.class);
-            return constructor.newInstance(StampFactory.forKind(kind), left, right);
+            Constructor<? extends ValueNode> constructor = nodeClass.getConstructor(ValueNode.class, ValueNode.class);
+            return constructor.newInstance(left, right);
         } catch (Throwable ex) {
             throw new GraalInternalError(ex).addContext(nodeClass.getName());
         }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Mon Jun 30 12:02:19 2014 +0200
@@ -86,8 +86,8 @@
                     MethodCallTargetNode callTarget = (MethodCallTargetNode) usage;
                     verifyInvoke(node, callTarget);
                 } else if (usage instanceof ObjectEqualsNode) {
-                    verify(!isWord(node) || ((ObjectEqualsNode) usage).x() != node, node, usage, "cannot use word type in comparison");
-                    verify(!isWord(node) || ((ObjectEqualsNode) usage).y() != node, node, usage, "cannot use word type in comparison");
+                    verify(!isWord(node) || ((ObjectEqualsNode) usage).getX() != node, node, usage, "cannot use word type in comparison");
+                    verify(!isWord(node) || ((ObjectEqualsNode) usage).getY() != node, node, usage, "cannot use word type in comparison");
                 } else if (usage instanceof ArrayLengthNode) {
                     verify(!isWord(node) || ((ArrayLengthNode) usage).array() != node, node, usage, "cannot get array length from word value");
                 } else if (usage instanceof ValuePhiNode) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/SourceTextTest.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2013, 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.truffle.api.test.utilities;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.source.*;
+
+public class SourceTextTest {
+
+    private final Source emptySource = Source.fromText("", null);
+
+    private final Source emptyLineSource = Source.fromText("\n", null);
+
+    private final Source shortSource = Source.fromText("01", null);
+
+    private final Source longSource = Source.fromText("01234\n67\n9\n", null);
+
+    @Test
+    public void emptyTextTest0() {
+        assertEquals(emptySource.getLineCount(), 0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void emptyTextTest1() {
+        emptySource.getLineNumber(0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void emptyTextTest2() {
+        emptySource.getColumnNumber(0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void emptyTextTest3() {
+        emptySource.getLineNumber(-1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void emptyTextTest4() {
+        emptySource.getLineStartOffset(0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void emptyTextTest5() {
+        emptySource.getLineStartOffset(1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void emptyTextTest6() {
+        emptySource.getLineLength(1);
+    }
+
+    @Test
+    public void emptyLineTest0() {
+        assertEquals(emptyLineSource.getLineCount(), 1);
+        assertEquals(emptyLineSource.getLineNumber(0), 1);
+        assertEquals(emptyLineSource.getLineStartOffset(1), 0);
+        assertEquals(emptyLineSource.getColumnNumber(0), 1);
+        assertEquals(emptyLineSource.getLineLength(1), 0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void emptyLineTest1() {
+        emptyLineSource.getLineNumber(1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void emptyLineTest2() {
+        emptyLineSource.getLineStartOffset(2);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void emptyLineTest3() {
+        emptyLineSource.getColumnNumber(1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void emptyLineTest4() {
+        emptyLineSource.getLineLength(2);
+    }
+
+    @Test
+    public void shortTextTest0() {
+
+        assertEquals(shortSource.getLineCount(), 1);
+
+        assertEquals(shortSource.getLineNumber(0), 1);
+        assertEquals(shortSource.getLineStartOffset(1), 0);
+        assertEquals(shortSource.getColumnNumber(0), 1);
+
+        assertEquals(shortSource.getLineNumber(1), 1);
+        assertEquals(shortSource.getColumnNumber(1), 2);
+
+        assertEquals(shortSource.getLineLength(1), 2);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shortTextTest1() {
+        shortSource.getLineNumber(-1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shortTextTest2() {
+        shortSource.getColumnNumber(-1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shortTextTest3() {
+        shortSource.getLineNumber(2);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shortTextTest4() {
+        shortSource.getColumnNumber(2);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shortTextTest5() {
+        shortSource.getLineLength(2);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shortTextTest6() {
+        shortSource.getLineLength(2);
+    }
+
+    @Test
+    public void longTextTest0() {
+
+        assertEquals(longSource.getLineCount(), 3);
+
+        assertEquals(longSource.getLineNumber(0), 1);
+        assertEquals(longSource.getLineStartOffset(1), 0);
+        assertEquals(longSource.getColumnNumber(0), 1);
+
+        assertEquals(longSource.getLineNumber(4), 1);
+        assertEquals(longSource.getColumnNumber(4), 5);
+
+        assertEquals(longSource.getLineNumber(5), 1); // newline
+        assertEquals(longSource.getColumnNumber(5), 6); // newline
+        assertEquals(longSource.getLineLength(1), 5);
+
+        assertEquals(longSource.getLineNumber(6), 2);
+        assertEquals(longSource.getLineStartOffset(2), 6);
+        assertEquals(longSource.getColumnNumber(6), 1);
+
+        assertEquals(longSource.getLineNumber(7), 2);
+        assertEquals(longSource.getColumnNumber(7), 2);
+
+        assertEquals(longSource.getLineNumber(8), 2); // newline
+        assertEquals(longSource.getLineNumber(8), 2); // newline
+        assertEquals(longSource.getLineLength(2), 2);
+
+        assertEquals(longSource.getLineNumber(9), 3);
+        assertEquals(longSource.getLineStartOffset(3), 9);
+        assertEquals(longSource.getColumnNumber(9), 1);
+
+        assertEquals(longSource.getLineNumber(10), 3); // newline
+        assertEquals(longSource.getColumnNumber(10), 2); // newline
+        assertEquals(longSource.getLineLength(3), 1);
+
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void longTextTest1() {
+        longSource.getLineNumber(11);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void longTextTest2() {
+        longSource.getColumnNumber(11);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void longTextTest3() {
+        longSource.getLineStartOffset(4);
+    }
+
+}
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/TextMapTest.java	Mon Jun 30 08:50:26 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,202 +0,0 @@
-/*
- * Copyright (c) 2013, 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.truffle.api.test.utilities;
-
-import static org.junit.Assert.*;
-
-import org.junit.*;
-
-import com.oracle.truffle.api.source.*;
-
-public class TextMapTest {
-
-    final TextMap emptyTextMap = new TextMap("");
-
-    final TextMap emptyLineMap = new TextMap("\n");
-
-    private final TextMap shortMap = new TextMap("01");
-
-    private final TextMap longMap = new TextMap("01234\n67\n9\n");
-
-    @Test
-    public void emptyTextTest0() {
-        assertEquals(emptyTextMap.lineCount(), 0);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void emptyTextTest1() {
-        emptyTextMap.offsetToLine(0);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void emptyTextTest2() {
-        emptyTextMap.offsetToCol(0);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void emptyTextTest3() {
-        emptyTextMap.lineStartOffset(-1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void emptyTextTest4() {
-        emptyTextMap.lineStartOffset(0);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void emptyTextTest5() {
-        emptyTextMap.lineStartOffset(1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void emptyTextTest6() {
-        emptyTextMap.lineLength(1);
-    }
-
-    @Test
-    public void emptyLineTest0() {
-        assertEquals(emptyLineMap.lineCount(), 1);
-        assertEquals(emptyLineMap.offsetToLine(0), 1);
-        assertEquals(emptyLineMap.lineStartOffset(1), 0);
-        assertEquals(emptyLineMap.offsetToCol(0), 1);
-        assertEquals(emptyLineMap.lineLength(1), 0);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void emptyLineTest1() {
-        emptyLineMap.offsetToLine(1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void emptyLineTest2() {
-        emptyLineMap.lineStartOffset(2);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void emptyLineTest3() {
-        emptyLineMap.offsetToCol(1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void emptyLineTest4() {
-        emptyLineMap.lineLength(2);
-    }
-
-    @Test
-    public void shortTextTest0() {
-
-        assertEquals(shortMap.lineCount(), 1);
-
-        assertEquals(shortMap.offsetToLine(0), 1);
-        assertEquals(shortMap.lineStartOffset(1), 0);
-        assertEquals(shortMap.offsetToCol(0), 1);
-
-        assertEquals(shortMap.offsetToLine(1), 1);
-        assertEquals(shortMap.offsetToCol(1), 2);
-
-        assertEquals(shortMap.lineLength(1), 2);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void shortTextTest1() {
-        shortMap.offsetToLine(-1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void shortTextTest2() {
-        shortMap.offsetToCol(-1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void shortTextTest3() {
-        shortMap.offsetToLine(2);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void shortTextTest4() {
-        shortMap.offsetToCol(2);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void shortTextTest5() {
-        shortMap.lineStartOffset(2);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void shortTextTest6() {
-        shortMap.lineLength(2);
-    }
-
-    @Test
-    public void longTextTest0() {
-
-        assertEquals(longMap.lineCount(), 3);
-
-        assertEquals(longMap.offsetToLine(0), 1);
-        assertEquals(longMap.lineStartOffset(1), 0);
-        assertEquals(longMap.offsetToCol(0), 1);
-
-        assertEquals(longMap.offsetToLine(4), 1);
-        assertEquals(longMap.offsetToCol(4), 5);
-
-        assertEquals(longMap.offsetToLine(5), 1); // newline
-        assertEquals(longMap.offsetToCol(5), 6); // newline
-        assertEquals(longMap.lineLength(1), 5);
-
-        assertEquals(longMap.offsetToLine(6), 2);
-        assertEquals(longMap.lineStartOffset(2), 6);
-        assertEquals(longMap.offsetToCol(6), 1);
-
-        assertEquals(longMap.offsetToLine(7), 2);
-        assertEquals(longMap.offsetToCol(7), 2);
-
-        assertEquals(longMap.offsetToLine(8), 2); // newline
-        assertEquals(longMap.offsetToLine(8), 2); // newline
-        assertEquals(longMap.lineLength(2), 2);
-
-        assertEquals(longMap.offsetToLine(9), 3);
-        assertEquals(longMap.lineStartOffset(3), 9);
-        assertEquals(longMap.offsetToCol(9), 1);
-
-        assertEquals(longMap.offsetToLine(10), 3); // newline
-        assertEquals(longMap.offsetToCol(10), 2); // newline
-        assertEquals(longMap.lineLength(3), 1);
-
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void longTextTest1() {
-        longMap.offsetToLine(11);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void longTextTest2() {
-        longMap.offsetToCol(11);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void longTextTest3() {
-        longMap.lineStartOffset(4);
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerAsserts.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerAsserts.java	Mon Jun 30 12:02:19 2014 +0200
@@ -29,7 +29,7 @@
  * either executed in the interpreter or in the compiled code. The assertions are checked during
  * code generation and the Truffle compiler produces for failing assertions a stack trace that
  * identifies the code position of the assertion in the context of the current compilation.
- * 
+ *
  */
 public class CompilerAsserts {
 
@@ -42,9 +42,12 @@
     public static void neverPartOfCompilation() {
     }
 
+    public static void neverPartOfCompilation(@SuppressWarnings("unused") String message) {
+    }
+
     /**
      * Assertion that the corresponding value is reduced to a constant during compilation.
-     * 
+     *
      * @param value the value that must be constant during compilation
      * @return the value given as parameter
      */
@@ -54,7 +57,7 @@
 
     /**
      * Assertion that the corresponding value is reduced to a constant during compilation.
-     * 
+     *
      * @param value the value that must be constant during compilation
      * @return the value given as parameter
      */
@@ -64,7 +67,7 @@
 
     /**
      * Assertion that the corresponding value is reduced to a constant during compilation.
-     * 
+     *
      * @param value the value that must be constant during compilation
      * @return the value given as parameter
      */
@@ -74,7 +77,7 @@
 
     /**
      * Assertion that the corresponding value is reduced to a constant during compilation.
-     * 
+     *
      * @param value the value that must be constant during compilation
      * @return the value given as parameter
      */
@@ -84,7 +87,7 @@
 
     /**
      * Assertion that the corresponding value is reduced to a constant during compilation.
-     * 
+     *
      * @param value the value that must be constant during compilation
      * @return the value given as parameter
      */
@@ -94,7 +97,7 @@
 
     /**
      * Assertion that the corresponding value is reduced to a constant during compilation.
-     * 
+     *
      * @param value the value that must be constant during compilation
      * @return the value given as parameter
      */
@@ -104,7 +107,7 @@
 
     /**
      * Assertion that the corresponding value is reduced to a constant during compilation.
-     * 
+     *
      * @param value the value that must be constant during compilation
      * @return the value given as parameter
      */
@@ -114,7 +117,7 @@
 
     /**
      * Assertion that the corresponding value is reduced to a constant during compilation.
-     * 
+     *
      * @param value the value that must be constant during compilation
      * @return the value given as parameter
      */
@@ -124,7 +127,7 @@
 
     /**
      * Assertion that the corresponding value is reduced to a constant during compilation.
-     * 
+     *
      * @param value the value that must be constant during compilation
      * @return the value given as parameter
      */
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Mon Jun 30 12:02:19 2014 +0200
@@ -109,6 +109,16 @@
     }
 
     /**
+     * Has a {@link Probe} been created that is uniquely associated with a particular source code
+     * location.
+     *
+     * @return a probe uniquely associated with an extent of guest language source code.
+     */
+    public final boolean hasProbe(SourceSection sourceSection) {
+        return probeManager.hasProbe(sourceSection);
+    }
+
+    /**
      * Returns all existing probes with specific tag, or all probes if {@code tag = null}; empty
      * collection if no probes found.
      */
@@ -120,7 +130,7 @@
      * Returns all existing probes with first character on a specified line; empty collection if no
      * probes found.
      */
-    public final Collection<Probe> findProbesByLine(SourceLineLocation lineLocation) {
+    public final Collection<Probe> findProbesByLine(LineLocation lineLocation) {
         return probeManager.findProbesByLine(lineLocation);
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/NullSourceSection.java	Mon Jun 30 08:50:26 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.truffle.api;
-
-/**
- * Marker for a special flavor of {@link SourceSection} that has no content and can be ignored.
- */
-public interface NullSourceSection extends SourceSection {
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java	Mon Jun 30 08:50:26 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2013, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.truffle.api;
-
-import java.io.*;
-
-import com.oracle.truffle.api.source.*;
-
-/**
- * Represents a unit (typically a file) of guest language source code.
- */
-public interface Source {
-
-    /**
-     * Returns the name of this resource holding a guest language program. An example would be the
-     * name of a guest language source code file.
-     *
-     * @return the name of the guest language program
-     */
-    String getName();
-
-    /**
-     * Returns a short version of the name of the resource holding a guest language program (as
-     * described in @getName). For example, this could be just the name of the file, rather than a
-     * full path.
-     *
-     * @return the short name of the guest language program
-     */
-    String getShortName();
-
-    /**
-     * The normalized, canonical name of the file.
-     */
-    String getPath();
-
-    /**
-     * Access to the source contents.
-     */
-    Reader getReader();
-
-    /**
-     * Access to the source contents.
-     */
-    InputStream getInputStream();
-
-    /**
-     * Return the complete text of the code.
-     */
-    String getCode();
-
-    /**
-     * Given a 1-based line number, return the text in the line, not including a possible
-     * terminating newline.
-     */
-    String getCode(int lineNumber);
-
-    /**
-     * The number of text lines in the source, including empty lines; characters at the end of the
-     * source without a terminating newline count as a line.
-     */
-    int getLineCount();
-
-    /**
-     * Given a 0-based character offset, return the 1-based number of the line that includes the
-     * position.
-     */
-    int getLineNumber(int offset);
-
-    /**
-     * Given a 1-based line number, return the 0-based offset of the first character in the line.
-     */
-    int getLineStartOffset(int lineNumber);
-
-    /**
-     * The number of characters (not counting a possible terminating newline) in a (1-based)
-     * numbered line.
-     */
-    int getLineLength(int lineNumber);
-
-    /**
-     * Creates a representation of a contiguous region of text in the source. Computes the
-     * {@code (startLine, startColumn)} values by building a {@linkplain TextMap map} of lines in
-     * the source.
-     * <p>
-     * Checks the position arguments for consistency with the source.
-     * <p>
-     * The resulting representation defines hash/equality around equivalent location, presuming that
-     * {@link Source} representations are cannonical.
-     *
-     *
-     * @param identifier terse description of the region
-     * @param charIndex 0-based position of the first character in the section
-     * @param length the number of characters in the section
-     * @return newly created object representing the specified region
-     * @throws IllegalArgumentException if either of the arguments are outside the text of the
-     *             source
-     * @throws IllegalStateException if the source is one of the "null" instances
-     */
-    SourceSection createSection(String identifier, int charIndex, int length) throws IllegalArgumentException, IllegalStateException;
-
-    /**
-     * Creates a representation of a contiguous region of text in the source. Computes the
-     * {@code charIndex} value by building a {@linkplain TextMap map} of lines in the source.
-     * <p>
-     * Checks the position arguments for consistency with the source.
-     * <p>
-     * The resulting representation defines hash/equality around equivalent location, presuming that
-     * {@link Source} representations are cannonical.
-     *
-     * @param identifier terse description of the region
-     * @param startLine 1-based line number of the first character in the section
-     * @param startColumn 1-based column number of the first character in the section
-     * @param length the number of characters in the section
-     * @return newly created object representing the specified region
-     * @throws IllegalArgumentException if arguments are outside the text of the source
-     * @throws IllegalStateException if the source is one of the "null" instances
-     */
-    SourceSection createSection(String identifier, int startLine, int startColumn, int length);
-
-    /**
-     * Creates a representation of a contiguous region of text in the source.
-     * <p>
-     * This method performs no checks on the validity of the arguments.
-     * <p>
-     * The resulting representation defines hash/equality around equivalent location, presuming that
-     * {@link Source} representations are cannonical.
-     *
-     * @param identifier terse description of the region
-     * @param startLine 1-based line number of the first character in the section
-     * @param startColumn 1-based column number of the first character in the section
-     * @param charIndex the 0-based index of the first character of the section
-     * @param length the number of characters in the section
-     * @return newly created object representing the specified region
-     */
-    SourceSection createSection(String identifier, int startLine, int startColumn, int charIndex, int length);
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Mon Jun 30 08:50:26 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-/*
- * Copyright (c) 2013, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.truffle.api;
-
-/**
- * Description of contiguous section of text within a {@link Source} of program code.
- *
- * The starting location of the section can be described using two different coordinates:
- * <ul>
- * <li>{@code (startLine, startColumn)}: rows and columns are 1-based, so the first character in a
- * source file is at position {@code (1,1)}. {@code Tab} characters are counted as occupying one
- * column.</li>
- * <li><b>character index</b>: 0-based offset of the character from the beginning of the source, so
- * the first character in a file is at index {@code 0}.</li>
- * </ul>
- * The {@code Newline} that terminates each line counts as a single character for the purpose of a
- * character index and when counting the length of text. The {@code (line,column)} coordinates of a
- * {@code Newline} should never appear in a text section.
- * <p>
- * If the final character of source is not a {@code Newline}, the final characters of the text are
- * still considered to be a line ("unterminated").
- * <p>
- *
- * @see Source#createSection(String, int, int, int, int)
- * @see Source#createSection(String, int, int, int)
- * @see Source#createSection(String, int, int)
- */
-public interface SourceSection {
-
-    // TODO support alternate text representations/encodings
-
-    /**
-     * Representation of the source program that contains this section.
-     *
-     * @return the source object
-     */
-    Source getSource();
-
-    /**
-     * Returns 1-based line number of the first character in this section (inclusive).
-     *
-     * @return the starting line number
-     */
-    int getStartLine();
-
-    /**
-     * Returns the 1-based column number of the first character in this section (inclusive).
-     *
-     * @return the starting column number
-     */
-    int getStartColumn();
-
-    /**
-     * Returns the 0-based index of the first character in this section.
-     *
-     * @return the starting character index
-     */
-    int getCharIndex();
-
-    /**
-     * Returns the length of this section in characters.
-     *
-     * @return the number of characters in the section
-     */
-    int getCharLength();
-
-    /**
-     * Returns the index of the text position immediately following the last character in the
-     * section.
-     *
-     * @return the end position of the section
-     */
-    int getCharEndIndex();
-
-    /**
-     * Returns terse text describing this source section, typically used for printing the section.
-     *
-     * @return the identifier of the section
-     */
-    String getIdentifier();
-
-    /**
-     * Returns text described by this section.
-     *
-     * @return the code as a String object
-     */
-    String getCode();
-
-    /**
-     * Returns a short description of the source section, using just the file name, rather than its
-     * full path.
-     *
-     * @return a short description of the source section
-     */
-    String getShortDescription();
-
-    /**
-     * Singleton instance with no content.
-     */
-    SourceSection NULL = new NullSourceSection() {
-
-        @Override
-        public Source getSource() {
-            return null;
-        }
-
-        @Override
-        public int getStartLine() {
-            return 0;
-        }
-
-        @Override
-        public int getStartColumn() {
-            return 0;
-        }
-
-        @Override
-        public int getCharIndex() {
-            return 0;
-        }
-
-        @Override
-        public int getCharLength() {
-            return 0;
-        }
-
-        @Override
-        public int getCharEndIndex() {
-            return 0;
-        }
-
-        @Override
-        public String getIdentifier() {
-            return null;
-        }
-
-        @Override
-        public String getCode() {
-            return null;
-        }
-
-        @Override
-        public String getShortDescription() {
-            return "short";
-        }
-
-    };
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleOptions.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleOptions.java	Mon Jun 30 12:02:19 2014 +0200
@@ -72,6 +72,13 @@
      */
     public static NodeCost TraceRewritesFilterToCost = parseNodeInfoKind(System.getProperty("truffle.TraceRewritesFilterToCost"));
 
+    /**
+     * Enables the dumping of Node creations and AST rewrites in JSON format.
+     * <p>
+     * Can be set with {@code -Dtruffle.TraceASTJSON=true}.
+     */
+    public static final boolean TraceASTJSON = Boolean.getBoolean("truffle.TraceASTJSON");
+
     private static NodeCost parseNodeInfoKind(String kind) {
         if (kind == null) {
             return null;
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java	Mon Jun 30 12:02:19 2014 +0200
@@ -57,6 +57,7 @@
     }
 
     public FrameSlot addFrameSlot(Object identifier, FrameSlotKind kind) {
+        CompilerAsserts.neverPartOfCompilation("interpreter-only.  includes hashmap operations.");
         assert !identifierToSlotMap.containsKey(identifier);
         FrameSlot slot = new FrameSlot(this, identifier, slots.size(), kind);
         slots.add(slot);
@@ -87,6 +88,7 @@
     }
 
     public void removeFrameSlot(Object identifier) {
+        CompilerAsserts.neverPartOfCompilation("interpreter-only.  includes hashmap operations.");
         assert identifierToSlotMap.containsKey(identifier);
         slots.remove(identifierToSlotMap.get(identifier));
         identifierToSlotMap.remove(identifier);
@@ -104,7 +106,7 @@
 
     /**
      * Retrieve the list of all the identifiers associated with this frame descriptor.
-     * 
+     *
      * @return the list of all the identifiers in this frame descriptor
      */
     public Set<Object> getIdentifiers() {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java	Mon Jun 30 12:02:19 2014 +0200
@@ -25,6 +25,7 @@
 package com.oracle.truffle.api.frame;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 
 /**
  * A slot in a frame that can store a value of a given type.
@@ -34,7 +35,7 @@
     private final FrameDescriptor descriptor;
     private final Object identifier;
     private final int index;
-    @com.oracle.truffle.api.CompilerDirectives.CompilationFinal private FrameSlotKind kind;
+    @CompilationFinal private FrameSlotKind kind;
 
     public FrameSlot(FrameDescriptor descriptor, Object identifier, int index, FrameSlotKind kind) {
         this.descriptor = descriptor;
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,7 +24,7 @@
  */
 package com.oracle.truffle.api.instrument;
 
-import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.source.*;
 
 /**
  * A collector of {@link ExecutionEvents} at a specific site (node) in a Truffle AST (generated by a
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,10 +24,14 @@
  */
 package com.oracle.truffle.api.instrument;
 
-import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.source.*;
 
 /**
  * Client for receiving events relate to {@link Probe} management. Does not report AST copying.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development.
+ *
+ * @See Instrumentation
  */
 public interface ProbeListener {
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SourceCallback.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SourceCallback.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,7 +24,7 @@
  */
 package com.oracle.truffle.api.instrument;
 
-import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.source.*;
 
 /**
  * Instrumentation callback for guest language source-related events.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SourceListener.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SourceListener.java	Mon Jun 30 12:02:19 2014 +0200
@@ -24,7 +24,7 @@
  */
 package com.oracle.truffle.api.instrument;
 
-import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.source.*;
 
 /**
  * A client of the instrumentation framework that requests event notifications from the language
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java	Mon Jun 30 12:02:19 2014 +0200
@@ -27,12 +27,12 @@
 import java.io.*;
 import java.util.*;
 
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.nodes.NodeUtil.NodeClass;
 import com.oracle.truffle.api.nodes.NodeUtil.NodeField;
 import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind;
+import com.oracle.truffle.api.source.*;
 
 /**
  * A language-agnostic for printing out various pieces of a Truffle AST.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java	Mon Jun 30 12:02:19 2014 +0200
@@ -28,6 +28,7 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
 
 public class DefaultVisualizer implements Visualizer {
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -31,6 +31,7 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
 
 /**
  * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java	Mon Jun 30 12:02:19 2014 +0200
@@ -26,7 +26,6 @@
 
 import java.util.*;
 
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeCallback;
 import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeImpl;
@@ -47,7 +46,7 @@
     /**
      * Map: Source line ==> probes associated with source sections starting on the line.
      */
-    private final Map<SourceLineLocation, Collection<Probe>> lineToProbes = new HashMap<>();
+    private final Map<LineLocation, Collection<Probe>> lineToProbes = new HashMap<>();
 
     private final List<ProbeListener> probeListeners = new ArrayList<>();
 
@@ -104,7 +103,7 @@
 
         // Register new probe by source line, there may be more than one
         // Create line location for map key
-        final SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine());
+        final LineLocation lineLocation = sourceSection.getLineLocation();
 
         Collection<Probe> probes = lineToProbes.get(lineLocation);
         if (probes == null) {
@@ -120,6 +119,11 @@
         return probe;
     }
 
+    public boolean hasProbe(SourceSection sourceSection) {
+        assert sourceSection != null;
+        return srcToProbe.get(sourceSection) != null;
+    }
+
     public Collection<Probe> findProbesTaggedAs(PhylumTag tag) {
         final List<Probe> probes = new ArrayList<>();
         for (Probe probe : srcToProbe.values()) {
@@ -130,7 +134,7 @@
         return probes;
     }
 
-    public Collection<Probe> findProbesByLine(SourceLineLocation lineLocation) {
+    public Collection<Probe> findProbesByLine(LineLocation lineLocation) {
         final Collection<Probe> probes = lineToProbes.get(lineLocation);
         if (probes == null) {
             return Collections.emptyList();
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,6 +30,8 @@
 import java.util.concurrent.*;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.api.utilities.*;
 
 /**
  * Abstract base class for all Truffle nodes.
@@ -57,12 +59,15 @@
     }
 
     protected Node() {
-        CompilerAsserts.neverPartOfCompilation();
+        this(null);
     }
 
     protected Node(SourceSection sourceSection) {
         CompilerAsserts.neverPartOfCompilation();
         this.sourceSection = sourceSection;
+        if (TruffleOptions.TraceASTJSON) {
+            JSONHelper.dumpNewNode(this);
+        }
     }
 
     /**
@@ -168,6 +173,9 @@
         }
         boolean isInserted = newChild.parent == null;
         newChild.parent = this;
+        if (TruffleOptions.TraceASTJSON) {
+            JSONHelper.dumpNewChild(this, newChild);
+        }
         newChild.adoptHelper();
         if (isInserted) {
             newChild.onAdopt();
@@ -272,6 +280,9 @@
             this.parent.adoptUnadoptedHelper(newNode);
         }
         reportReplace(this, newNode, reason);
+        if (TruffleOptions.TraceASTJSON) {
+            JSONHelper.dumpReplaceChild(this, newNode, reason);
+        }
         onReplace(newNode, reason);
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon Jun 30 12:02:19 2014 +0200
@@ -34,6 +34,7 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.Node.Child;
 import com.oracle.truffle.api.nodes.Node.Children;
+import com.oracle.truffle.api.source.*;
 
 /**
  * Utility class that manages the special access methods for node instances.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.source.*;
 
 /**
  * A root node is a node with a method to execute it given only a frame as a parameter. Therefore, a
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderDeserializer.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderDeserializer.java	Mon Jun 30 12:02:19 2014 +0200
@@ -29,11 +29,11 @@
 
 import sun.misc.*;
 
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.nodes.NodeUtil.NodeClass;
 import com.oracle.truffle.api.nodes.NodeUtil.NodeField;
 import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind;
+import com.oracle.truffle.api.source.*;
 
 /**
  * Experimental API. May change without notice.
@@ -61,12 +61,12 @@
 
     /**
      * Deserializes the byte stream and returns the deserialized Truffle AST node.
-     * 
+     *
      * @param bytes the trimmed byte array containing the serialized data
      * @param expectedType the expected root node type. Throws an exception if the root node is not
      *            assignable from this type.
      * @return the deserialized Truffle AST represented by the root Node.
-     * 
+     *
      * @throws UnsupportedConstantPoolTypeException thrown if a type is encountered that is not
      *             supported by the constant pool implementation.
      */
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderSerializer.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderSerializer.java	Mon Jun 30 12:02:19 2014 +0200
@@ -29,11 +29,11 @@
 
 import sun.misc.*;
 
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.nodes.NodeUtil.NodeClass;
 import com.oracle.truffle.api.nodes.NodeUtil.NodeField;
 import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind;
+import com.oracle.truffle.api.source.*;
 
 /**
  * Experimental API. May change without notice.
@@ -59,10 +59,10 @@
 
     /**
      * Serializes the node AST and returns the serialized data as byte array.
-     * 
+     *
      * @param node the root node that represents the Truffle AST that should be serialized.
      * @return a trimmed byte array that contains the serialized data.
-     * 
+     *
      * @throws UnsupportedConstantPoolTypeException thrown if a type is encountered that is not
      *             supported by the constant pool implementation.
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/LineLocation.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.truffle.api.source;
+
+/**
+ * A specification for a location in guest language source, expressed as a line number in a specific
+ * instance of {@link Source}, suitable for hash table keys with equality defined in terms of
+ * content.
+ */
+public interface LineLocation {
+
+    public Source getSource();
+
+    /**
+     * Gets the 1-based number of a line in the source
+     */
+    public int getLineNumber();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/NullSourceSection.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,105 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.truffle.api.source;
+
+/**
+ * A special subtype of {@link SourceSection} that represents unavailable source, e.g. for language
+ * <em>builtins</em>.
+ */
+public class NullSourceSection implements SourceSection {
+
+    private final String kind;
+    private final String name;
+    private final String asCode;
+
+    /**
+     * Placeholder for source that is unavailable, e.g. for language <em>builtins</em>.
+     *
+     * @param kind the general category, e.g. "JS builtin"
+     * @param name specific name for this section
+     */
+    public NullSourceSection(String kind, String name) {
+        this(kind, name, kind);
+    }
+
+    /**
+     * Placeholder for source that is unavailable, e.g. for language <em>builtins</em>.
+     *
+     * @param kind the general category, e.g. "JS builtin"
+     * @param name specific name for this section
+     * @param asCode string to return when {@link #getCode()} is called
+     */
+    public NullSourceSection(String kind, String name, String asCode) {
+        this.kind = kind;
+        this.name = name;
+        this.asCode = asCode;
+    }
+
+    public final Source getSource() {
+        return null;
+    }
+
+    public final int getStartLine() {
+        throw new UnsupportedOperationException(this.toString());
+    }
+
+    public final LineLocation getLineLocation() {
+        throw new UnsupportedOperationException(this.toString());
+    }
+
+    public final int getStartColumn() {
+        throw new UnsupportedOperationException(this.toString());
+    }
+
+    public final int getCharIndex() {
+        throw new UnsupportedOperationException(this.toString());
+    }
+
+    public final int getCharLength() {
+        throw new UnsupportedOperationException(this.toString());
+    }
+
+    public final int getCharEndIndex() {
+        throw new UnsupportedOperationException(this.toString());
+    }
+
+    public final String getIdentifier() {
+        return name;
+    }
+
+    public final String getCode() {
+        return asCode;
+    }
+
+    public final String getShortDescription() {
+        return kind + ": " + name;
+    }
+
+    @Override
+    public String toString() {
+        return getShortDescription();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,975 @@
+/*
+ * Copyright (c) 2013, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.truffle.api.source;
+
+import java.io.*;
+import java.lang.ref.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * Representation of a guest language source code unit and its contents. Sources originate in
+ * several ways:
+ * <ul>
+ * <li><strong>Literal:</strong> A named text string. These are not indexed and should be considered
+ * value objects; equality is defined based on contents. <br>
+ * See {@link Source#fromText(String, String)}</li>
+ * <p>
+ * <li><strong>File:</strong> Each file is represented as a canonical object, indexed by the
+ * absolute, canonical path name of the file. File contents are <em>read lazily</em> and contents
+ * optionally <em>cached</em>. <br>
+ * See {@link Source#fromFileName(String)}<br>
+ * See {@link Source#fromFileName(String, boolean)}</li>
+ * <p>
+ * <li><strong>URL:</strong> Each URL source is represented as a canonical object, indexed by the
+ * URL. Contents are <em>read eagerly</em> and <em>cached</em>. <br>
+ * See {@link Source#fromURL(URL, String)}</li>
+ * <p>
+ * <li><strong>Reader:</strong> Contents are <em>read eagerly</em> and treated as a <em>Literal</em>
+ * . <br>
+ * See {@link Source#fromReader(Reader, String)}</li>
+ * <p>
+ * <li><strong>Pseudo File:</strong> A literal text string that can be retrieved by name as if it
+ * were a file, unlike literal sources; useful for testing. <br>
+ * See {@link Source#asPseudoFile(String, String)}</li>
+ * </ul>
+ * <p>
+ * <strong>File cache:</strong>
+ * <ol>
+ * <li>File content caching is optional, <em>off</em> by default.</li>
+ * <li>The first access to source file contents will result in the contents being read, and (if
+ * enabled) cached.</li>
+ * <li>If file contents have been cached, access to contents via {@link Source#getInputStream()} or
+ * {@link Source#getReader()} will be provided from the cache.</li>
+ * <li>Any access to file contents via the cache will result in a timestamp check and possible cache
+ * reload.</li>
+ * </ol>
+ */
+public abstract class Source {
+
+    // TODO (mlvdv) consider canonicalizing and reusing SourceSection instances
+    // TOOD (mlvdv) connect SourceSections into a spatial tree for fast geometric lookup
+
+    // Files and pseudo files are indexed.
+    private static final Map<String, WeakReference<Source>> filePathToSource = new HashMap<>();
+
+    private static boolean fileCacheEnabled = true;
+
+    /**
+     * Gets the canonical representation of a source file, whose contents will be read lazily and
+     * then cached.
+     *
+     * @param fileName name
+     * @param reset forces any existing {@link Source} cache to be cleared, forcing a re-read
+     * @return canonical representation of the file's contents.
+     * @throws IOException if the file can not be read
+     */
+    public static Source fromFileName(String fileName, boolean reset) throws IOException {
+
+        final WeakReference<Source> nameRef = filePathToSource.get(fileName);
+        Source source = nameRef == null ? null : nameRef.get();
+        if (source == null) {
+            final File file = new File(fileName);
+            if (!file.canRead()) {
+                throw new IOException("Can't read file " + fileName);
+            }
+            final String path = file.getCanonicalPath();
+            final WeakReference<Source> pathRef = filePathToSource.get(path);
+            source = pathRef == null ? null : pathRef.get();
+            if (source == null) {
+                source = new FileSource(file, fileName, path);
+                filePathToSource.put(path, new WeakReference<>(source));
+            }
+        }
+        if (reset) {
+            source.reset();
+        }
+        return source;
+    }
+
+    /**
+     * Gets the canonical representation of a source file, whose contents will be read lazily and
+     * then cached.
+     *
+     * @param fileName name
+     * @return canonical representation of the file's contents.
+     * @throws IOException if the file can not be read
+     */
+    public static Source fromFileName(String fileName) throws IOException {
+        return fromFileName(fileName, false);
+    }
+
+    /**
+     * Creates a non-canonical source from literal text.
+     *
+     * @param code textual source code
+     * @param description a note about the origin, for error messages and debugging
+     * @return a newly created, non-indexed source representation
+     */
+    public static Source fromText(String code, String description) {
+        assert code != null;
+        return new LiteralSource(description, code);
+    }
+
+    /**
+     * Creates a source whose contents will be read immediately from a URL and cached.
+     *
+     * @param url
+     * @param name identifies the origin, possibly useful for debugging
+     * @return a newly created, non-indexed source representation
+     * @throws IOException if reading fails
+     */
+    public static Source fromURL(URL url, String name) throws IOException {
+        return URLSource.get(url, name);
+    }
+
+    /**
+     * Creates a source whose contents will be read immediately and cached.
+     *
+     * @param reader
+     * @param description a note about the origin, possibly useful for debugging
+     * @return a newly created, non-indexed source representation
+     * @throws IOException if reading fails
+     */
+    public static Source fromReader(Reader reader, String description) throws IOException {
+        return new LiteralSource(description, read(reader));
+    }
+
+    /**
+     * Creates a source from literal text, but which acts as a file and can be retrieved by name
+     * (unlike other literal sources); intended for testing.
+     *
+     * @param code textual source code
+     * @param pseudoFileName string to use for indexing/lookup
+     * @return a newly created, source representation, canonical with respect to its name
+     */
+    public static Source asPseudoFile(String code, String pseudoFileName) {
+        final Source source = new LiteralSource(pseudoFileName, code);
+        filePathToSource.put(pseudoFileName, new WeakReference<>(source));
+        return source;
+    }
+
+    /**
+     * Enables/disables caching of file contents, <em>disabled</em> by default. Caching of sources
+     * created from literal text or readers is always enabled.
+     */
+    public static void setFileCaching(boolean enabled) {
+        fileCacheEnabled = enabled;
+    }
+
+    private static String read(Reader reader) throws IOException {
+        final StringBuilder builder = new StringBuilder();
+        final char[] buffer = new char[1024];
+
+        while (true) {
+            final int n = reader.read(buffer);
+            if (n == -1) {
+                break;
+            }
+            builder.append(buffer, 0, n);
+        }
+
+        return builder.toString();
+    }
+
+    Source() {
+    }
+
+    private TextMap textMap = null;
+
+    protected abstract void reset();
+
+    /**
+     * Returns the name of this resource holding a guest language program. An example would be the
+     * name of a guest language source code file.
+     *
+     * @return the name of the guest language program
+     */
+    public abstract String getName();
+
+    /**
+     * Returns a short version of the name of the resource holding a guest language program (as
+     * described in @getName). For example, this could be just the name of the file, rather than a
+     * full path.
+     *
+     * @return the short name of the guest language program
+     */
+    public abstract String getShortName();
+
+    /**
+     * The normalized, canonical name if the source is a file.
+     */
+    public abstract String getPath();
+
+    /**
+     * The URL if the source is retrieved via URL.
+     */
+    public abstract URL getURL();
+
+    /**
+     * Access to the source contents.
+     */
+    public abstract Reader getReader();
+
+    /**
+     * Access to the source contents.
+     */
+    public final InputStream getInputStream() {
+        return new ByteArrayInputStream(getCode().getBytes());
+    }
+
+    /**
+     * Return the complete text of the code.
+     */
+    public abstract String getCode();
+
+    /**
+     * Gets the text (not including a possible terminating newline) in a (1-based) numbered line.
+     */
+    public final String getCode(int lineNumber) {
+        checkTextMap();
+        final int offset = textMap.lineStartOffset(lineNumber);
+        final int length = textMap.lineLength(lineNumber);
+        return getCode().substring(offset, offset + length);
+    }
+
+    /**
+     * The number of text lines in the source, including empty lines; characters at the end of the
+     * source without a terminating newline count as a line.
+     */
+    public final int getLineCount() {
+        return checkTextMap().lineCount();
+    }
+
+    /**
+     * Given a 0-based character offset, return the 1-based number of the line that includes the
+     * position.
+     *
+     * @throws IllegalArgumentException if the offset is outside the text contents
+     */
+    public final int getLineNumber(int offset) throws IllegalArgumentException {
+        return checkTextMap().offsetToLine(offset);
+    }
+
+    /**
+     * Given a 0-based character offset, return the 1-based number of the column at the position.
+     *
+     * @throws IllegalArgumentException if the offset is outside the text contents
+     */
+    public final int getColumnNumber(int offset) throws IllegalArgumentException {
+        return checkTextMap().offsetToCol(offset);
+    }
+
+    /**
+     * Given a 1-based line number, return the 0-based offset of the first character in the line.
+     *
+     * @throws IllegalArgumentException if there is no such line in the text
+     */
+    public final int getLineStartOffset(int lineNumber) throws IllegalArgumentException {
+        return checkTextMap().lineStartOffset(lineNumber);
+    }
+
+    /**
+     * The number of characters (not counting a possible terminating newline) in a (1-based)
+     * numbered line.
+     *
+     * @throws IllegalArgumentException if there is no such line in the text
+     */
+    public final int getLineLength(int lineNumber) throws IllegalArgumentException {
+        return checkTextMap().lineLength(lineNumber);
+    }
+
+    /**
+     * Creates a representation of a contiguous region of text in the source.
+     * <p>
+     * This method performs no checks on the validity of the arguments.
+     * <p>
+     * The resulting representation defines hash/equality around equivalent location, presuming that
+     * {@link Source} representations are canonical.
+     *
+     * @param identifier terse description of the region
+     * @param startLine 1-based line number of the first character in the section
+     * @param startColumn 1-based column number of the first character in the section
+     * @param charIndex the 0-based index of the first character of the section
+     * @param length the number of characters in the section
+     * @return newly created object representing the specified region
+     */
+    public final SourceSection createSection(String identifier, int startLine, int startColumn, int charIndex, int length) {
+        return new DefaultSourceSection(this, identifier, startLine, startColumn, charIndex, length);
+    }
+
+    /**
+     * Creates a representation of a contiguous region of text in the source. Computes the
+     * {@code charIndex} value by building a {@linkplain TextMap map} of lines in the source.
+     * <p>
+     * Checks the position arguments for consistency with the source.
+     * <p>
+     * The resulting representation defines hash/equality around equivalent location, presuming that
+     * {@link Source} representations are canonical.
+     *
+     * @param identifier terse description of the region
+     * @param startLine 1-based line number of the first character in the section
+     * @param startColumn 1-based column number of the first character in the section
+     * @param length the number of characters in the section
+     * @return newly created object representing the specified region
+     * @throws IllegalArgumentException if arguments are outside the text of the source
+     * @throws IllegalStateException if the source is one of the "null" instances
+     */
+    public final SourceSection createSection(String identifier, int startLine, int startColumn, int length) {
+        checkTextMap();
+        final int lineStartOffset = textMap.lineStartOffset(startLine);
+        if (startColumn > textMap.lineLength(startLine)) {
+            throw new IllegalArgumentException("column out of range");
+        }
+        final int startOffset = lineStartOffset + startColumn - 1;
+        return new DefaultSourceSection(this, identifier, startLine, startColumn, startOffset, length);
+    }
+
+    /**
+     * Creates a representation of a contiguous region of text in the source. Computes the
+     * {@code (startLine, startColumn)} values by building a {@linkplain TextMap map} of lines in
+     * the source.
+     * <p>
+     * Checks the position arguments for consistency with the source.
+     * <p>
+     * The resulting representation defines hash/equality around equivalent location, presuming that
+     * {@link Source} representations are canonical.
+     *
+     *
+     * @param identifier terse description of the region
+     * @param charIndex 0-based position of the first character in the section
+     * @param length the number of characters in the section
+     * @return newly created object representing the specified region
+     * @throws IllegalArgumentException if either of the arguments are outside the text of the
+     *             source
+     * @throws IllegalStateException if the source is one of the "null" instances
+     */
+    public final SourceSection createSection(String identifier, int charIndex, int length) throws IllegalArgumentException {
+        final int codeLength = getCode().length();
+        if (!(charIndex >= 0 && length >= 0 && charIndex + length <= codeLength)) {
+            throw new IllegalArgumentException("text positions out of range");
+        }
+        checkTextMap();
+        final int startLine = getLineNumber(charIndex);
+        final int startColumn = charIndex - getLineStartOffset(startLine) + 1;
+
+        return new DefaultSourceSection(this, identifier, startLine, startColumn, charIndex, length);
+    }
+
+    /**
+     * Creates a representation of a line of text in the source identified only by line number, from
+     * which the character information will be computed.
+     *
+     * @param identifier terse description of the line
+     * @param lineNumber 1-based line number of the first character in the section
+     * @return newly created object representing the specified line
+     * @throws IllegalArgumentException if the line does not exist the source
+     * @throws IllegalStateException if the source is one of the "null" instances
+     */
+    public final SourceSection createSection(String identifier, int lineNumber) {
+        checkTextMap();
+        final int charIndex = textMap.lineStartOffset(lineNumber);
+        final int length = textMap.lineLength(lineNumber);
+        return createSection(identifier, charIndex, length);
+    }
+
+    /**
+     * Creates a representation of a line number in this source, suitable for use as a hash table
+     * key with equality defined to mean equivalent location.
+     *
+     * @param lineNumber a 1-based line number in this source
+     * @return a representation of a line in this source
+     */
+    public final LineLocation createLineLocation(int lineNumber) {
+        return new LineLocationImpl(this, lineNumber);
+    }
+
+    private TextMap checkTextMap() {
+        if (textMap == null) {
+            final String code = getCode();
+            if (code == null) {
+                throw new RuntimeException("can't read file " + getName());
+            }
+            textMap = new TextMap(code);
+        }
+        return textMap;
+    }
+
+    private static final class LiteralSource extends Source {
+
+        private final String name; // Name used originally to describe the source
+        private final String code;
+
+        public LiteralSource(String name, String code) {
+            this.name = name;
+            this.code = code;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String getShortName() {
+            return name;
+        }
+
+        @Override
+        public String getCode() {
+            return code;
+        }
+
+        @Override
+        public String getPath() {
+            return name;
+        }
+
+        @Override
+        public URL getURL() {
+            return null;
+        }
+
+        @Override
+        public Reader getReader() {
+            return new StringReader(code);
+        }
+
+        @Override
+        protected void reset() {
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + name.hashCode();
+            result = prime * result + (code == null ? 0 : code.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (!(obj instanceof LiteralSource)) {
+                return false;
+            }
+            LiteralSource other = (LiteralSource) obj;
+            return name.equals(other.name) && code.equals(other.code);
+        }
+
+    }
+
+    private static final class FileSource extends Source {
+
+        private final File file;
+        private final String name; // Name used originally to describe the source
+        private final String path;  // Normalized path description of an actual file
+
+        private String code = null;  // A cache of the file's contents
+        private long timeStamp;      // timestamp of the cache in the file system
+
+        public FileSource(File file, String name, String path) {
+            this.file = file;
+            this.name = name;
+            this.path = path;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String getShortName() {
+            return file.getName();
+        }
+
+        @Override
+        public String getCode() {
+            if (fileCacheEnabled) {
+                if (code == null || timeStamp != file.lastModified()) {
+                    try {
+                        code = read(getReader());
+                        timeStamp = file.lastModified();
+                    } catch (IOException e) {
+                    }
+                }
+                return code;
+            }
+            try {
+                return read(new FileReader(file));
+            } catch (IOException e) {
+            }
+            return null;
+        }
+
+        @Override
+        public String getPath() {
+            return path;
+        }
+
+        @Override
+        public URL getURL() {
+            return null;
+        }
+
+        @Override
+        public Reader getReader() {
+            if (code != null && timeStamp == file.lastModified()) {
+                return new StringReader(code);
+            }
+            try {
+                return new FileReader(file);
+            } catch (FileNotFoundException e) {
+                throw new RuntimeException("Can't find file " + path);
+            }
+        }
+
+        @Override
+        protected void reset() {
+            this.code = null;
+        }
+
+    }
+
+    private static final class URLSource extends Source {
+
+        private static final Map<URL, WeakReference<URLSource>> urlToSource = new HashMap<>();
+
+        public static URLSource get(URL url, String name) throws IOException {
+            WeakReference<URLSource> sourceRef = urlToSource.get(url);
+            URLSource source = sourceRef == null ? null : sourceRef.get();
+            if (source == null) {
+                source = new URLSource(url, name);
+                urlToSource.put(url, new WeakReference<>(source));
+            }
+            return source;
+        }
+
+        private final URL url;
+        private final String name;
+        private String code = null;  // A cache of the source contents
+
+        public URLSource(URL url, String name) throws IOException {
+            this.url = url;
+            this.name = name;
+            code = read(new InputStreamReader(url.openStream()));
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String getShortName() {
+            return name;
+        }
+
+        @Override
+        public String getPath() {
+            return url.getPath();
+        }
+
+        @Override
+        public URL getURL() {
+            return url;
+        }
+
+        @Override
+        public Reader getReader() {
+            return new StringReader(code);
+        }
+
+        @Override
+        public String getCode() {
+            return code;
+        }
+
+        @Override
+        protected void reset() {
+        }
+
+    }
+
+    private static final class DefaultSourceSection implements SourceSection {
+
+        private final Source source;
+        private final String identifier;
+        private final int startLine;
+        private final int startColumn;
+        private final int charIndex;
+        private final int charLength;
+
+        /**
+         * Creates a new object representing a contiguous text section within the source code of a
+         * guest language program's text.
+         * <p>
+         * The starting location of the section is specified using two different coordinate:
+         * <ul>
+         * <li><b>(row, column)</b>: rows and columns are 1-based, so the first character in a
+         * source file is at position {@code (1,1)}.</li>
+         * <li><b>character index</b>: 0-based offset of the character from the beginning of the
+         * source, so the first character in a file is at index {@code 0}.</li>
+         * </ul>
+         * The <b>newline</b> that terminates each line counts as a single character for the purpose
+         * of a character index. The (row,column) coordinates of a newline character should never
+         * appear in a text section.
+         * <p>
+         *
+         * @param source object representing the complete source program that contains this section
+         * @param identifier an identifier used when printing the section
+         * @param startLine the 1-based number of the start line of the section
+         * @param startColumn the 1-based number of the start column of the section
+         * @param charIndex the 0-based index of the first character of the section
+         * @param charLength the length of the section in number of characters
+         */
+        public DefaultSourceSection(Source source, String identifier, int startLine, int startColumn, int charIndex, int charLength) {
+            this.source = source;
+            this.identifier = identifier;
+            this.startLine = startLine;
+            this.startColumn = startColumn;
+            this.charIndex = charIndex;
+            this.charLength = charLength;
+        }
+
+        @Override
+        public final Source getSource() {
+            return source;
+        }
+
+        @Override
+        public final int getStartLine() {
+            return startLine;
+        }
+
+        @Override
+        public final LineLocation getLineLocation() {
+            return source.createLineLocation(startLine);
+        }
+
+        @Override
+        public final int getStartColumn() {
+            return startColumn;
+        }
+
+        @Override
+        public final int getCharIndex() {
+            return charIndex;
+        }
+
+        @Override
+        public final int getCharLength() {
+            return charLength;
+        }
+
+        @Override
+        public final int getCharEndIndex() {
+            return charIndex + charLength;
+        }
+
+        @Override
+        public final String getIdentifier() {
+            return identifier;
+        }
+
+        @Override
+        public final String getCode() {
+            return getSource().getCode().substring(charIndex, charIndex + charLength);
+        }
+
+        @Override
+        public final String getShortDescription() {
+            return String.format("%s:%d", source.getShortName(), startLine);
+        }
+
+        @Override
+        public String toString() {
+            return getCode();
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + charIndex;
+            result = prime * result + charLength;
+            result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
+            result = prime * result + ((source == null) ? 0 : source.hashCode());
+            result = prime * result + startColumn;
+            result = prime * result + startLine;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (!(obj instanceof DefaultSourceSection)) {
+                return false;
+            }
+            DefaultSourceSection other = (DefaultSourceSection) obj;
+            if (charIndex != other.charIndex) {
+                return false;
+            }
+            if (charLength != other.charLength) {
+                return false;
+            }
+            if (identifier == null) {
+                if (other.identifier != null) {
+                    return false;
+                }
+            } else if (!identifier.equals(other.identifier)) {
+                return false;
+            }
+            if (source == null) {
+                if (other.source != null) {
+                    return false;
+                }
+            } else if (!source.equals(other.source)) {
+                return false;
+            }
+            if (startColumn != other.startColumn) {
+                return false;
+            }
+            if (startLine != other.startLine) {
+                return false;
+            }
+            return true;
+        }
+
+    }
+
+    private static final class LineLocationImpl implements LineLocation {
+        private final Source source;
+        private final int line;
+
+        public LineLocationImpl(Source source, int line) {
+            assert source != null;
+            this.source = source;
+            this.line = line;
+        }
+
+        @Override
+        public Source getSource() {
+            return source;
+        }
+
+        @Override
+        public int getLineNumber() {
+            return line;
+        }
+
+        @Override
+        public String toString() {
+            return "SourceLine [" + source.getName() + ", " + line + "]";
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + line;
+            result = prime * result + source.hashCode();
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (!(obj instanceof LineLocationImpl)) {
+                return false;
+            }
+            LineLocationImpl other = (LineLocationImpl) obj;
+            if (line != other.line) {
+                return false;
+            }
+            return source.equals(other.source);
+        }
+
+    }
+
+    /**
+     * A utility for converting between coordinate systems in a string of text interspersed with
+     * newline characters. The coordinate systems are:
+     * <ul>
+     * <li>0-based character offset from the beginning of the text, where newline characters count
+     * as a single character and the first character in the text occupies position 0.</li>
+     * <li>1-based position in the 2D space of lines and columns, in which the first position in the
+     * text is at (1,1).</li>
+     * </ul>
+     * <p>
+     * This utility is based on positions occupied by characters, not text stream positions as in a
+     * text editor. The distinction shows up in editors where you can put the cursor just past the
+     * last character in a buffer; this is necessary, among other reasons, so that you can put the
+     * edit cursor in a new (empty) buffer. For the purposes of this utility, however, there are no
+     * character positions in an empty text string and there are no lines in an empty text string.
+     * <p>
+     * A newline character designates the end of a line and occupies a column position.
+     * <p>
+     * If the text ends with a character other than a newline, then the characters following the
+     * final newline character count as a line, even though not newline-terminated.
+     * <p>
+     * <strong>Limitations:</strong>
+     * <ul>
+     * <li>Does not handle multiple character encodings correctly.</li>
+     * <li>Treats tabs as occupying 1 column.</li>
+     * <li>Does not handle multiple-character line termination sequences correctly.</li>
+     * </ul>
+     */
+    private static final class TextMap {
+
+        // 0-based offsets of newline characters in the text, with sentinel
+        private final int[] nlOffsets;
+
+        // The number of characters in the text, including newlines (which count as 1).
+        private final int textLength;
+
+        // Is the final text character a newline?
+        final boolean finalNL;
+
+        /**
+         * Constructs map permitting translation between 0-based character offsets and 1-based
+         * lines/columns.
+         */
+        public TextMap(String text) {
+            this.textLength = text.length();
+            final ArrayList<Integer> lines = new ArrayList<>();
+            lines.add(0);
+            int offset = 0;
+
+            while (offset < text.length()) {
+                final int nlIndex = text.indexOf('\n', offset);
+                if (nlIndex >= 0) {
+                    offset = nlIndex + 1;
+                    lines.add(offset);
+                } else {
+                    break;
+                }
+            }
+            lines.add(Integer.MAX_VALUE);
+
+            nlOffsets = new int[lines.size()];
+            for (int line = 0; line < lines.size(); line++) {
+                nlOffsets[line] = lines.get(line);
+            }
+
+            finalNL = textLength > 0 && (textLength == nlOffsets[nlOffsets.length - 2]);
+        }
+
+        /**
+         * Converts 0-based character offset to 1-based number of the line containing the character.
+         *
+         * @throws IllegalArgumentException if the offset is outside the string.
+         */
+        public int offsetToLine(int offset) throws IllegalArgumentException {
+            if (offset < 0 || offset >= textLength) {
+                throw new IllegalArgumentException("offset out of bounds");
+            }
+            int line = 1;
+            while (offset >= nlOffsets[line]) {
+                line++;
+            }
+            return line;
+        }
+
+        /**
+         * Converts 0-based character offset to 1-based number of the column occupied by the
+         * character.
+         * <p>
+         * Tabs are not expanded; they occupy 1 column.
+         *
+         * @throws IllegalArgumentException if the offset is outside the string.
+         */
+        public int offsetToCol(int offset) throws IllegalArgumentException {
+            return 1 + offset - nlOffsets[offsetToLine(offset) - 1];
+        }
+
+        /**
+         * The number of lines in the text; if characters appear after the final newline, then they
+         * also count as a line, even though not newline-terminated.
+         */
+        public int lineCount() {
+            if (textLength == 0) {
+                return 0;
+            }
+            return finalNL ? nlOffsets.length - 2 : nlOffsets.length - 1;
+        }
+
+        /**
+         * Converts 1-based line number to the 0-based offset of the line's first character; this
+         * would be the offset of a newline if the line is empty.
+         *
+         * @throws IllegalArgumentException if there is no such line in the text.
+         */
+        public int lineStartOffset(int line) throws IllegalArgumentException {
+            if (textLength == 0 || lineOutOfRange(line)) {
+                throw new IllegalArgumentException("line out of bounds");
+            }
+            return nlOffsets[line - 1];
+        }
+
+        /**
+         * Gets the number of characters in a line, identified by 1-based line number;
+         * <em>does not</em> include the final newline, if any.
+         *
+         * @throws IllegalArgumentException if there is no such line in the text.
+         */
+        public int lineLength(int line) throws IllegalArgumentException {
+            if (textLength == 0 || lineOutOfRange(line)) {
+                throw new IllegalArgumentException("line out of bounds");
+            }
+            if (line == nlOffsets.length - 1 && !finalNL) {
+                return textLength - nlOffsets[line - 1];
+            }
+            return (nlOffsets[line] - nlOffsets[line - 1]) - 1;
+
+        }
+
+        /**
+         * Is the line number out of range.
+         */
+        private boolean lineOutOfRange(int line) {
+            return line <= 0 || line >= nlOffsets.length || (line == nlOffsets.length - 1 && finalNL);
+        }
+
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceFactory.java	Mon Jun 30 08:50:26 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,546 +0,0 @@
-/*
- * Copyright (c) 2013, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.truffle.api.source;
-
-import java.io.*;
-import java.lang.ref.*;
-import java.util.*;
-
-import com.oracle.truffle.api.*;
-
-/**
- * Provider for canonical representations of source code. Three kinds of sources are supported.
- * <ul>
- * <li><strong>File:</strong> Each file is represented as a canonical object, indexed by the
- * absolute, canonical path name of the file. File contents are <em>read lazily</em> and contents
- * optionally <em>cached</em>.</li>
- * <li><strong>Literal Source:</strong> A named text string, whose contents are supplied concretely
- * (possibly via an {@link Reader}), can also be used as a source. These are not indexed and should
- * be considered value objects; equality is defined based on contents.</li>
- * <li><strong>Fake Files:</strong> A named text string used for testing; its contents can be
- * retrieved by name, unlike literal sources.</li>
- * </ul>
- * <p>
- * <strong>File cache:</strong>
- * <ol>
- * <li>File content caching is optional, <em>off</em> by default.</li>
- * <li>The first access to source file contents will result in the contents being read, and (if
- * enabled) cached.</li>
- * <li>If file contents have been cached, access to contents via {@link Source#getInputStream()} or
- * {@link Source#getReader()} will be provided from the cache.</li>
- * <li>Any access to file contents via the cache will result in a timestamp check and possible cache
- * reload.</li>
- * </ol>
- */
-public final class SourceFactory {
-
-    // Only files and fake files are indexed.
-    private static final Map<String, WeakReference<SourceImpl>> pathToSource = new HashMap<>();
-
-    private static boolean fileCacheEnabled = true;
-
-    private SourceFactory() {
-    }
-
-    /**
-     * Gets the canonical representation of a source file, whose contents will be read lazily and
-     * then cached.
-     *
-     * @param fileName name
-     * @param reset forces any existing {@link Source} cache to be cleared, forcing a re-read
-     * @return canonical representation of the file's contents.
-     * @throws RuntimeException if the file can not be read
-     */
-    public static Source fromFile(String fileName, boolean reset) throws RuntimeException {
-
-        // TODO (mlvdv) throw IOException
-
-        SourceImpl source = lookup(fileName);
-        if (source == null) {
-            final File file = new File(fileName);
-            String path = null;
-            if (file.exists()) {
-                try {
-                    path = file.getCanonicalPath();
-                } catch (IOException e) {
-                    throw new RuntimeException("Can't find file " + fileName);
-                }
-            }
-            source = lookup(path);
-            if (source == null) {
-                source = new FileSourceImpl(file, fileName, path);
-                store(path, source);
-            }
-        }
-        if (reset) {
-            source.reset();
-        }
-        return source;
-    }
-
-    /**
-     * Gets the canonical representation of a source file, whose contents will be read lazily and
-     * then cached.
-     *
-     * @param fileName name
-     * @return canonical representation of the file's contents.
-     * @throws RuntimeException if the file can not be read
-     */
-    public static Source fromFile(String fileName) throws RuntimeException {
-        return fromFile(fileName, false);
-    }
-
-    /**
-     * Creates a non-canonical source from literal text.
-     *
-     * @param code textual source code
-     * @param description a note about the origin, for error messages and debugging
-     * @return a newly created, non-indexed source representation
-     */
-    public static Source fromText(String code, String description) {
-        assert code != null;
-        return new LiteralSourceImpl(description, code);
-    }
-
-    /**
-     * Creates a source whose contents will be read immediately and cached.
-     *
-     * @param reader
-     * @param description a note about the origin, possibly useful for debugging
-     * @return a newly created, non-indexed source representation
-     * @throws IOException if reading fails
-     */
-    public static Source fromReader(Reader reader, String description) throws IOException {
-        return new LiteralSourceImpl(description, read(reader));
-    }
-
-    /**
-     * Creates a source from literal text, but which acts as a file and can be retrieved by name
-     * (unlike other literal sources); intended for testing.
-     *
-     * @param code textual source code
-     * @param fakeFileName string to use for indexing/lookup
-     * @return a newly created, source representation, canonical with respect to its name
-     */
-    public static Source asFakeFile(String code, String fakeFileName) {
-        final SourceImpl source = new LiteralSourceImpl(fakeFileName, code);
-        store(fakeFileName, source);
-        return source;
-    }
-
-    /**
-     * Enables/disables caching of file contents, <em>disabled</em> by default. Caching of sources
-     * created from literal text or readers is always enabled.
-     */
-    public static void setFileCaching(boolean enabled) {
-        fileCacheEnabled = enabled;
-    }
-
-    private static SourceImpl lookup(String key) {
-        WeakReference<SourceImpl> sourceRef = pathToSource.get(key);
-        return sourceRef == null ? null : sourceRef.get();
-    }
-
-    private static void store(String key, SourceImpl source) {
-        pathToSource.put(key, new WeakReference<>(source));
-    }
-
-    private static String read(Reader reader) throws IOException {
-        final StringBuilder builder = new StringBuilder();
-        final char[] buffer = new char[1024];
-
-        while (true) {
-            final int n = reader.read(buffer);
-            if (n == -1) {
-                break;
-            }
-            builder.append(buffer, 0, n);
-        }
-
-        return builder.toString();
-    }
-
-    private abstract static class SourceImpl implements Source {
-        // TODO (mlvdv) consider canonicalizing and reusing SourceSection instances
-        // TOOD (mlvdv) connect SourceSections into a spatial tree for fast geometric lookup
-
-        protected TextMap textMap = null;
-
-        protected abstract void reset();
-
-        public final InputStream getInputStream() {
-            return new ByteArrayInputStream(getCode().getBytes());
-        }
-
-        /**
-         * Gets the text (not including a possible terminating newline) in a (1-based) numbered
-         * line.
-         */
-        public final String getCode(int lineNumber) {
-            checkTextMap();
-            final int offset = textMap.lineStartOffset(lineNumber);
-            final int length = textMap.lineLength(lineNumber);
-            return getCode().substring(offset, offset + length);
-        }
-
-        /**
-         * The number of text lines in the source.
-         */
-        public final int getLineCount() {
-            return checkTextMap().lineCount();
-        }
-
-        /**
-         * The 1-based number of the line that includes a 0-based character offset.
-         */
-        public final int getLineNumber(int offset) {
-            return checkTextMap().offsetToLine(offset);
-        }
-
-        /**
-         * The 0-based character offset at the start of a (1-based) numbered line.
-         */
-        public final int getLineStartOffset(int lineNumber) {
-            return checkTextMap().lineStartOffset(lineNumber);
-        }
-
-        /**
-         * The number of characters (not counting a possible terminating newline) in a (1-based)
-         * numbered line.
-         */
-        public final int getLineLength(int lineNumber) {
-            return checkTextMap().lineLength(lineNumber);
-        }
-
-        public final SourceSection createSection(String identifier, int startOffset, int sectionLength) throws IllegalArgumentException {
-            final int codeLength = getCode().length();
-            if (!(startOffset >= 0 && sectionLength >= 0 && startOffset + sectionLength <= codeLength)) {
-                throw new IllegalArgumentException("text positions out of range");
-            }
-            checkTextMap();
-            final int startLine = getLineNumber(startOffset);
-            final int startColumn = startOffset - getLineStartOffset(startLine) + 1;
-
-            return new SourceSectionImpl(this, identifier, startLine, startColumn, startOffset, sectionLength);
-        }
-
-        public SourceSection createSection(String identifier, int startLine, int startColumn, int sectionLength) {
-            checkTextMap();
-            final int lineStartOffset = textMap.lineStartOffset(startLine);
-            if (startColumn > textMap.lineLength(startLine)) {
-                throw new IllegalArgumentException("column out of range");
-            }
-            final int startOffset = lineStartOffset + startColumn - 1;
-            return new SourceSectionImpl(this, identifier, startLine, startColumn, startOffset, sectionLength);
-        }
-
-        public SourceSection createSection(String identifier, int startLine, int startColumn, int charIndex, int length) {
-            return new SourceSectionImpl(this, identifier, startLine, startColumn, charIndex, length);
-        }
-
-        private TextMap checkTextMap() {
-            if (textMap == null) {
-                final String code = getCode();
-                if (code == null) {
-                    throw new RuntimeException("can't read file " + getName());
-                }
-                textMap = new TextMap(code);
-            }
-            return textMap;
-        }
-    }
-
-    private static class LiteralSourceImpl extends SourceImpl {
-
-        private final String name; // Name used originally to describe the source
-        private final String code;
-
-        public LiteralSourceImpl(String name, String code) {
-            this.name = name;
-            this.code = code;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public String getShortName() {
-            return name;
-        }
-
-        @Override
-        public String getCode() {
-            return code;
-        }
-
-        @Override
-        public String getPath() {
-            return name;
-        }
-
-        @Override
-        public Reader getReader() {
-            return new StringReader(code);
-        }
-
-        @Override
-        protected void reset() {
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + name.hashCode();
-            result = prime * result + (code == null ? 0 : code.hashCode());
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj == null) {
-                return false;
-            }
-            if (!(obj instanceof LiteralSourceImpl)) {
-                return false;
-            }
-            LiteralSourceImpl other = (LiteralSourceImpl) obj;
-            return name.equals(other.name) && code.equals(other.code);
-        }
-
-    }
-
-    private static class FileSourceImpl extends SourceImpl {
-
-        private final File file;
-        private final String name; // Name used originally to describe the source
-        private final String path;  // Normalized path description of an actual file
-
-        private String code = null;  // A cache of the file's contents
-        private long timeStamp;      // timestamp of the cache in the file system
-
-        public FileSourceImpl(File file, String name, String path) {
-            this.file = file;
-            this.name = name;
-            this.path = path;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public String getShortName() {
-            return file.getName();
-        }
-
-        @Override
-        public String getCode() {
-            if (fileCacheEnabled) {
-                if (code == null || timeStamp != file.lastModified()) {
-                    try {
-                        code = read(getReader());
-                        timeStamp = file.lastModified();
-                    } catch (IOException e) {
-                    }
-                }
-                return code;
-            }
-            try {
-                return read(new FileReader(file));
-            } catch (IOException e) {
-            }
-            return null;
-        }
-
-        @Override
-        public String getPath() {
-            return path;
-        }
-
-        @Override
-        public Reader getReader() {
-            if (code != null && timeStamp == file.lastModified()) {
-                return new StringReader(code);
-            }
-            try {
-                return new FileReader(file);
-            } catch (FileNotFoundException e) {
-                throw new RuntimeException("Can't find file " + path);
-            }
-        }
-
-        @Override
-        protected void reset() {
-            this.code = null;
-        }
-
-    }
-
-    private static class SourceSectionImpl implements SourceSection {
-
-        private final Source source;
-        private final String identifier;
-        private final int startLine;
-        private final int startColumn;
-        private final int charIndex;
-        private final int charLength;
-
-        /**
-         * Creates a new object representing a contiguous text section within the source code of a
-         * guest language program's text.
-         * <p>
-         * The starting location of the section is specified using two different coordinate:
-         * <ul>
-         * <li><b>(row, column)</b>: rows and columns are 1-based, so the first character in a
-         * source file is at position {@code (1,1)}.</li>
-         * <li><b>character index</b>: 0-based offset of the character from the beginning of the
-         * source, so the first character in a file is at index {@code 0}.</li>
-         * </ul>
-         * The <b>newline</b> that terminates each line counts as a single character for the purpose
-         * of a character index. The (row,column) coordinates of a newline character should never
-         * appear in a text section.
-         * <p>
-         *
-         * @param source object representing the complete source program that contains this section
-         * @param identifier an identifier used when printing the section
-         * @param startLine the 1-based number of the start line of the section
-         * @param startColumn the 1-based number of the start column of the section
-         * @param charIndex the 0-based index of the first character of the section
-         * @param charLength the length of the section in number of characters
-         */
-        public SourceSectionImpl(Source source, String identifier, int startLine, int startColumn, int charIndex, int charLength) {
-            this.source = source;
-            this.identifier = identifier;
-            this.startLine = startLine;
-            this.startColumn = startColumn;
-            this.charIndex = charIndex;
-            this.charLength = charLength;
-        }
-
-        public final Source getSource() {
-            return source;
-        }
-
-        public final int getStartLine() {
-            return startLine;
-        }
-
-        public final int getStartColumn() {
-            return startColumn;
-        }
-
-        public final int getCharIndex() {
-            return charIndex;
-        }
-
-        public final int getCharLength() {
-            return charLength;
-        }
-
-        public final int getCharEndIndex() {
-            return charIndex + charLength;
-        }
-
-        public final String getIdentifier() {
-            return identifier;
-        }
-
-        public final String getCode() {
-            return getSource().getCode().substring(charIndex, charIndex + charLength);
-        }
-
-        public final String getShortDescription() {
-            return String.format("%s:%d", source.getShortName(), startLine);
-        }
-
-        @Override
-        public String toString() {
-            return String.format("%s:%d", source.getName(), startLine);
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + charIndex;
-            result = prime * result + charLength;
-            result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
-            result = prime * result + ((source == null) ? 0 : source.hashCode());
-            result = prime * result + startColumn;
-            result = prime * result + startLine;
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj == null) {
-                return false;
-            }
-            if (!(obj instanceof SourceSectionImpl)) {
-                return false;
-            }
-            SourceSectionImpl other = (SourceSectionImpl) obj;
-            if (charIndex != other.charIndex) {
-                return false;
-            }
-            if (charLength != other.charLength) {
-                return false;
-            }
-            if (identifier == null) {
-                if (other.identifier != null) {
-                    return false;
-                }
-            } else if (!identifier.equals(other.identifier)) {
-                return false;
-            }
-            if (source == null) {
-                if (other.source != null) {
-                    return false;
-                }
-            } else if (!source.equals(other.source)) {
-                return false;
-            }
-            if (startColumn != other.startColumn) {
-                return false;
-            }
-            if (startLine != other.startLine) {
-                return false;
-            }
-            return true;
-        }
-
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceLineLocation.java	Mon Jun 30 08:50:26 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2013, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.truffle.api.source;
-
-import com.oracle.truffle.api.*;
-
-/**
- * A specification for a location in guest language source, expressed as a line number in a specific
- * instance of {@link Source}, suitable for hash table keys with equality defined in terms of
- * content.
- */
-public class SourceLineLocation implements Comparable<Object> {
-
-    private final Source source;
-    private final int line;
-
-    public SourceLineLocation(Source source, int line) {
-        assert source != null;
-        this.source = source;
-        this.line = line;
-    }
-
-    public SourceLineLocation(SourceSection sourceSection) {
-        this(sourceSection.getSource(), sourceSection.getStartLine());
-    }
-
-    public Source getSource() {
-        return source;
-    }
-
-    public int getLine() {
-        return line;
-    }
-
-    @Override
-    public String toString() {
-        return "SourceLine [" + source.getName() + ", " + line + "]";
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + line;
-        result = prime * result + source.hashCode();
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (!(obj instanceof SourceLineLocation)) {
-            return false;
-        }
-        SourceLineLocation other = (SourceLineLocation) obj;
-        if (line != other.line) {
-            return false;
-        }
-        return source.equals(other.source);
-    }
-
-    @Override
-    public int compareTo(Object o) {
-        final SourceLineLocation other = (SourceLineLocation) o;
-        final int nameOrder = source.getName().compareTo(other.source.getName());
-        if (nameOrder != 0) {
-            return nameOrder;
-        }
-        return Integer.compare(line, other.line);
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceSection.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.truffle.api.source;
+
+/**
+ * Description of contiguous section of text within a {@link Source} of program code; supports
+ * multiple modes of access to the text and its location. A special {@linkplain NullSourceSection
+ * null subtype} should be used for code that is not available from source, e.g language builtins.
+ *
+ * @see Source#createSection(String, int, int, int, int)
+ * @see Source#createSection(String, int, int, int)
+ * @see Source#createSection(String, int, int)
+ * @see Source#createSection(String, int)
+ * @see NullSourceSection
+ */
+public interface SourceSection {
+
+    // TODO support alternate text representations/encodings
+
+    /**
+     * Representation of the source program that contains this section.
+     *
+     * @return the source object
+     */
+    Source getSource();
+
+    /**
+     * Returns 1-based line number of the first character in this section (inclusive).
+     *
+     * @return the starting line number
+     */
+    int getStartLine();
+
+    /**
+     * Gets a representation of the first line of the section, suitable for a hash key.
+     */
+    LineLocation getLineLocation();
+
+    /**
+     * Returns the 1-based column number of the first character in this section (inclusive).
+     *
+     * @return the starting column number
+     */
+    int getStartColumn();
+
+    /**
+     * Returns the 0-based index of the first character in this section.
+     *
+     * @return the starting character index
+     */
+    int getCharIndex();
+
+    /**
+     * Returns the length of this section in characters.
+     *
+     * @return the number of characters in the section
+     */
+    int getCharLength();
+
+    /**
+     * Returns the index of the text position immediately following the last character in the
+     * section.
+     *
+     * @return the end position of the section
+     */
+    int getCharEndIndex();
+
+    /**
+     * Returns terse text describing this source section, typically used for printing the section.
+     *
+     * @return the identifier of the section
+     */
+    String getIdentifier();
+
+    /**
+     * Returns text described by this section.
+     *
+     * @return the code as a String object
+     */
+    String getCode();
+
+    /**
+     * Returns a short description of the source section, using just the file name, rather than its
+     * full path.
+     *
+     * @return a short description of the source section
+     */
+    String getShortDescription();
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/TextMap.java	Mon Jun 30 08:50:26 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2013, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.truffle.api.source;
-
-import java.util.*;
-
-/**
- * A utility for converting between coordinate systems in a string of text interspersed with newline
- * characters. The coordinate systems are:
- * <ul>
- * <li>0-based character offset from the beginning of the text, where newline characters count as a
- * single character and the first character in the text occupies position 0.</li>
- * <li>1-based position in the 2D space of lines and columns, in which the first position in the
- * text is at (1,1).</li>
- * </ul>
- * <p>
- * This utility is based on positions occupied by characters, not text stream positions as in a text
- * editor. The distinction shows up in editors where you can put the cursor just past the last
- * character in a buffer; this is necessary, among other reasons, so that you can put the edit
- * cursor in a new (empty) buffer. For the purposes of this utility, however, there are no character
- * positions in an empty text string and there are no lines in an empty text string.
- * <p>
- * A newline character designates the end of a line and occupies a column position.
- * <p>
- * If the text ends with a character other than a newline, then the characters following the final
- * newline character count as a line, even though not newline-terminated.
- * <p>
- * <strong>Limitations:</strong>
- * <ul>
- * <li>Does not handle multiple character encodings correctly.</li>
- * <li>Treats tabs as occupying 1 column.</li>
- * <li>Does not handle multiple-character line termination sequences correctly.</li>
- * </ul>
- */
-public final class TextMap {
-
-    // 0-based offsets of newline characters in the text, with sentinel
-    private final int[] nlOffsets;
-
-    // The number of characters in the text, including newlines (which count as 1).
-    private final int textLength;
-
-    // Is the final text character a newline?
-    final boolean finalNL;
-
-    /**
-     * Constructs map permitting translation between 0-based character offsets and 1-based
-     * lines/columns.
-     */
-    public TextMap(String text) {
-        this.textLength = text.length();
-        final ArrayList<Integer> lines = new ArrayList<>();
-        lines.add(0);
-        int offset = 0;
-
-        while (offset < text.length()) {
-            final int nlIndex = text.indexOf('\n', offset);
-            if (nlIndex >= 0) {
-                offset = nlIndex + 1;
-                lines.add(offset);
-            } else {
-                break;
-            }
-        }
-        lines.add(Integer.MAX_VALUE);
-
-        nlOffsets = new int[lines.size()];
-        for (int line = 0; line < lines.size(); line++) {
-            nlOffsets[line] = lines.get(line);
-        }
-
-        finalNL = textLength > 0 && (textLength == nlOffsets[nlOffsets.length - 2]);
-    }
-
-    /**
-     * Converts 0-based character offset to 1-based number of the line containing the character.
-     * 
-     * @throws IllegalArgumentException if the offset is outside the string.
-     */
-    public int offsetToLine(int offset) throws IllegalArgumentException {
-        if (offset < 0 || offset >= textLength) {
-            throw new IllegalArgumentException("offset out of bounds");
-        }
-        int line = 1;
-        while (offset >= nlOffsets[line]) {
-            line++;
-        }
-        return line;
-    }
-
-    /**
-     * Converts 0-based character offset to 1-based number of the column occupied by the character.
-     * <p>
-     * Tabs are not expanded; they occupy 1 column.
-     * 
-     * @throws IllegalArgumentException if the offset is outside the string.
-     */
-    public int offsetToCol(int offset) throws IllegalArgumentException {
-        return 1 + offset - nlOffsets[offsetToLine(offset) - 1];
-    }
-
-    /**
-     * The number of lines in the text; if characters appear after the final newline, then they also
-     * count as a line, even though not newline-terminated.
-     */
-    public int lineCount() {
-        if (textLength == 0) {
-            return 0;
-        }
-        return finalNL ? nlOffsets.length - 2 : nlOffsets.length - 1;
-    }
-
-    /**
-     * Converts 1-based line number to the 0-based offset of the line's first character; this would
-     * be the offset of a newline if the line is empty.
-     * 
-     * @throws IllegalArgumentException if there is no such line in the text.
-     */
-    public int lineStartOffset(int line) throws IllegalArgumentException {
-        if (textLength == 0 || lineOutOfRange(line)) {
-            throw new IllegalArgumentException("line out of bounds");
-        }
-        return nlOffsets[line - 1];
-    }
-
-    /**
-     * Gets the number of characters in a line, identified by 1-based line number; <em>does not</em>
-     * include the final newline, if any.
-     * 
-     * @throws IllegalArgumentException if there is no such line in the text.
-     */
-    public int lineLength(int line) throws IllegalArgumentException {
-        if (textLength == 0 || lineOutOfRange(line)) {
-            throw new IllegalArgumentException("line out of bounds");
-        }
-        if (line == nlOffsets.length - 1 && !finalNL) {
-            return textLength - nlOffsets[line - 1];
-        }
-        return (nlOffsets[line] - nlOffsets[line - 1]) - 1;
-
-    }
-
-    /**
-     * Is the line number out of range.
-     */
-    private boolean lineOutOfRange(int line) {
-        return line <= 0 || line >= nlOffsets.length || (line == nlOffsets.length - 1 && finalNL);
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/JSONHelper.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2013, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.truffle.api.utilities;
+
+import java.util.*;
+
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
+
+/**
+ * Helper function that allows to dump the AST during creation to a JSON format.
+ */
+public class JSONHelper {
+
+    private static StringBuilder AstJsonDumpBuilder = new StringBuilder();
+
+    public static void dumpNewChild(Node parentNode, Node childNode) {
+        if (AstJsonDumpBuilder != null) {
+            AstJsonDumpBuilder.append("{ \"action\": \"insertNode\", \"parentId\": \"" + getID(parentNode) + "\", \"newId\": \"" + getID(childNode) + "\" },\n");
+        }
+    }
+
+    public static void dumpReplaceChild(Node oldNode, Node newNode, CharSequence reason) {
+        if (AstJsonDumpBuilder != null) {
+            AstJsonDumpBuilder.append("{ \"action\": \"replaceNode\", \"oldId\": \"" + getID(oldNode) + "\", \"newId\": \"" + getID(newNode) + "\", \"reason\": " + quote(reason) + " },\n");
+        }
+    }
+
+    public static void dumpNewNode(Node newNode) {
+        if (AstJsonDumpBuilder != null) {
+            AstJsonDumpBuilder.append("{ \"action\": \"createNode\", \"newId\": \"" + getID(newNode) + "\", \"type\": \"" + getType(newNode) + "\", \"description\": \"" + newNode.getDescription() +
+                            "\", \"language\": \"" + newNode.getLanguage() + "\"" + getSourceSectionInfo(newNode) + " },\n");
+        }
+    }
+
+    private static String getSourceSectionInfo(Node newNode) {
+        SourceSection sourceSection = newNode.getSourceSection();
+        if (sourceSection != null) {
+            return ", \"identifier\": \"" + sourceSection.getIdentifier() + "\" ";
+        } else {
+            return "";
+        }
+    }
+
+    public static String getResult() {
+        return AstJsonDumpBuilder.toString();
+    }
+
+    private static String getID(Node newChild) {
+        return String.valueOf(newChild.hashCode());
+    }
+
+    private static String getType(Node node) {
+        return node.getClass().getSimpleName();
+    }
+
+    private static String quote(CharSequence value) {
+        StringBuilder builder = new StringBuilder(value.length() + 2);
+        builder.append('"');
+        for (int i = 0; i < value.length(); i++) {
+            char c = value.charAt(i);
+            switch (c) {
+                case '"':
+                    builder.append("\\\"");
+                    break;
+                case '\\':
+                    builder.append("\\\\");
+                    break;
+                case '\b':
+                    builder.append("\\b");
+                    break;
+                case '\f':
+                    builder.append("\\f");
+                    break;
+                case '\n':
+                    builder.append("\\n");
+                    break;
+                case '\r':
+                    builder.append("\\r");
+                    break;
+                case '\t':
+                    builder.append("\\t");
+                    break;
+                default: {
+                    if (c < ' ') {
+                        builder.append("\\u00");
+                        builder.append(Character.forDigit((c >> 4) & 0xF, 16));
+                        builder.append(Character.forDigit(c & 0xF, 16));
+                    } else {
+                        builder.append(c);
+                    }
+                }
+            }
+        }
+        builder.append('"');
+        return builder.toString();
+    }
+
+    public static void restart() {
+        AstJsonDumpBuilder = new StringBuilder();
+    }
+
+    public static JsonObjectBuilder object() {
+        return new JsonObjectBuilder();
+    }
+
+    public static JsonArrayBuilder array() {
+        return new JsonArrayBuilder();
+    }
+
+    public static abstract class JsonStringBuilder {
+        @Override
+        public final String toString() {
+            StringBuilder sb = new StringBuilder();
+            appendTo(sb);
+            return sb.toString();
+        }
+
+        protected abstract void appendTo(StringBuilder sb);
+
+        protected static void appendValue(StringBuilder sb, Object value) {
+            if (value instanceof JsonStringBuilder) {
+                ((JsonStringBuilder) value).appendTo(sb);
+            } else if (value instanceof Integer || value instanceof Boolean || value == null) {
+                sb.append(value);
+            } else {
+                sb.append(quote(String.valueOf(value)));
+            }
+        }
+    }
+
+    public static final class JsonObjectBuilder extends JsonStringBuilder {
+        private final Map<String, Object> contents = new LinkedHashMap<>();
+
+        private JsonObjectBuilder() {
+        }
+
+        public JsonObjectBuilder add(String key, String value) {
+            contents.put(key, value);
+            return this;
+        }
+
+        public JsonObjectBuilder add(String key, Number value) {
+            contents.put(key, value);
+            return this;
+        }
+
+        public JsonObjectBuilder add(String key, Boolean value) {
+            contents.put(key, value);
+            return this;
+        }
+
+        public JsonObjectBuilder add(String key, JsonStringBuilder value) {
+            contents.put(key, value);
+            return this;
+        }
+
+        @Override
+        protected void appendTo(StringBuilder sb) {
+            sb.append("{");
+            boolean comma = false;
+            for (Map.Entry<String, Object> entry : contents.entrySet()) {
+                if (comma) {
+                    sb.append(", ");
+                }
+                sb.append(quote(entry.getKey()));
+                sb.append(": ");
+                appendValue(sb, entry.getValue());
+                comma = true;
+            }
+            sb.append("}");
+        }
+    }
+
+    public static final class JsonArrayBuilder extends JsonStringBuilder {
+        private final List<Object> contents = new ArrayList<>();
+
+        private JsonArrayBuilder() {
+        }
+
+        public JsonArrayBuilder add(String value) {
+            contents.add(value);
+            return this;
+        }
+
+        public JsonArrayBuilder add(Number value) {
+            contents.add(value);
+            return this;
+        }
+
+        public JsonArrayBuilder add(Boolean value) {
+            contents.add(value);
+            return this;
+        }
+
+        public JsonArrayBuilder add(JsonStringBuilder value) {
+            contents.add(value);
+            return this;
+        }
+
+        @Override
+        protected void appendTo(StringBuilder sb) {
+            sb.append("[");
+            boolean comma = false;
+            for (Object value : contents) {
+                if (comma) {
+                    sb.append(", ");
+                }
+                appendValue(sb, value);
+                comma = true;
+            }
+            sb.append("]");
+        }
+    }
+}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Mon Jun 30 12:02:19 2014 +0200
@@ -36,6 +36,7 @@
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.nodes.Node.Child;
 import com.oracle.truffle.api.nodes.Node.Children;
+import com.oracle.truffle.api.source.*;
 
 /**
  * THIS IS NOT PUBLIC API.
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java	Mon Jun 30 12:02:19 2014 +0200
@@ -36,7 +36,6 @@
 import org.junit.runners.*;
 import org.junit.runners.model.*;
 
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.runtime.*;
@@ -156,7 +155,7 @@
         PrintStream printer = new PrintStream(out);
         try {
             SLContext context = new SLContext(new BufferedReader(new StringReader(repeat(testCase.testInput, REPEATS))), printer);
-            final Source source = SourceFactory.fromText(readAllLines(testCase.path), testCase.sourceName);
+            final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName);
             SLMain.run(context, source, null, REPEATS);
 
             String actualOutput = new String(out.toByteArray());
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Mon Jun 30 12:02:19 2014 +0200
@@ -123,9 +123,9 @@
 
         Source source;
         if (args.length == 0) {
-            source = SourceFactory.fromReader(new InputStreamReader(System.in), "stdin");
+            source = Source.fromReader(new InputStreamReader(System.in), "stdin");
         } else {
-            source = SourceFactory.fromFile(args[0]);
+            source = Source.fromFileName(args[0]);
         }
 
         int repeats = 1;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Mon Jun 30 12:02:19 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.truffle.sl.builtins;
 
 import com.oracle.truffle.api.CompilerDirectives.SlowPath;
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
@@ -45,7 +44,7 @@
 
     @SlowPath
     private static void doDefineFunction(SLContext context, String code) {
-        Source source = SourceFactory.fromText(code, "[defineFunction]");
+        Source source = Source.fromText(code, "[defineFunction]");
         /* The same parsing code as for parsing the initial source. */
         Parser.parseSL(context, source);
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -41,10 +41,6 @@
     @Children private final SLStatementNode[] bodyNodes;
 
     public SLBlockNode(SLStatementNode[] bodyNodes) {
-        /*
-         * It is a Truffle requirement to call adoptChildren(), which performs all the necessary
-         * steps to add the new children to the node tree.
-         */
         this.bodyNodes = bodyNodes;
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -50,10 +50,6 @@
     private final BranchProfile nullTaken = new BranchProfile();
 
     public SLFunctionBodyNode(SLStatementNode bodyNode) {
-        /*
-         * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps
-         * to add the new child to the node tree.
-         */
         this.bodyNode = bodyNode;
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -53,10 +53,6 @@
     private final BranchProfile elseTaken = new BranchProfile();
 
     public SLIfNode(SLExpressionNode conditionNode, SLStatementNode thenPartNode, SLStatementNode elsePartNode) {
-        /*
-         * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps
-         * to add the new child to the node tree.
-         */
         this.conditionNode = conditionNode;
         this.thenPartNode = thenPartNode;
         this.elsePartNode = elsePartNode;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java	Mon Jun 30 12:02:19 2014 +0200
@@ -51,10 +51,6 @@
     private final BranchProfile breakTaken = new BranchProfile();
 
     public SLWhileNode(SLExpressionNode conditionNode, SLStatementNode bodyNode) {
-        /*
-         * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps
-         * to add the new child to the node tree.
-         */
         this.conditionNode = conditionNode;
         this.bodyNode = bodyNode;
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Mon Jun 30 12:02:19 2014 +0200
@@ -30,7 +30,7 @@
 
 import java.util.*;
 
-import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Mon Jun 30 12:02:19 2014 +0200
@@ -27,7 +27,7 @@
 
 import java.util.*;
 
-import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
@@ -52,7 +52,7 @@
     public final Scanner scanner;
     public final Errors errors;
     private final SLNodeFactory factory;
-    
+
     public Parser(SLContext context, Source source) {
         this.scanner = new Scanner(source.getInputStream());
         this.factory = new SLNodeFactory(context, source);
@@ -133,39 +133,39 @@
 	void Function() {
 		Expect(4);
 		Expect(1);
-		factory.startFunction(t); 
+		factory.startFunction(t);
 		Expect(5);
 		if (la.kind == 1) {
 			Get();
-			factory.addFormalParameter(t); 
+			factory.addFormalParameter(t);
 			while (la.kind == 6) {
 				Get();
 				Expect(1);
-				factory.addFormalParameter(t); 
+				factory.addFormalParameter(t);
 			}
 		}
 		Expect(7);
 		SLStatementNode body = Block(false);
-		factory.finishFunction(body); 
+		factory.finishFunction(body);
 	}
 
 	SLStatementNode  Block(boolean inLoop) {
 		SLStatementNode  result;
 		factory.startBlock();
-		List<SLStatementNode> body = new ArrayList<>(); 
+		List<SLStatementNode> body = new ArrayList<>();
 		Expect(8);
 		while (StartOf(1)) {
 			SLStatementNode s = Statement(inLoop);
-			body.add(s); 
+			body.add(s);
 		}
 		Expect(9);
-		result = factory.finishBlock(body); 
+		result = factory.finishBlock(body);
 		return result;
 	}
 
 	SLStatementNode  Statement(boolean inLoop) {
 		SLStatementNode  result;
-		result = null; 
+		result = null;
 		switch (la.kind) {
 		case 13: {
 			result = WhileStatement();
@@ -173,13 +173,13 @@
 		}
 		case 10: {
 			Get();
-			if (inLoop) { result = factory.createBreak(t); } else { SemErr("break used outside of loop"); } 
+			if (inLoop) { result = factory.createBreak(t); } else { SemErr("break used outside of loop"); }
 			Expect(11);
 			break;
 		}
 		case 12: {
 			Get();
-			if (inLoop) { result = factory.createContinue(t); } else { SemErr("continue used outside of loop"); } 
+			if (inLoop) { result = factory.createContinue(t); } else { SemErr("continue used outside of loop"); }
 			Expect(11);
 			break;
 		}
@@ -205,11 +205,11 @@
 		SLStatementNode  result;
 		Expect(13);
 		Expect(5);
-		Token whileToken = t; 
+		Token whileToken = t;
 		SLExpressionNode condition = Expression();
 		Expect(7);
 		SLStatementNode body = Block(true);
-		result = factory.createWhile(whileToken, condition, body); 
+		result = factory.createWhile(whileToken, condition, body);
 		return result;
 	}
 
@@ -217,16 +217,16 @@
 		SLStatementNode  result;
 		Expect(14);
 		Expect(5);
-		Token ifToken = t; 
+		Token ifToken = t;
 		SLExpressionNode condition = Expression();
 		Expect(7);
 		SLStatementNode thenPart = Block(inLoop);
-		SLStatementNode elsePart = null; 
+		SLStatementNode elsePart = null;
 		if (la.kind == 15) {
 			Get();
 			elsePart = Block(inLoop);
 		}
-		result = factory.createIf(ifToken, condition, thenPart, elsePart); 
+		result = factory.createIf(ifToken, condition, thenPart, elsePart);
 		return result;
 	}
 
@@ -234,11 +234,11 @@
 		SLStatementNode  result;
 		Expect(16);
 		Token returnToken = t;
-		SLExpressionNode value = null; 
+		SLExpressionNode value = null;
 		if (StartOf(2)) {
 			value = Expression();
 		}
-		result = factory.createReturn(returnToken, value); 
+		result = factory.createReturn(returnToken, value);
 		Expect(11);
 		return result;
 	}
@@ -248,9 +248,9 @@
 		result = LogicTerm();
 		while (la.kind == 17) {
 			Get();
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = LogicTerm();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -260,9 +260,9 @@
 		result = LogicFactor();
 		while (la.kind == 18) {
 			Get();
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = LogicFactor();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -297,9 +297,9 @@
 				break;
 			}
 			}
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = Arithmetic();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -313,9 +313,9 @@
 			} else {
 				Get();
 			}
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = Term();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -329,47 +329,47 @@
 			} else {
 				Get();
 			}
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = Factor();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
 
 	SLExpressionNode  Factor() {
 		SLExpressionNode  result;
-		result = null; 
+		result = null;
 		if (la.kind == 1) {
 			Get();
-			Token nameToken = t; 
+			Token nameToken = t;
 			if (la.kind == 5) {
 				Get();
 				List<SLExpressionNode> parameters = new ArrayList<>();
-				SLExpressionNode parameter; 
+				SLExpressionNode parameter;
 				if (StartOf(2)) {
 					parameter = Expression();
-					parameters.add(parameter); 
+					parameters.add(parameter);
 					while (la.kind == 6) {
 						Get();
 						parameter = Expression();
-						parameters.add(parameter); 
+						parameters.add(parameter);
 					}
 				}
-				result = factory.createCall(nameToken, parameters); 
+				result = factory.createCall(nameToken, parameters);
 				Expect(7);
 			} else if (la.kind == 29) {
 				Get();
 				SLExpressionNode value = Expression();
-				result = factory.createAssignment(nameToken, value); 
+				result = factory.createAssignment(nameToken, value);
 			} else if (StartOf(4)) {
-				result = factory.createRead(nameToken); 
+				result = factory.createRead(nameToken);
 			} else SynErr(32);
 		} else if (la.kind == 2) {
 			Get();
-			result = factory.createStringLiteral(t); 
+			result = factory.createStringLiteral(t);
 		} else if (la.kind == 3) {
 			Get();
-			result = factory.createNumericLiteral(t); 
+			result = factory.createNumericLiteral(t);
 		} else if (la.kind == 5) {
 			Get();
 			result = Expression();
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Mon Jun 30 12:02:19 2014 +0200
@@ -25,9 +25,9 @@
 import java.math.*;
 import java.util.*;
 
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.nodes.call.*;
 import com.oracle.truffle.sl.nodes.controlflow.*;
--- a/make/Makefile	Mon Jun 30 08:50:26 2014 +0200
+++ b/make/Makefile	Mon Jun 30 12:02:19 2014 +0200
@@ -193,7 +193,7 @@
 
 $(GRAAL_VM_TARGETS):
 	$(CD) $(GAMMADIR)/make; \
-	$(MAKE) BUILD_DIR=$(GRAAL_DIR) BUILD_FLAVOR=$(@:%graal=%) VM_TARGET=$@ generic_buildgraal $(ALT_OUT)
+	$(MAKE) BUILD_DIR=$(GRAAL_DIR) BUILD_FLAVOR=$(@:%graal=%) VM_TARGET=$@ INCLUDE_GRAAL=true generic_buildgraal $(ALT_OUT)
 
 # Install hotspot script in build directory
 HOTSPOT_SCRIPT=$(BUILD_DIR)/$(BUILD_FLAVOR)/hotspot
--- a/mx/mx_graal.py	Mon Jun 30 08:50:26 2014 +0200
+++ b/mx/mx_graal.py	Mon Jun 30 12:02:19 2014 +0200
@@ -168,7 +168,6 @@
         rmIfExists(join(_graal_home, 'build'))
         rmIfExists(join(_graal_home, 'build-nograal'))
         rmIfExists(_jdksDir())
-        rmIfExists(mx.distribution('GRAAL').path)
 
 def export(args):
     """create archives of builds split by vmbuild and vm"""
@@ -506,14 +505,23 @@
             jreLibDir = join(jdks, e, 'jre', 'lib')
             if exists(jreLibDir):
                 def install(srcJar, dstDir):
-                    # do a copy and then a move to get atomic updating (on Unix)
                     name = os.path.basename(srcJar)
-                    fd, tmp = tempfile.mkstemp(suffix='', prefix=name, dir=dstDir)
-                    shutil.copyfile(srcJar, tmp)
-                    os.close(fd)
                     dstJar = join(dstDir, name)
-                    shutil.move(tmp, dstJar)
-                    os.chmod(dstJar, JDK_UNIX_PERMISSIONS)
+                    if mx.get_env('SYMLINK_GRAAL_JAR', None) == 'true':
+                        # Using symlinks is much faster than copying but may
+                        # cause issues if graal.jar is being updated while
+                        # the VM is running.
+                        if not os.path.islink(dstJar) or not os.path.realpath(dstJar) == srcJar:
+                            if exists(dstJar):
+                                os.remove(dstJar)
+                            os.symlink(srcJar, dstJar)
+                    else:
+                        # do a copy and then a move to get atomic updating (on Unix)
+                        fd, tmp = tempfile.mkstemp(suffix='', prefix=name, dir=dstDir)
+                        shutil.copyfile(srcJar, tmp)
+                        os.close(fd)
+                        shutil.move(tmp, dstJar)
+                        os.chmod(dstJar, JDK_UNIX_PERMISSIONS)
 
                 install(graalJar, jreLibDir)
                 if graalDist.sourcesPath:
@@ -802,13 +810,19 @@
             env.pop('LD_LIBRARY_PATH', None)
             env.pop('CLASSPATH', None)
 
-            if mx._opts.verbose:
-                # Issue an env prefix that can be used to run the make on the command line
-                envPrefix = ' '.join([key + '=' + env[key] for key in env.iterkeys() if not os.environ.has_key(key) or env[key] != os.environ[key]])
-                if len(envPrefix):
-                    mx.log('env ' + envPrefix + ' \\')
+            # Issue an env prefix that can be used to run the make on the command line
+            if not mx._opts.verbose:
+                mx.log('--------------- make command line ----------------------')
+
+            envPrefix = ' '.join([key + '=' + env[key] for key in env.iterkeys() if not os.environ.has_key(key) or env[key] != os.environ[key]])
+            if len(envPrefix):
+                mx.log('env ' + envPrefix + ' \\')
 
             runCmd.append(build + buildSuffix)
+
+            if not mx._opts.verbose:
+                mx.log(' '.join(runCmd))
+                mx.log('--------------------------------------------------------')
             mx.run(runCmd, err=filterXusage, env=env)
 
         jvmCfg = _vmCfgInJdk(jdk)
@@ -1798,7 +1812,7 @@
 
     path = join(_graal_home, 'lib', 'hcfdis-1.jar')
     if not exists(path):
-        mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hcfdis-1.jar'])
+        mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hcfdis-2.jar'])
     mx.run_java(['-jar', path] + args.files)
 
     if args.map is not None:
@@ -1854,6 +1868,20 @@
 def isGraalEnabled(vm):
     return vm != 'original' and not vm.endswith('nograal')
 
+def jol(args):
+    """Java Object Layout"""
+    jolurl = "http://lafo.ssw.uni-linz.ac.at/truffle/jol/jol-internals.jar"
+    joljar = "lib/jol-internals.jar"
+    if not exists(joljar):
+        mx.download(joljar, [jolurl])
+
+    candidates = mx.findclass(args, logToConsole=False, matcher=lambda s, classname: s == classname or classname.endswith('.' + s) or classname.endswith('$' + s))
+    if len(candidates) > 10:
+        print "Found %d candidates. Please be more precise." % (len(candidates))
+        return
+
+    vm(['-javaagent:' + joljar, '-cp', os.pathsep.join([mx.classpath(), joljar]), "org.openjdk.jol.MainObjectInternals"] + candidates)
+
 def site(args):
     """create a website containing javadoc and the project dependency graph"""
 
@@ -2080,7 +2108,8 @@
         'vmfg': [vmfg, '[-options] class [args...]'],
         'deoptalot' : [deoptalot, '[n]'],
         'longtests' : [longtests, ''],
-        'sl' : [sl, '[SL args|@VM options]']
+        'sl' : [sl, '[SL args|@VM options]'],
+        'jol' : [jol, ''],
     }
 
     mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append'])
--- a/mx/projects	Mon Jun 30 08:50:26 2014 +0200
+++ b/mx/projects	Mon Jun 30 12:02:19 2014 +0200
@@ -5,30 +5,30 @@
 jrelibrary@JFR@jar=jfr.jar
 
 library@JUNIT@path=lib/junit-4.11.jar
-library@JUNIT@urls=http://repo1.maven.org/maven2/junit/junit/4.11/junit-4.11.jar
+library@JUNIT@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/junit-4.11.jar,http://repo1.maven.org/maven2/junit/junit/4.11/junit-4.11.jar
 library@JUNIT@sha1=4e031bb61df09069aeb2bffb4019e7a5034a4ee0
 library@JUNIT@eclipse.container=org.eclipse.jdt.junit.JUNIT_CONTAINER/4
 library@JUNIT@sourcePath=lib/junit-4.11-sources.jar
-library@JUNIT@sourceUrls=http://repo1.maven.org/maven2/junit/junit/4.11/junit-4.11-sources.jar
+library@JUNIT@sourceUrls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/junit-4.11-sources.jar,http://repo1.maven.org/maven2/junit/junit/4.11/junit-4.11-sources.jar
 library@JUNIT@sourceSha1=28e0ad201304e4a4abf999ca0570b7cffc352c3c
 library@JUNIT@dependencies=HAMCREST
 
 library@HAMCREST@path=lib/hamcrest-core-1.3.jar
-library@HAMCREST@urls=http://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
+library@HAMCREST@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/hamcrest-core-1.3.jar,http://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
 library@HAMCREST@sha1=42a25dc3219429f0e5d060061f71acb49bf010a0
 library@HAMCREST@sourcePath=lib/hamcrest-core-1.3-sources.jar
-library@HAMCREST@sourceUrls=http://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar
+library@HAMCREST@sourceUrls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/hamcrest-core-1.3-sources.jar,http://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar
 library@HAMCREST@sourceSha1=1dc37250fbc78e23a65a67fbbaf71d2e9cbc3c0b
 
 library@CHECKSTYLE@path=lib/checkstyle-5.5-all.jar
 library@CHECKSTYLE@urls=jar:http://sourceforge.net/projects/checkstyle/files/checkstyle/5.5/checkstyle-5.5-bin.zip/download!/checkstyle-5.5/checkstyle-5.5-all.jar
 
-library@FINDBUGS@path=lib/findbugs-3.0.0-dev-20131204-e3cbbd5.jar
-library@FINDBUGS@urls=jar:http://sourceforge.net/projects/findbugs/files/findbugs/3.0.0/findbugs-3.0.0-dev-20131204-e3cbbd5.zip/download!/findbugs-3.0.0-dev-20131204-e3cbbd5/lib/findbugs.jar
-library@FINDBUGS@sha1=539fdc73ef5f65a85c94687f6ec77dcd8493f8c1
+library@FINDBUGS@path=lib/findbugs-3.0.0-rc1.jar
+library@FINDBUGS@urls=jar:http://lafo.ssw.uni-linz.ac.at/graal-external-deps/findbugs-3.0.0-rc1.zip!/findbugs-3.0.0-rc1/lib/findbugs.jar,jar:http://sourceforge.net/projects/findbugs/files/findbugs/3.0.0/findbugs-3.0.0-rc1.zip/download!/findbugs-3.0.0-rc1/lib/findbugs.jar
+library@FINDBUGS@sha1=3a0a592608b41b57a77721b933b7bb78fcf64015
 
 library@DACAPO@path=lib/dacapo-9.12-bach.jar
-library@DACAPO@urls=http://softlayer.dl.sourceforge.net/project/dacapobench/9.12-bach/dacapo-9.12-bach.jar
+library@DACAPO@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/dacapo-9.12-bach.jar,http://softlayer.dl.sourceforge.net/project/dacapobench/9.12-bach/dacapo-9.12-bach.jar
 library@DACAPO@sha1=2626a9546df09009f6da0df854e6dc1113ef7dd4
 
 library@JACOCOAGENT@path=lib/jacocoagent.jar
@@ -40,29 +40,30 @@
 library@JACOCOREPORT@sha1=a630436391832d697a12c8f7daef8655d7a1efd2
 
 library@DACAPO_SCALA@path=lib/dacapo-scala-0.1.0-20120216.jar
-library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar
+library@DACAPO_SCALA@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/dacapo-scala-0.1.0-20120216.jar,http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar
 library@DACAPO_SCALA@sha1=59b64c974662b5cf9dbd3cf9045d293853dd7a51
 
 library@OKRA@path=lib/okra-1.9.jar
-library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9.jar
+library@OKRA@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.9.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.9.jar
 library@OKRA@sha1=df450b04882e6b5a365299e2cbf1622038ae880e
 library@OKRA@sourcePath=lib/okra-1.9-src.jar
-library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-src.jar
+library@OKRA@sourceUrls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.9-src.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.9-src.jar
 library@OKRA@sourceSha1=41dcda5197ca4d87bc94e4d7b5a90e7f22667756
 
 library@OKRA_WITH_SIM@path=lib/okra-1.9-with-sim.jar
-library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim.jar
+library@OKRA_WITH_SIM@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.9-with-sim.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim.jar
 library@OKRA_WITH_SIM@sha1=816fa24814cf51c02f9c05477447bb55a152b388
 library@OKRA_WITH_SIM@sourcePath=lib/okra-1.9-with-sim-src.jar
 library@OKRA_WITH_SIM@sourceSha1=1628919457999a8479d9f39845865de527dbd523
-library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim-src.jar
+library@OKRA_WITH_SIM@sourceUrls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.9-with-sim-src.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim-src.jar
 
 library@JAVA_ALLOCATION_INSTRUMENTER@path=lib/java-allocation-instrumenter.jar
-library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-c7e3525a6b90.jar
-library@JAVA_ALLOCATION_INSTRUMENTER@sha1=128eb20a4cd3362a4d8b94614e66647808a2e37c
+library@JAVA_ALLOCATION_INSTRUMENTER@sourcePath=lib/java-allocation-instrumenter.jar
+library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-8f0db117e64e.jar
+library@JAVA_ALLOCATION_INSTRUMENTER@sha1=476d9a44cd19d6b55f81571077dfa972a4f8a083
 
 library@VECMATH@path=lib/vecmath-1.3.1.jar
-library@VECMATH@urls=http://mirrors.ibiblio.org/pub/mirrors/maven/java3d/jars/vecmath-1.3.1.jar
+library@VECMATH@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/vecmath-1.3.1.jar,http://mirrors.ibiblio.org/pub/mirrors/maven/java3d/jars/vecmath-1.3.1.jar
 library@VECMATH@sha1=a0ae4f51da409fa0c20fa0ca59e6bbc9413ae71d
 
 distribution@GRAAL@path=graal.jar
--- a/mxtool/mx.py	Mon Jun 30 08:50:26 2014 +0200
+++ b/mxtool/mx.py	Mon Jun 30 12:02:19 2014 +0200
@@ -102,7 +102,8 @@
                 existingSource = zf._provenance.get(arcname, None)
                 isOverwrite = False
                 if existingSource and existingSource != source:
-                    log('warning: ' + self.path + ': avoid overwrite of ' + arcname + '\n  new: ' + source + '\n  old: ' + existingSource)
+                    if arcname[-1] != os.path.sep:
+                        logv('warning: ' + self.path + ': avoid overwrite of ' + arcname + '\n  new: ' + source + '\n  old: ' + existingSource)
                     isOverwrite = True
                 zf._provenance[arcname] = source
                 return isOverwrite
@@ -1978,8 +1979,9 @@
             if not self.jdtJar:
                 mainJava = java()
                 if not args.error_prone:
-                    self.logCompilation('javac')
-                    javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
+                    javac = args.alt_javac if args.alt_javac else mainJava.javac
+                    self.logCompilation('javac' if not args.alt_javac else args.alt_javac)
+                    javacCmd = [javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
                     if jdk.debug_port is not None:
                         javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
                     javacCmd += processorArgs
@@ -2063,10 +2065,11 @@
     parser.add_argument('--no-native', action='store_false', dest='native', help='do not build native projects')
     parser.add_argument('--jdt-warning-as-error', action='store_true', help='convert all Eclipse batch compiler warnings to errors')
     parser.add_argument('--jdt-show-task-tags', action='store_true', help='show task tags as Eclipse batch compiler warnings')
+    parser.add_argument('--alt-javac', dest='alt_javac', help='path to alternative javac executable', metavar='<path>')
     compilerSelect = parser.add_mutually_exclusive_group()
     compilerSelect.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='<path>')
     compilerSelect.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler', default=_defaultEcjPath(), metavar='<path>')
-    compilerSelect.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not')
+    compilerSelect.add_argument('--force-javac', action='store_true', dest='javac', help='use javac whether ecj.jar is found or not')
 
     if suppliedParser:
         parser.add_argument('remainder', nargs=REMAINDER, metavar='...')
@@ -2846,6 +2849,7 @@
     parser = parser if suppliedParser else ArgumentParser(prog='mx clean')
     parser.add_argument('--no-native', action='store_false', dest='native', help='do not clean native projects')
     parser.add_argument('--no-java', action='store_false', dest='java', help='do not clean Java projects')
+    parser.add_argument('--no-dist', action='store_false', dest='dist', help='do not delete distributions')
 
     args = parser.parse_args(args)
 
@@ -2855,6 +2859,10 @@
             path = unicode("\\\\?\\" + dirPath)
         shutil.rmtree(path)
 
+    def _rmIfExists(name):
+        if os.path.isfile(name):
+            os.unlink(name)
+
     for p in projects_opt_limit_to_suites():
         if p.native:
             if args.native:
@@ -2878,6 +2886,12 @@
                 if config.exists():
                     os.unlink(config.path)
 
+    if args.dist:
+        for d in _dists.keys():
+            log('Removing distribution {0}...'.format(d))
+            _rmIfExists(distribution(d).path)
+            _rmIfExists(distribution(d).sourcesPath)
+
     if suppliedParser:
         return args
 
@@ -4149,9 +4163,8 @@
         projectDirs = [p.dir for p in suite.projects]
         for dirpath, dirnames, files in os.walk(suite.dir):
             if dirpath == suite.dir:
-                # no point in traversing .hg
-                if '.hg' in dirnames:
-                    dirnames.remove('.hg')
+                # no point in traversing .hg or lib/
+                dirnames[:] = [d for d in dirnames if d not in ['.hg', 'lib']]
             elif dirpath in projectDirs:
                 # don't traverse subdirs of an existing project in this suite
                 dirnames[:] = []
@@ -4474,7 +4487,7 @@
         return kwargs.pop(0)
     return None
 
-def findclass(args, logToConsole=True):
+def findclass(args, logToConsole=True, matcher=lambda string, classname: string in classname):
     """find all classes matching a given substring"""
     matches = []
     for entry, filename in classpath_walk(includeBootClasspath=True):
@@ -4485,7 +4498,7 @@
                 classname = filename.replace(os.sep, '.')
             classname = classname[:-len('.class')]
             for a in args:
-                if a in classname:
+                if matcher(a, classname):
                     matches.append(classname)
                     if logToConsole:
                         log(classname)
--- a/src/cpu/x86/vm/assembler_x86.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/cpu/x86/vm/assembler_x86.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -1824,7 +1824,7 @@
 
 void Assembler::movsbl(Register dst, Register src) { // movsxb
   NOT_LP64(assert(src->has_byte_register(), "must have byte register"));
-  int encode = prefix_and_encode(dst->encoding(), src->encoding(), true);
+  int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true);
   emit_int8(0x0F);
   emit_int8((unsigned char)0xBE);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -1917,7 +1917,7 @@
 
 void Assembler::movzbl(Register dst, Register src) { // movzxb
   NOT_LP64(assert(src->has_byte_register(), "must have byte register"));
-  int encode = prefix_and_encode(dst->encoding(), src->encoding(), true);
+  int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true);
   emit_int8(0x0F);
   emit_int8((unsigned char)0xB6);
   emit_int8(0xC0 | encode);
@@ -4562,12 +4562,12 @@
   return reg_enc;
 }
 
-int Assembler::prefix_and_encode(int dst_enc, int src_enc, bool byteinst) {
+int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) {
   if (dst_enc < 8) {
     if (src_enc >= 8) {
       prefix(REX_B);
       src_enc -= 8;
-    } else if (byteinst && src_enc >= 4) {
+    } else if ((src_is_byte && src_enc >= 4) || (dst_is_byte && dst_enc >= 4)) {
       prefix(REX);
     }
   } else {
--- a/src/cpu/x86/vm/assembler_x86.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/cpu/x86/vm/assembler_x86.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -556,7 +556,10 @@
   int prefix_and_encode(int reg_enc, bool byteinst = false);
   int prefixq_and_encode(int reg_enc);
 
-  int prefix_and_encode(int dst_enc, int src_enc, bool byteinst = false);
+  int prefix_and_encode(int dst_enc, int src_enc) {
+    return prefix_and_encode(dst_enc, false, src_enc, false);
+  }
+  int prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte);
   int prefixq_and_encode(int dst_enc, int src_enc);
 
   void prefix(Register reg);
--- a/src/gpu/hsail/vm/gpu_hsail.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/gpu/hsail/vm/gpu_hsail.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -66,11 +66,11 @@
 JNINativeMethod Hsail::HSAIL_methods[] = {
   {CC"initialize",       CC"()Z",                               FN_PTR(Hsail::initialize)},
   {CC"generateKernel",   CC"([B" STRING ")J",                   FN_PTR(Hsail::generate_kernel)},
-  {CC"executeKernel0",   CC"("HS_INSTALLED_CODE"I["OBJECT"["OBJECT"["JLTHREAD"I[I)Z",  FN_PTR(Hsail::execute_kernel_void_1d)},
+  {CC"executeKernel0",   CC"("HS_INSTALLED_CODE"I["OBJECT"["JLTHREAD"I[I)Z",  FN_PTR(Hsail::execute_kernel_void_1d)},
 };
 
-void * Hsail::_device_context = NULL;
-jint   Hsail::_notice_safepoints = false;
+void* Hsail::_device_context = NULL;
+jint  Hsail::_notice_safepoints = false;
 
 Hsail::okra_create_context_func_t  Hsail::_okra_create_context;
 Hsail::okra_create_kernel_func_t   Hsail::_okra_create_kernel;
@@ -85,43 +85,6 @@
 Hsail::okra_clearargs_func_t       Hsail::_okra_clearargs;
 Hsail::okra_register_heap_func_t   Hsail::_okra_register_heap;
 
-struct Stats {
-  int _dispatches;
-  int _deopts;
-  int _overflows;
-  bool _changeSeen;
-
-public:
-  Stats() {
-    _dispatches = _deopts = _overflows = 0;
-    _changeSeen = false;
-  }
-
-  void incDeopts() {
-    _deopts++;
-    _changeSeen = true;
-  }
-  void incOverflows() {
-    _overflows++;
-    _changeSeen = true;
-  }
-
-  void finishDispatch() {
-    _dispatches++;
-    if (_changeSeen) {
-      // print();
-      _changeSeen = false;
-    }
-  }
-
-  void print() {
-    tty->print_cr("Disp=%d, Deopts=%d, Ovflows=%d", _dispatches, _deopts, _overflows);
-  }
-
-};
-
-static Stats kernelStats;
-
 //static jint in_kernel = 0;
 
 void Hsail::notice_safepoints() {
@@ -145,7 +108,7 @@
   _okra_register_heap(Universe::heap()->base(), Universe::heap()->capacity());
 }
 
-GPU_VMENTRY(jboolean, Hsail::execute_kernel_void_1d, (JNIEnv* env, jclass, jobject kernel_handle, jint dimX, jobject args, jobject oops_save,
+GPU_VMENTRY(jboolean, Hsail::execute_kernel_void_1d, (JNIEnv* env, jclass, jobject kernel_handle, jint dimX, jobject args,
                                                       jobject donor_threads, jint allocBytesPerWorkitem, jobject oop_map_array))
 
   ResourceMark rm;
@@ -162,10 +125,10 @@
     SharedRuntime::throw_and_post_jvmti_exception(JavaThread::current(), vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException(), NULL);
   }
 
-return execute_kernel_void_1d_internal((address) kernel, dimX, args, mh, nm, oops_save, donor_threads, allocBytesPerWorkitem, oop_map_array, CHECK_0);
+return execute_kernel_void_1d_internal((address) kernel, dimX, args, mh, nm, donor_threads, allocBytesPerWorkitem, oop_map_array, CHECK_0);
 GPU_END
 
-static void showRanges(jboolean *a, int len) {
+static void showRanges(jboolean* a, int len) {
   // show ranges
   bool lookFor = true;
   for (int i = 0; i < len; i++) {
@@ -182,225 +145,36 @@
   }
 }
 
-// fill and retire old tlab and get a new one
-// if we can't get one, no problem someone will eventually do a gc
-void Hsail::getNewTlabForDonorThread(ThreadLocalAllocBuffer* tlab, size_t tlabMinHsail) {
-  tlab->clear_before_allocation();    // fill and retire old tlab (will also check for null)
-
-  // get a size for a new tlab that is at least tlabMinHsail.
-  size_t new_tlab_size = tlab->compute_size(tlabMinHsail);
-  if (new_tlab_size == 0) return;
-
-  HeapWord* tlab_start = Universe::heap()->allocate_new_tlab(new_tlab_size);
-  if (tlab_start == NULL) return;
-
-  // ..and clear it if required
-  if (ZeroTLAB) {
-    Copy::zero_to_words(tlab_start, new_tlab_size);
-  }
-  // and init the tlab pointers
-  tlab->fill(tlab_start, tlab_start, new_tlab_size);
-}
-
-static void printTlabInfo (ThreadLocalAllocBuffer* tlab) {
-  HeapWord *start = tlab->start();
-  HeapWord *top = tlab->top();
-  HeapWord *end = tlab->end();
-  // sizes are in bytes
-  size_t tlabFree = tlab->free() * HeapWordSize;
-  size_t tlabUsed = tlab->used() * HeapWordSize;
-  size_t tlabSize = tlabFree + tlabUsed;
-  double freePct = 100.0 * (double) tlabFree/(double) tlabSize;
-  tty->print_cr("(%p, %p, %p), siz=%ld, free=%ld (%f%%)", start, top, end, tlabSize, tlabFree, freePct);
-}
-
-class OopSaver : public StackObj {
-private:
-  objArrayOop _oopsSaveArray;
-  typeArrayOop _oopMapArray;
-  jobject  _oops_save;
-  jobject _oop_map_array;
-  int _last_pcoffset;
-  int _last_idx;
-  int _saveAreaCounts;
-
-  enum {
-    SAVEAREACOUNTS_OFST=0,
-    SPAN_OFST=1,
-    HEADERSIZE=2
-  }; 
-  int mapPcOffsetToIndex(int pcOffset) {
-    if (pcOffset == _last_pcoffset) {
-      return _last_idx;
-    }
-    int span = _oopMapArray->int_at(SPAN_OFST);
-    for (int idx = HEADERSIZE; idx < _oopMapArray->length(); idx += span) {
-      int ofst = _oopMapArray->int_at(idx);
-      if (ofst == pcOffset) {
-        _last_pcoffset = pcOffset;
-        _last_idx = idx + 1;
-        return _last_idx;
-      }
-    }
-    ShouldNotReachHere();
-    return -1;
-  }
-
-public:
-  OopSaver(jobject oops_save, jobject oop_map_array) {
-    _oops_save = oops_save;
-    _oop_map_array = oop_map_array;
-    _last_pcoffset = -1;
-    _saveAreaCounts = getSaveAreaCounts(oop_map_array);
-    resolveArrays();
-  }
- 
-  void resolveArrays() {
-    _oopsSaveArray = (objArrayOop) JNIHandles::resolve(_oops_save);
-    _oopMapArray = (typeArrayOop) JNIHandles::resolve(_oop_map_array);
-  }
-
-  void * getOopForBit(HSAILFrame * hsailFrame, int bit) {
-    assert(isOop(hsailFrame, bit), "");
-    void *oop;
-    if (bit < hsailFrame->num_d_regs()) {
-      // d register
-      oop = (void*) hsailFrame->get_d_reg(bit);
-    } else {
-      // stack slot
-      int stackOffset = (bit - hsailFrame->num_d_regs()) * 8;  // 8 bytes per stack slot
-      oop = (void *) hsailFrame->get_stackslot64(stackOffset);
-    }
-    return oop;
-  }
-
-  void putOopForBit(HSAILFrame * hsailFrame, int bit, void *oop) {
-    assert(isOop(hsailFrame, bit), "");
-    if (bit < hsailFrame->num_d_regs()) {
-      // d register
-      hsailFrame->put_d_reg(bit, (jlong) oop);
-    } else {
-      // stack slot
-      int stackOffset = (bit - hsailFrame->num_d_regs()) * 8;  // 8 bytes per stack slot
-      hsailFrame->put_stackslot64(stackOffset, (jlong) oop);
-    }
-  }
-
-  void saveOopsFromFrame(HSAILFrame * hsailFrame, int deoptSlot){
-    // as used, no need to resolve arrays on each call
-    int oopsPerDeopt = hsailFrame->num_d_regs() + hsailFrame->num_stack_slots();
-
-    // handle the dregister and stackSlot based oops
-    for (int bit = 0; bit < oopsPerDeopt; bit++) {
-      if (isOop(hsailFrame, bit)) {
-        void* saved_oop = getOopForBit(hsailFrame, bit);
-        int saveArrayIndex = deoptSlot * oopsPerDeopt + bit;
-        _oopsSaveArray->obj_at_put(saveArrayIndex, (oop) saved_oop);
-      }
-    }
-  }
-
-  void restoreOopsToFrame(HSAILFrame * hsailFrame, int deoptSlot, int workitem){
-    // need to re-resolve on each restore
-    resolveArrays();
-    int oopsPerDeopt = hsailFrame->num_d_regs() + hsailFrame->num_stack_slots();
-
-    // handle the dregister and stackSlot based oops
-    for (int bit = 0; bit < oopsPerDeopt; bit++) {
-      if (isOop(hsailFrame, bit)) {
-        // the dregister or stack slot at this bit is an oop, retrieve it from array and put back in frame
-        int saveArrayIndex = deoptSlot * oopsPerDeopt + bit;
-        void * newValue = (void *) _oopsSaveArray->obj_at(saveArrayIndex);
-        void * oldValue = getOopForBit(hsailFrame, bit);
-        assert((oldValue != 0 ? newValue != 0 : newValue == 0), "bad dregValue retrieved");
-        if (newValue != oldValue) {
-          if (TraceGPUInteraction) {
-            int numDRegs = hsailFrame->num_d_regs();
-            const char *name = (bit < numDRegs ? "$d" : "stk");
-            int num = (bit < numDRegs ? bit : bit - numDRegs);
-            tty->print_cr("oop moved for %s%d, workitem %d, slot %d, old=%p, new=%p",
-                          name, num, workitem, deoptSlot, oldValue, newValue);
-          }
-          putOopForBit(hsailFrame, bit, newValue);
-        }
-      }
-    }
-  }
-
-  bool isOop(HSAILFrame * hsailFrame, int bit){
-    // re-resolve on each access
-    resolveArrays();
-    if (bit > hsailFrame->num_d_regs() + hsailFrame->num_stack_slots()) {
-      return false;
-    }
-    int pcOffset = hsailFrame->pc_offset();
-    int bits_int_idx = mapPcOffsetToIndex(pcOffset) + (bit / 32);
-    int bitpos = bit % 32;
-    int bits = _oopMapArray->int_at(bits_int_idx);
-    return ((bits & (1 << bitpos)) != 0);
-  }
-
-  static int getSaveAreaCounts(jobject oopMapArrayObject) {
-    typeArrayOop oopMapArray = (typeArrayOop) JNIHandles::resolve(oopMapArrayObject);
-    return oopMapArray->int_at(SAVEAREACOUNTS_OFST);
-  }
-
-};
-
-jboolean Hsail::execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod *nm, jobject oops_save,
+jboolean Hsail::execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod* nm,
                                                 jobject donor_threads, int allocBytesPerWorkitem, jobject oop_map_array, TRAPS) {
   ResourceMark rm(THREAD);
   objArrayOop argsArray = (objArrayOop) JNIHandles::resolve(args);
-
-  // TODO: avoid donor thread logic if kernel does not allocate
-  objArrayOop donorThreadObjects = (objArrayOop) JNIHandles::resolve(donor_threads);
-  int numDonorThreads = donorThreadObjects->length();
-  guarantee(numDonorThreads > 0, "need at least one donor thread");
-  JavaThread** donorThreads = NEW_RESOURCE_ARRAY(JavaThread*, numDonorThreads);
-  for (int i = 0; i < numDonorThreads; i++) {
-    donorThreads[i] = java_lang_Thread::thread(donorThreadObjects->obj_at(i));
-  }
-
-
-  // compute tlabMinHsail based on number of workitems, number of donor
-  // threads, allocBytesPerWorkitem rounded up
-  size_t tlabMinHsail = (allocBytesPerWorkitem * dimX + (numDonorThreads - 1)) / numDonorThreads;
-  if (TraceGPUInteraction) {
-    tty->print_cr("computed tlabMinHsail = %d", tlabMinHsail);
-  }
+  assert(THREAD->is_Java_thread(), "must be a JavaThread");
 
-  for (int i = 0; i < numDonorThreads; i++) {
-    JavaThread* donorThread = donorThreads[i];
-    ThreadLocalAllocBuffer* tlab = &donorThread->tlab();
-    if (TraceGPUInteraction) {
-      tty->print("donorThread %d, is %p, tlab at %p -> ", i, donorThread, tlab);
-      printTlabInfo(tlab);
-    }
-
-    // note: this used vs. free limit checking should be based on some
-    // heuristic where we see how much this kernel tends to allocate
-    if ((tlab->end() == NULL) || (tlab->free() * HeapWordSize < tlabMinHsail)) {
-      getNewTlabForDonorThread(tlab, tlabMinHsail);
-      if (TraceGPUInteraction) {
-        tty->print("donorThread %d, refilled tlab, -> ", i);
-        printTlabInfo(tlab);
-      }
-    }
-  }
-
+  // We avoid HSAILAllocationInfo logic if kernel does not allocate
+  // in which case the donor_thread array passed in will be null
+  HSAILAllocationInfo* allocInfo = (donor_threads == NULL ? NULL : new HSAILAllocationInfo(donor_threads, dimX, allocBytesPerWorkitem));
+  
   // Reset the kernel arguments
   _okra_clearargs(kernel);
 
+  JavaThread* thread = (JavaThread*)THREAD;
   HSAILDeoptimizationInfo* e;
   if (UseHSAILDeoptimization) {
     // get how many bytes per deopt save area are required
-    int saveAreaCounts = OopSaver::getSaveAreaCounts(oop_map_array);
+    int saveAreaCounts = HSAILOopMapHelper::get_save_area_counts(oop_map_array);
     int numSRegs = saveAreaCounts & 0xff;
     int numDRegs = (saveAreaCounts >> 8) & 0xff;
     int numStackSlots = (saveAreaCounts >> 16);
     int bytesPerSaveArea = numSRegs * 4 + (numDRegs + numStackSlots) * 8;
 
-    e = new (MAX_DEOPT_SLOTS, bytesPerSaveArea) HSAILDeoptimizationInfo(MAX_DEOPT_SLOTS, bytesPerSaveArea, dimX, donorThreads);
+    e = new (MAX_DEOPT_SLOTS, bytesPerSaveArea) HSAILDeoptimizationInfo(MAX_DEOPT_SLOTS, bytesPerSaveArea, dimX, allocInfo, oop_map_array);
+    // copy cur_tlab_infos
+    if (allocInfo != NULL) {
+      e->set_cur_tlabInfos(allocInfo->getCurTlabInfos());
+    }
+    // set deopt info in thread so gc oops_do processing can find it
+    thread->set_gpu_hsail_deopt_info(e);
   }
 
   // This object sets up the kernel arguments
@@ -409,12 +183,11 @@
     tty->print_cr("[HSAIL] range=%d", dimX);
   }
 
-  // if any object passed was null, throw an exception here
-  // doing this means the kernel code can avoid null checks on the object parameters.
+  // If any object passed was null, throw an exception here. Doing this
+  // means the kernel code can avoid null checks on the object parameters.
   if (hka.getFirstNullParameterIndex() >= 0) {
     char buf[64];
     sprintf(buf, "Null Kernel Parameter seen, Parameter Index: %d", hka.getFirstNullParameterIndex());
-    JavaThread* thread = (JavaThread*)THREAD;
     thread->set_gpu_exception_bci(0);
     thread->set_gpu_exception_method(mh());
     THROW_MSG_0(vmSymbols::java_lang_NullPointerException(), buf);
@@ -431,23 +204,9 @@
     //in_kernel = 0;
   }
 
-  // fix up any tlab tops that overflowed
-  bool anyOverflows = false;
-  for (int i = 0; i < numDonorThreads; i++) {
-    JavaThread * donorThread = donorThreads[i];
-    ThreadLocalAllocBuffer* tlab = &donorThread->tlab();
-    if (tlab->top() > tlab->end()) {
-      anyOverflows = true;
-      long overflowAmount = (long) tlab->top() - (long) tlab->pf_top(); 
-      // tlab->set_top is private this ugly hack gets around that
-      *(long *)((char *)tlab + in_bytes(tlab->top_offset())) = (long) tlab->pf_top();
-      if (TraceGPUInteraction) {
-        tty->print_cr("donorThread %d at %p overflowed by %ld bytes, setting last good top to %p", i, donorThread, overflowAmount, tlab->top());
-      }
-    }
-  }
-  if (anyOverflows) {
-    kernelStats.incOverflows();
+  // avoid HSAILAllocationInfo logic if kernel does not allocate
+  if (allocInfo != NULL) {
+    allocInfo->postKernelCleanup();
   }
 
   if (UseHSAILDeoptimization) {
@@ -465,45 +224,23 @@
         guarantee(deoptcode == 1, msg);
       }
     } else {
-      kernelStats.incDeopts();
-
       {
         TraceTime t3("handle deoptimizing workitems", TraceGPUInteraction);
         if (TraceGPUInteraction) {
           tty->print_cr("deopt happened.");
-          HSAILKernelDeoptimization * pdeopt = e->get_deopt_save_state(0);
+          HSAILKernelDeoptimization* pdeopt = e->get_deopt_save_state(0);
           tty->print_cr("first deopter was workitem %d", pdeopt->workitem());
         }
 
-        // Before handling any deopting workitems, save the pointers from
-        // the hsail frames in oops_save so they get adjusted by any
-        // GC. Need to do this before leaving thread_in_vm mode.
-        OopSaver oopSaver(oops_save, oop_map_array);
-        // resolve handle only needed once here (not exiting vm mode)
-        oopSaver.resolveArrays();
-
-        // since slots are allocated from the beginning, we know how far to look
-        assert(e->num_deopts() < e->num_slots(), "deopt save state overflow");
-        for (int k = 0; k < e->num_deopts(); k++) {
-          HSAILKernelDeoptimization * pdeopt = e->get_deopt_save_state(k);
-          assert (pdeopt->workitem() >= 0, "bad workitem in deopt");
-          // this is a workitem that deopted
-          oopSaver.saveOopsFromFrame(pdeopt->first_frame(), k);
-        }
-
         // Handle any deopting workitems.
         int count_deoptimized = 0;
         for (int k = 0; k < e->num_deopts(); k++) {
-          HSAILKernelDeoptimization * pdeopt = e->get_deopt_save_state(k);
+          HSAILKernelDeoptimization* pdeopt = e->get_deopt_save_state(k);
 
           jint workitem = pdeopt->workitem();
           if (workitem != -1) {
             int deoptId = pdeopt->pc_offset();
-            HSAILFrame *hsailFrame = pdeopt->first_frame();
-
-            // update the hsailFrame from the oopsSaveArray
-            // will re-resolve the handles each time
-            oopSaver.restoreOopsToFrame(hsailFrame, k, workitem);
+            HSAILFrame* hsailFrame = pdeopt->first_frame();
 
             JavaValue result(T_VOID);
             JavaCallArguments javaArgs;
@@ -511,7 +248,7 @@
             javaArgs.push_int(deoptId);
             javaArgs.push_long((jlong) hsailFrame);
 
-            // override the deoptimization action with Action_none until we decide
+            // Override the deoptimization action with Action_none until we decide
             // how to handle the other actions.
             int myActionReason = Deoptimization::make_trap_request(Deoptimization::trap_request_reason(pdeopt->reason()), Deoptimization::Action_none);
             javaArgs.push_int(myActionReason);
@@ -520,21 +257,24 @@
               tty->print_cr("[HSAIL] Deoptimizing to host for workitem=%d (slot=%d) with deoptId=%d, frame=" INTPTR_FORMAT ", actionAndReason=%d", workitem, k, deoptId, hsailFrame, myActionReason);
               // show the $d registers or stack slots containing references
               int maxOopBits = hsailFrame->num_d_regs() + hsailFrame->num_stack_slots();
+              HSAILOopMapHelper oopMapHelper(oop_map_array);
+              int pc_offset = hsailFrame->pc_offset();
               for (int bit = 0; bit < maxOopBits; bit++) {
-                if (oopSaver.isOop(hsailFrame, bit)) {
+                if (oopMapHelper.is_oop(pc_offset, bit)) {
                   if (bit < hsailFrame->num_d_regs()) {
                     // show $d reg oop
-                    tty->print_cr("  oop $d%d = %p", bit, oopSaver.getOopForBit(hsailFrame, bit));
+                    tty->print_cr("  oop $d%d = %p", bit, hsailFrame->get_oop_for_bit(bit));
                   } else {
                     // show stack slot oop
                     int stackOffset = (bit - hsailFrame->num_d_regs()) * 8;  // 8 bytes per stack slot
-                    tty->print_cr("  oop stk:%d = %p", stackOffset, oopSaver.getOopForBit(hsailFrame, bit));
+                    tty->print_cr("  oop stk:%d = %p", stackOffset, hsailFrame->get_oop_for_bit(bit));
                   }
                 }
               }
             }
             JavaCalls::call(&result, mh, &javaArgs, THREAD);
             count_deoptimized++;
+            e->set_deopt_work_index(k + 1);
           }
         }
         if (TraceGPUInteraction) {
@@ -542,6 +282,9 @@
         }
       }
     }
+    // when we are done with the deopts, we don't need to oops_do anything
+    // in the saved state anymore
+    thread->set_gpu_hsail_deopt_info(NULL);  
 
     // Handle any never_ran workitems if there were any
     {
@@ -551,7 +294,7 @@
       // turn off verbose trace stuff for javacall arg setup
       bool savedTraceGPUInteraction = TraceGPUInteraction;
       TraceGPUInteraction = false;
-      jboolean *never_ran_array = e->never_ran_array();
+      jboolean* never_ran_array = e->never_ran_array();
       if (handleNeverRansHere) {
         for (int k = 0; k < dimX; k++) {
           if (never_ran_array[k]) {
@@ -562,9 +305,10 @@
             JavaCallArguments javaArgs;
             // re-resolve the args_handle here
             objArrayOop resolvedArgsArray = (objArrayOop) JNIHandles::resolve(args);
-            // This object sets up the javaCall arguments
-            // the way argsArray is set up, this should work for instance methods as well
-            // (the receiver will be the first oop pushed)
+
+            // This object sets up the javaCall arguments. The way
+            // argsArray is set up, this should work for instance
+            // methods as well (the receiver will be the first oop pushed)
             HSAILJavaCallArguments hjca(&javaArgs, k, mh->signature(), resolvedArgsArray, mh->is_static());
             if (mh->is_static()) {
               JavaCalls::call_static(&result, methKlass, mh->name(), mh->signature(), &javaArgs, THREAD);
@@ -583,19 +327,19 @@
     }
 
     delete e;
+    delete allocInfo;
   }
-  kernelStats.finishDispatch();
   return success;
 }
 
-GPU_ENTRY(jlong, Hsail::generate_kernel, (JNIEnv *env, jclass, jbyteArray code_handle, jstring name_handle))
+GPU_ENTRY(jlong, Hsail::generate_kernel, (JNIEnv* env, jclass, jbyteArray code_handle, jstring name_handle))
   guarantee(_okra_create_kernel != NULL, "[HSAIL] Okra not linked");
   ResourceMark rm;
   jsize name_len = env->GetStringLength(name_handle);
   jsize code_len = env->GetArrayLength(code_handle);
 
   char* name = NEW_RESOURCE_ARRAY(char, name_len + 1);
-  unsigned char *code = NEW_RESOURCE_ARRAY(unsigned char, code_len + 1);
+  unsigned char* code = NEW_RESOURCE_ARRAY(unsigned char, code_len + 1);
 
   code[code_len] = 0;
   name[name_len] = 0;
@@ -631,7 +375,7 @@
         return false; \
   } \
 
-GPU_ENTRY(jboolean, Hsail::initialize, (JNIEnv *env, jclass))
+GPU_ENTRY(jboolean, Hsail::initialize, (JNIEnv* env, jclass))
   if (okra_library_name == NULL) {
     if (TraceGPUInteraction) {
       tty->print_cr("Unsupported HSAIL platform");
@@ -641,14 +385,14 @@
 
   // here we know we have a valid okra_library_name to try to load
   char ebuf[O_BUFLEN];
-  char *okra_lib_name_from_env_var = getenv("_OKRA_SIM_LIB_PATH_");
+  char* okra_lib_name_from_env_var = getenv("_OKRA_SIM_LIB_PATH_");
   if (okra_lib_name_from_env_var != NULL) {
     okra_library_name = okra_lib_name_from_env_var;
   }
   if (TraceGPUInteraction) {
     tty->print_cr("[HSAIL] library is %s", okra_library_name);
   }
-  void *okra_lib_handle = NULL;
+  void* okra_lib_handle = NULL;
 #if defined(LINUX)
   // Check first if the Okra library is already loaded.
   // TODO: Figure out how to do this on other OSes.
@@ -668,8 +412,8 @@
   
   guarantee(_okra_create_context == NULL, "cannot repeat GPU initialization");
 
-  // at this point we know  okra_lib_handle is valid whether we loaded
-  // here or earlier.  In either case, we can lookup the functions
+  // At this point we know  okra_lib_handle is valid whether we loaded
+  // here or earlier.  In either case, we can lookup the functions.
   LOOKUP_OKRA_FUNCTION(okra_create_context, okra_create_context);
   LOOKUP_OKRA_FUNCTION(okra_create_kernel, okra_create_kernel);
   LOOKUP_OKRA_FUNCTION(okra_push_object, okra_push_object);
@@ -707,3 +451,27 @@
   }
   return true;
 }
+
+
+void Hsail::HSAILDeoptimizationInfo::oops_do(OopClosure* f) {
+  int unprocessed_deopts = num_deopts() - deopt_work_index();
+  if (TraceGPUInteraction) {
+    tty->print_cr("HSAILDeoptimizationInfo::oops_do deopt_occurred=%d, total_deopts=%d, unprocessed_deopts=%d, oop_map_array=%p", _deopt_occurred, num_deopts(), unprocessed_deopts, _oop_map_array);
+  }
+  if (num_deopts() == 0 || unprocessed_deopts <= 0) {
+    return; // nothing to do
+  }
+  HSAILOopMapHelper oopMapHelper(_oop_map_array);
+  oopMapHelper.resolve_arrays();  // resolve once before processing
+
+  // go thru the unprocessed deopt frames, finding each oop and applying the closre
+  for (int k = deopt_work_index(); k < num_deopts(); k++) {
+    HSAILKernelDeoptimization* pdeopt = get_deopt_save_state(k);
+    assert (pdeopt->workitem() >= 0, "bad workitem in deopt");
+    if (TraceGPUInteraction) {
+      tty->print_cr("  deopt %d, workitem %d, pc %d", k, pdeopt->workitem(), pdeopt->pc_offset());
+    }
+    HSAILFrame* hsailFrame = pdeopt->first_frame();
+    hsailFrame->oops_do(f, &oopMapHelper);
+  }
+}
--- a/src/gpu/hsail/vm/gpu_hsail.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/gpu/hsail/vm/gpu_hsail.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -22,12 +22,49 @@
  *
  */
 
-#ifndef GPU_HSAIL_HPP
-#define GPU_HSAIL_HPP
+#ifndef GPU_HSAIL_VM_GPU_HSAIL_HPP
+#define GPU_HSAIL_VM_GPU_HSAIL_HPP
 
+#include "runtime/gpu.hpp"
 #include "utilities/exceptions.hpp"
 #include "graal/graalEnv.hpp"
+#include "gpu_hsail_OopMapHelper.hpp"
 #include "gpu_hsail_Frame.hpp"
+#include "gpu_hsail_Tlab.hpp"
+
+struct HSAILKernelStats {
+  int _dispatches;
+  int _deopts;
+  int _overflows;
+  bool _changeSeen;
+  
+public:
+  HSAILKernelStats() {
+    _dispatches = _deopts = _overflows = 0;
+    _changeSeen = false;
+  }
+  
+  void incDeopts() {
+    _deopts++;
+    _changeSeen = true;
+  }
+  void incOverflows() {
+    _overflows++;
+    _changeSeen = true;
+  }
+  
+  void finishDispatch() {
+    _dispatches++;
+    if (_changeSeen) {
+      // print();
+      _changeSeen = false;
+    }
+  }
+  
+  void print() {
+    tty->print_cr("Disp=%d, Deopts=%d, Ovflows=%d", _dispatches, _deopts, _overflows);
+  }
+};
 
 class Hsail : public Gpu {
 
@@ -46,9 +83,9 @@
     inline jint workitem() { return _workitemid; }
     inline jint reason() { return _actionAndReason; }
     inline jint pc_offset() { return first_frame()->pc_offset(); }
-    inline HSAILFrame *first_frame() {
+    inline HSAILFrame* first_frame() {
       // starts after the "header" fields
-      return (HSAILFrame *) (((jbyte *) this) + sizeof(*this));
+      return (HSAILFrame*) (((jbyte*) this) + sizeof(*this));
     }
   };
 
@@ -56,38 +93,45 @@
 // TODO: query the device to get this number
 #define MAX_DEOPT_SLOTS    (8 * 40 * 64)
 
+
   class HSAILDeoptimizationInfo : public CHeapObj<mtInternal> {
     friend class VMStructs;
    private:
     jint* _notice_safepoints;
     jint _deopt_occurred;
     jint _deopt_next_index;
-    JavaThread** _donor_threads;
     jint _num_slots;
     jint _deopt_span;
+    jint _deopt_work_index;           // how far we are in processing the deopts
+    HSAILTlabInfo** _cur_tlab_info;   // copy of what was in the HSAILAllocationInfo, to avoid an extra indirection
+    HSAILAllocationInfo* _alloc_info;
     char _ignore;
+    jobject _oop_map_array;
     // keep a pointer last so save area following it is word aligned
-    jboolean * _never_ran_array; 
+    jboolean* _never_ran_array; 
 
    public:
+    // static HSAILKernelStats kernelStats;
     HSAILKernelDeoptimization _deopt_save_states[1];  // number and size of these can vary per kernel
 
     static inline size_t hdr_size() {
       return sizeof(HSAILDeoptimizationInfo);
     }
 
-    inline jbyte * save_area_start() {
+    inline jbyte* save_area_start() {
       return (jbyte*) (this) + hdr_size();
     }
 
-    inline HSAILDeoptimizationInfo(int numSlots, int bytesPerSaveArea, int dimX, JavaThread** donorThreads) {
+    inline HSAILDeoptimizationInfo(int numSlots, int bytesPerSaveArea, int dimX, HSAILAllocationInfo* allocInfo, jobject oop_map_array) {
       _notice_safepoints = &Hsail::_notice_safepoints;
       _deopt_occurred = 0;
       _deopt_next_index = 0;
+      _deopt_work_index = 0;
       _num_slots = numSlots;
       _never_ran_array = NEW_C_HEAP_ARRAY(jboolean, dimX, mtInternal);
       memset(_never_ran_array, 0, dimX * sizeof(jboolean));
-      _donor_threads = donorThreads;
+      _alloc_info = allocInfo;
+      _oop_map_array = oop_map_array;
       _deopt_span = sizeof(HSAILKernelDeoptimization) + sizeof(HSAILFrame) + bytesPerSaveArea;
       if (TraceGPUInteraction) {
         tty->print_cr("HSAILDeoptimizationInfo allocated, %d slots of size %d, total size = 0x%lx bytes", _num_slots, _deopt_span, (_num_slots * _deopt_span + sizeof(HSAILDeoptimizationInfo)));
@@ -102,21 +146,29 @@
       return _deopt_occurred;
     }
     inline jint num_deopts() { return _deopt_next_index; }
-    inline jboolean *never_ran_array() { return _never_ran_array; }
+    inline jboolean* never_ran_array() { return _never_ran_array; }
     inline jint num_slots() {return _num_slots;}
+    inline void set_deopt_work_index(int val) { _deopt_work_index = val; }
+    inline jint deopt_work_index() { return _deopt_work_index; }
 
-    inline HSAILKernelDeoptimization * get_deopt_save_state(int slot) {
+    inline HSAILKernelDeoptimization* get_deopt_save_state(int slot) {
       // use _deopt_span to index into _deopt_states
-      return (HSAILKernelDeoptimization *) (save_area_start() + _deopt_span * slot);
+      return (HSAILKernelDeoptimization*) (save_area_start() + _deopt_span * slot);
     }
 
-    void * operator new (size_t hdrSize, int numSlots, int bytesPerSaveArea) {
+    void set_cur_tlabInfos(HSAILTlabInfo** ptlabInfos) {
+      _cur_tlab_info = ptlabInfos;
+    }
+
+    void oops_do(OopClosure* f);
+
+    void* operator new (size_t hdrSize, int numSlots, int bytesPerSaveArea) {
       assert(hdrSize <= hdr_size(), "");
       size_t totalSizeBytes = hdr_size()  + numSlots * (sizeof(HSAILKernelDeoptimization) + sizeof(HSAILFrame) + bytesPerSaveArea);
       return NEW_C_HEAP_ARRAY(char, totalSizeBytes, mtInternal);
     }
 
-    void operator delete (void *ptr) {
+    void operator delete (void* ptr) {
       FREE_C_HEAP_ARRAY(char, ptr, mtInternal);
     }
   };
@@ -126,21 +178,16 @@
   static JNINativeMethod HSAIL_methods[];
 
   // static native boolean initialize();
-  JNIEXPORT static jboolean initialize(JNIEnv *env, jclass);
+  JNIEXPORT static jboolean initialize(JNIEnv* env, jclass);
 
   // static native long generateKernel(byte[] targetCode, String name);
-  JNIEXPORT static jlong generate_kernel(JNIEnv *env, jclass, jbyteArray code_handle, jstring name_handle);
+  JNIEXPORT static jlong generate_kernel(JNIEnv* env, jclass, jbyteArray code_handle, jstring name_handle);
 
   // static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args);
-  JNIEXPORT static jboolean execute_kernel_void_1d(JNIEnv *env, jclass, jobject hotspotInstalledCode, jint dimX, jobject args, jobject oopsSave,
+  JNIEXPORT static jboolean execute_kernel_void_1d(JNIEnv* env, jclass, jobject hotspotInstalledCode, jint dimX, jobject args,
                                                    jobject donorThreads, int allocBytesPerWorkitem, jobject oop_map_array);
 
-  // static native void getThreadPointers(Object[] donorThreads, long[] threadPointersOut);
-  JNIEXPORT static void get_thread_pointers(JNIEnv *env, jclass, jobject donor_threads_handle, jobject thread_ptrs_handle);
-
-  static void getNewTlabForDonorThread(ThreadLocalAllocBuffer* tlab, size_t tlabMinHsail);
-
-  static jboolean execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod *nm, jobject oopsSave,
+  static jboolean execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod* nm,
                                                   jobject donorThreads, int allocBytesPerWorkitem, jobject oop_map_array, TRAPS);
 
   static void register_heap();
@@ -165,7 +212,7 @@
 
 private:
   typedef void* (*okra_create_context_func_t)();
-  typedef void* (*okra_create_kernel_func_t)(void*, unsigned char *, const char *);
+  typedef void* (*okra_create_kernel_func_t)(void*, unsigned char*, const char*);
   typedef bool (*okra_push_object_func_t)(void*, void*);
   typedef bool (*okra_push_boolean_func_t)(void*, jboolean);
   typedef bool (*okra_push_byte_func_t)(void*, jbyte);
@@ -197,4 +244,4 @@
   // true if safepoints are activated
   static jint _notice_safepoints;
 };
-#endif // GPU_HSAIL_HPP
+#endif // GPU_HSAIL_VM_GPU_HSAIL_HPP
--- a/src/gpu/hsail/vm/gpu_hsail_Frame.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/gpu/hsail/vm/gpu_hsail_Frame.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -22,8 +22,8 @@
  *
  */
 
-#ifndef GPU_HSAIL_FRAME_HPP
-#define GPU_HSAIL_FRAME_HPP
+#ifndef GPU_HSAIL_VM_GPU_HSAIL_FRAME_HPP
+#define GPU_HSAIL_VM_GPU_HSAIL_FRAME_HPP
 
 #include "graal/graalEnv.hpp"
 #include "code/debugInfo.hpp"
@@ -37,37 +37,86 @@
   jbyte _num_d_regs;
   jshort _num_stack_slots; 
 
+  jbyte* data_start() {return (jbyte*) this  + sizeof(*this); }
+  int sreg_ofst_start() { return 0; }
+  int dreg_ofst_start() { return sreg_ofst_start() + num_s_regs() * sizeof(jint); } 
+  int stackslot_ofst_start() { return dreg_ofst_start() + num_d_regs() * sizeof(jlong); } 
+
+  int sreg_ofst(int idx) {
+    assert(idx >= 0 && idx < num_s_regs(), "bad sreg index");
+    return sreg_ofst_start() + idx * sizeof(jint);
+  }
+
+  int dreg_ofst(int idx) {
+    assert(idx >= 0 && idx < num_d_regs(), "bad dreg index");
+    return dreg_ofst_start() + idx * sizeof(jlong);
+  }
+
+  int stackslot_ofst(int stackOffset) {
+    assert(stackOffset >= 0 && (unsigned int) stackOffset < num_stack_slots() * sizeof(jlong), "bad stackoffset");
+    return stackslot_ofst_start() + stackOffset;
+  }
+
+  // the _ptr versions just return a pointer to the indicated d reg or stackslot64
+  // some of these are used for oops_do processing
+  jint* get_s_reg_ptr(int idx) {
+    return((jint*) (data_start() + sreg_ofst(idx)));
+  }
+
+  jlong* get_d_reg_ptr(int idx) {
+    return((jlong*) (data_start() + dreg_ofst(idx)));
+  }
+
+  jlong* get_stackslot64_ptr(int stackOffset) {
+    return((jlong*) (data_start() + stackslot_ofst(stackOffset)));
+  }
+
+  jint* get_stackslot32_ptr(int stackOffset) {
+    return((jint*) (data_start() + stackslot_ofst(stackOffset)));
+  }
+
+  void* get_oop_ptr_for_bit(int bit) {
+    void* oop_ptr;
+    if (bit < num_d_regs()) {
+      // d register
+      oop_ptr = (void*) get_d_reg_ptr(bit);
+    } else {
+      // stack slot
+      int stackOffset = (bit - num_d_regs()) * 8;  // 8 bytes per stack slot
+      oop_ptr = (void*) get_stackslot64_ptr(stackOffset);
+    }
+    return oop_ptr;
+  }
+
 public:
   // Accessors
   jint pc_offset() { return _pc_offset; }
   jint num_s_regs() {return _num_s_regs; }
   jint num_d_regs() {return _num_d_regs; }
   jint num_stack_slots() {return _num_stack_slots; }
-  jbyte * data_start() {return (jbyte *) this  + sizeof(*this); }
-  jlong get_d_reg(int idx) {
-    int ofst = num_s_regs() * 4 + idx * 8;
-    return(*(jlong *) (data_start() + ofst));
-  }
-  jint get_s_reg(int idx) {
-    int ofst = idx * 4;
-    return(*(jint *) (data_start() + ofst));
+
+  jlong get_oop_for_bit(int bit) {
+    return * (jlong *) get_oop_ptr_for_bit(bit);
   }
-  void put_d_reg(int idx, jlong val) {
-    int ofst = num_s_regs() * 4 + idx * 8;
-    (*(jlong *) (data_start() + ofst)) = val;
-  }
-  jint get_stackslot32(int stackOffset) {
-    int ofst = num_s_regs() * 4 + num_d_regs() * 8 + stackOffset;
-    return(*(jint *) (data_start() + ofst));
-  }
-  jlong get_stackslot64(int stackOffset) {
-    int ofst = num_s_regs() * 4 + num_d_regs() * 8 + stackOffset;
-    return(*(jlong *) (data_start() + ofst));
-  }
-  void put_stackslot64(int stackOffset, jlong val) {
-    int ofst = num_s_regs() * 4 + num_d_regs() * 8 + stackOffset;
-    (*(jlong *) (data_start() + ofst)) = val;
+    
+  // do the oops from this frame
+  void oops_do(OopClosure* f, HSAILOopMapHelper* oopMapHelper) {
+    int oops_per_deopt = num_d_regs() + num_stack_slots();
+
+    // handle the dregister and stackSlot based oops
+    for (int bit = 0; bit < oops_per_deopt; bit++) {
+      if (oopMapHelper->is_oop(pc_offset(), bit)) {
+        void* oop_ptr = get_oop_ptr_for_bit(bit);
+        // the oops we are dealing with here in the hsailFrame are always uncompressed
+        oop old_oop = oopDesc::load_heap_oop((oop *)oop_ptr);
+        f->do_oop((oop*) oop_ptr);
+        if (TraceGPUInteraction) {
+          oop new_oop = oopDesc::load_heap_oop((oop *)oop_ptr);
+          tty->print_cr("bit=%d, oop_ptr=%p, old=%p, new=%p", bit, oop_ptr, (void *)old_oop, (void *)new_oop);
+        }
+      }
+    }
   }
 };
   
-#endif // GPU_HSAIL_FRAME_HPP
+#endif // GPU_HSAIL_VM_GPU_HSAIL_FRAME_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/hsail/vm/gpu_hsail_OopMapHelper.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef GPU_HSAIL_VM_GPU_HSAIL_OOPMAPHELPER_HPP
+#define GPU_HSAIL_VM_GPU_HSAIL_OOPMAPHELPER_HPP
+
+#include "graal/graalEnv.hpp"
+#include "code/debugInfo.hpp"
+#include "code/location.hpp"
+
+// Takes the jobject for the array of ints created by the java side
+// and decodes the information based on pc_offset to find oops
+class HSAILOopMapHelper : public StackObj {
+private:
+  jobject _oop_map_array_jobject;
+  typeArrayOop _oop_map_array;
+  int _last_pcoffset;
+  int _last_idx;
+
+  enum {
+    SAVEAREACOUNTS_OFST=0,
+    SPAN_OFST=1,
+    HEADERSIZE=2
+  }; 
+  int mapPcOffsetToIndex(int pcOffset) {
+    if (pcOffset == _last_pcoffset) {
+      return _last_idx;
+    }
+    int span = _oop_map_array->int_at(SPAN_OFST);
+    for (int idx = HEADERSIZE; idx < _oop_map_array->length(); idx += span) {
+      int ofst = _oop_map_array->int_at(idx);
+      if (ofst == pcOffset) {
+        _last_pcoffset = pcOffset;
+        _last_idx = idx + 1;
+        return _last_idx;
+      }
+    }
+    ShouldNotReachHere();
+    return -1;
+  }
+
+public:
+  HSAILOopMapHelper(jobject oop_map_array_jobject) {
+    _oop_map_array_jobject = oop_map_array_jobject;
+    _last_pcoffset = -1;
+    resolve_arrays();
+  }
+ 
+  void resolve_arrays() {
+    _oop_map_array = (typeArrayOop) JNIHandles::resolve(_oop_map_array_jobject);
+  }
+
+  static int get_save_area_counts(jobject oop_map_array_jobject) {
+    typeArrayOop oop_map_array_resolved = (typeArrayOop) JNIHandles::resolve(oop_map_array_jobject);
+    return oop_map_array_resolved->int_at(SAVEAREACOUNTS_OFST);
+  }
+
+  bool is_oop(int pcOffset, int bit){
+    int bits_int_idx = mapPcOffsetToIndex(pcOffset) + (bit / 32);
+    int bitpos = bit % 32;
+    int bits = _oop_map_array->int_at(bits_int_idx);
+    return ((bits & (1 << bitpos)) != 0);
+  }
+
+};
+
+#endif // GPU_HSAIL_VM_GPU_HSAIL_OOPMAPHELPER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/hsail/vm/gpu_hsail_Tlab.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef GPU_HSAIL_VM_GPU_HSAIL_TLAB_HPP
+#define GPU_HSAIL_VM_GPU_HSAIL_TLAB_HPP
+
+#include "graal/graalEnv.hpp"
+#include "code/debugInfo.hpp"
+#include "code/location.hpp"
+#include "gpu_hsail.hpp"
+
+class HSAILAllocationInfo;
+
+class HSAILTlabInfo VALUE_OBJ_CLASS_SPEC {
+  friend class VMStructs;
+public:
+  // uses only the necessary fields from a full TLAB
+  HeapWord* _start;
+  HeapWord* _top;
+  HeapWord* _end;
+  HeapWord* _last_good_top;
+  HeapWord* _original_top;
+  JavaThread* _donor_thread;         // donor thread associated with this tlabInfo
+  HSAILAllocationInfo* _alloc_info;   // same as what is in HSAILDeoptimizationInfo
+
+  // Accessors
+  HeapWord* start() { return _start; }
+  HeapWord* top() { return _top; }
+  HeapWord* end() { return _end; }
+  HeapWord* last_good_top() { return _last_good_top; }
+  HeapWord* original_top() { return _original_top; }
+  void initialize(HeapWord* start, HeapWord* top, HeapWord* end, JavaThread* donorThread, HSAILAllocationInfo* allocInfo) {
+    _start = start;
+    _top = _original_top = top;
+    _end = end;
+    _donor_thread = donorThread;
+    _alloc_info = allocInfo;
+  }
+};
+
+
+class HSAILAllocationInfo : public CHeapObj<mtInternal> {
+  friend class VMStructs;
+private:
+  JavaThread** donorThreads;
+  jint _num_donor_threads;
+  size_t _tlab_align_reserve_bytes;    // filled in from ThreadLocalAllocBuffer::alignment_reserve_in_bytes()
+  HSAILTlabInfo** _cur_tlab_infos;    // array of current tlab info pointers, one per donor_thread
+  HSAILTlabInfo* _tlab_infos_pool_start;    // pool for new tlab_infos
+  HSAILTlabInfo* _tlab_infos_pool_next;     // where next will be allocated from
+  HSAILTlabInfo* _tlab_infos_pool_end;      // where next will be allocated from
+
+public:
+  HSAILAllocationInfo(jobject donor_threads_jobj, int dimX, int allocBytesPerWorkitem) {
+    // fill in the donorThreads array
+    objArrayOop donorThreadObjects = (objArrayOop) JNIHandles::resolve(donor_threads_jobj);
+    _num_donor_threads = donorThreadObjects->length();
+    guarantee(_num_donor_threads > 0, "need at least one donor thread");
+    donorThreads = NEW_C_HEAP_ARRAY(JavaThread*, _num_donor_threads, mtInternal);
+    for (int i = 0; i < _num_donor_threads; i++) {
+      donorThreads[i] = java_lang_Thread::thread(donorThreadObjects->obj_at(i));
+    }
+    
+    // Compute max_tlab_infos based on amount of free heap space
+    size_t max_tlab_infos;
+    {
+      JavaThread* donorThread = donorThreads[0];
+      ThreadLocalAllocBuffer* tlab = &donorThread->tlab();
+      size_t new_tlab_size = tlab->compute_size(0);
+      size_t heap_bytes_free = Universe::heap()->unsafe_max_tlab_alloc(donorThread);
+      if (new_tlab_size != 0) {
+        max_tlab_infos = MIN2(heap_bytes_free / new_tlab_size, (size_t)(64 * _num_donor_threads));
+      } else {
+        max_tlab_infos = 8 * _num_donor_threads;   // an arbitrary multiple
+      }
+      if (TraceGPUInteraction) {
+        tty->print_cr("heapFree = %ld, newTlabSize=%ld, tlabInfos allocated = %ld", heap_bytes_free, new_tlab_size, max_tlab_infos);
+      }
+    }
+
+    _cur_tlab_infos = NEW_C_HEAP_ARRAY(HSAILTlabInfo*, _num_donor_threads, mtInternal);
+    _tlab_infos_pool_start = NEW_C_HEAP_ARRAY(HSAILTlabInfo, max_tlab_infos, mtInternal);
+    _tlab_infos_pool_next = &_tlab_infos_pool_start[_num_donor_threads];
+    _tlab_infos_pool_end = &_tlab_infos_pool_start[max_tlab_infos];
+    _tlab_align_reserve_bytes = ThreadLocalAllocBuffer::alignment_reserve_in_bytes();
+      
+    // we will fill the first N tlabInfos from the donor threads
+    for (int i = 0; i < _num_donor_threads; i++) {
+      JavaThread* donorThread = donorThreads[i];
+      ThreadLocalAllocBuffer* tlab = &donorThread->tlab();
+      if (TraceGPUInteraction) {
+        tty->print("donorThread %d, is %p, tlab at %p -> ", i, donorThread, tlab);
+        printTlabInfoFromThread(tlab);
+      }
+      
+      // Here we try to get a new tlab if current one is null. Note:
+      // eventually we may want to test if the size is too small based
+      // on some heuristic where we see how much this kernel tends to
+      // allocate, but for now we can just let it overflow and let the
+      // GPU allocate new tlabs. Actually, if we can't prime a tlab
+      // here, it might make sense to do a gc now rather than to start
+      // the kernel and have it deoptimize.  How to do that?
+      if (tlab->end() == NULL) {
+        bool success = getNewTlabForDonorThread(tlab, i);
+        if (TraceGPUInteraction) {
+          if (success) {
+            tty->print("donorThread %d, refilled tlab, -> ", i);
+            printTlabInfoFromThread(tlab);
+          } else {
+            tty->print("donorThread %d, could not refill tlab, left as ", i);
+            printTlabInfoFromThread(tlab);
+          }
+        }
+      }
+
+      // extract the necessary tlab fields into a TlabInfo record
+      HSAILTlabInfo* pTlabInfo = &_tlab_infos_pool_start[i];
+      _cur_tlab_infos[i] = pTlabInfo;
+      pTlabInfo->initialize(tlab->start(), tlab->top(), tlab->end(), donorThread, this);
+    }
+  }
+
+  ~HSAILAllocationInfo() {
+    FREE_C_HEAP_ARRAY(HSAILTlabInfo*, _cur_tlab_infos, mtInternal);
+    FREE_C_HEAP_ARRAY(HSAILTlabInfo, _tlab_infos_pool_start, mtInternal);
+    FREE_C_HEAP_ARRAY(JavaThread*, donorThreads, mtInternal);
+  }
+
+  void postKernelCleanup() {
+    // go thru all the tlabInfos, fix up any tlab tops that overflowed
+    // complete the tlabs if they overflowed
+    // update the donor threads tlabs when appropriate
+    bool anyOverflows = false;
+    size_t bytesAllocated = 0;
+    // if there was an overflow in allocating tlabInfos, correct it here
+    if (_tlab_infos_pool_next > _tlab_infos_pool_end) {
+      if (TraceGPUInteraction) {
+        int overflowAmount = _tlab_infos_pool_next - _tlab_infos_pool_end;
+        tty->print_cr("tlabInfo allocation overflowed by %d units", overflowAmount);
+      }
+      _tlab_infos_pool_next = _tlab_infos_pool_end;
+    }
+    for (HSAILTlabInfo* tlabInfo = _tlab_infos_pool_start; tlabInfo < _tlab_infos_pool_next; tlabInfo++) {
+      if (TraceGPUInteraction) {
+        tty->print_cr("postprocess tlabInfo %p, start=%p, top=%p, end=%p, last_good_top=%p", tlabInfo, 
+                      tlabInfo->start(), tlabInfo->top(), tlabInfo->end(), tlabInfo->last_good_top());
+      }
+      JavaThread* donorThread = tlabInfo->_donor_thread;
+      ThreadLocalAllocBuffer* tlab = &donorThread->tlab();
+      bool overflowed = false;
+      // if a tlabInfo has NULL fields, i.e. we could not prime it on entry,
+      // or we could not get a tlab from the gpu, so ignore tlabInfo here
+      if (tlabInfo->start() != NULL) {
+        if (tlabInfo->top() > tlabInfo->end()) {
+          anyOverflows = true;
+          overflowed = true;
+          if (TraceGPUInteraction) {
+            long overflowAmount = (long) tlabInfo->top() - (long) tlabInfo->last_good_top(); 
+            tty->print_cr("tlabInfo %p (donorThread = %p) overflowed by %ld bytes, setting last good top to %p", tlabInfo, donorThread, overflowAmount, tlabInfo->last_good_top());
+          }
+          tlabInfo->_top = tlabInfo->last_good_top();
+        }
+
+        // fill the donor thread tlab with the tlabInfo information
+        // we do this even if it will get overwritten by a later tlabinfo
+        // because it helps with tlab statistics for that donor thread
+        tlab->fill(tlabInfo->start(), tlabInfo->top(), (tlabInfo->end() - tlabInfo->start()) + tlab->alignment_reserve());
+
+        // if there was an overflow, make it parsable with retire = true
+        if (overflowed) {
+          tlab->make_parsable(true);
+        }
+        
+        size_t delta = (long)(tlabInfo->top()) - (long)(tlabInfo->original_top());
+        if (TraceGPUInteraction) {
+          tty->print_cr("%ld bytes were allocated by tlabInfo %p (start %p, top %p, end %p", delta, tlabInfo,
+                        tlabInfo->start(), tlabInfo->top(), tlabInfo->end());
+        }
+        bytesAllocated += delta;
+      }
+    }
+    if (TraceGPUInteraction) {
+      tty->print_cr("%ld total bytes were allocated in this kernel", bytesAllocated);
+    }
+    if (anyOverflows) {
+      // Hsail::kernelStats.incOverflows();
+    }
+  }
+
+  HSAILTlabInfo** getCurTlabInfos() {
+    return _cur_tlab_infos;
+  }
+
+private:
+  // fill and retire old tlab and get a new one
+  // if we can't get one, no problem someone will eventually do a gc
+  bool getNewTlabForDonorThread(ThreadLocalAllocBuffer* tlab, int idx) {
+
+    tlab->clear_before_allocation();    // fill and retire old tlab (will also check for null)
+    
+    // get a size for a new tlab that is based on the desired_size
+    size_t new_tlab_size = tlab->compute_size(0);
+    if (new_tlab_size == 0) return false;
+    
+    HeapWord* tlab_start = Universe::heap()->allocate_new_tlab(new_tlab_size);
+    if (tlab_start == NULL) return false;
+    
+    // ..and clear it if required
+    if (ZeroTLAB) {
+      Copy::zero_to_words(tlab_start, new_tlab_size);
+    }
+    // and init the tlab pointers
+    tlab->fill(tlab_start, tlab_start, new_tlab_size);
+    return true;
+  }
+  
+  void printTlabInfoFromThread (ThreadLocalAllocBuffer* tlab) {
+    HeapWord* start = tlab->start();
+    HeapWord* top = tlab->top();
+    HeapWord* end = tlab->end();
+    // sizes are in bytes
+    size_t tlabFree = tlab->free() * HeapWordSize;
+    size_t tlabUsed = tlab->used() * HeapWordSize;
+    size_t tlabSize = tlabFree + tlabUsed;
+    double freePct = 100.0 * (double) tlabFree/(double) tlabSize;
+    tty->print_cr("(%p, %p, %p), siz=%ld, free=%ld (%f%%)", start, top, end, tlabSize, tlabFree, freePct);
+  }
+  
+};
+  
+#endif // GPU_HSAIL_VM_GPU_HSAIL_TLAB_HPP
--- a/src/gpu/hsail/vm/hsailArgumentsBase.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/gpu/hsail/vm/hsailArgumentsBase.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -38,6 +38,29 @@
   return arg;
 }
 
+void HSAILArgumentsBase::collectArgs() {
+  if (TraceGPUInteraction) {
+    tty->print_cr("[HSAIL] %s::collectArgs, sig:%s  args length=%d", argsBuilderName(), _signature->as_C_string(), _length);
+  }
+  if (!_is_static) {
+    // First object in args should be 'this'
+    oop arg = _args->obj_at(_index++);
+    assert(arg->is_instance() && (!arg->is_array()), "First arg should be 'this'");
+    if (TraceGPUInteraction) {
+      tty->print_cr("[HSAIL] %s, instance method, this " PTR_FORMAT ", is a %s", argsBuilderName(), (address) arg, arg->klass()->external_name());
+    }
+    pushObject(arg);
+  } else {
+    if (TraceGPUInteraction) {
+      tty->print_cr("[HSAIL] %s, static method", argsBuilderName());
+    }
+  }
+  // Iterate over the entire signature
+  iterate();
+
+  pushTrailingArgs();
+}
+
 void HSAILArgumentsBase::do_bool() {
   // Get the boxed value
   oop arg = _args->obj_at(_index++);
--- a/src/gpu/hsail/vm/hsailArgumentsBase.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/gpu/hsail/vm/hsailArgumentsBase.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -22,19 +22,16 @@
  *
  */
 
-#ifndef BASE_ARGUMENTS_HSAIL_HPP
-#define BASE_ARGUMENTS_HSAIL_HPP
+#ifndef GPU_HSAIL_VM_HSAIL_ARGUMENTS_BASE_HPP
+#define GPU_HSAIL_VM_HSAIL_ARGUMENTS_BASE_HPP
 
 #include "runtime/signature.hpp"
 
 
-/***
- * Base class which iterates thru a signature and pulls from a
- * objArrayOop of boxed values.  Used as base for HSAILKernelArguments
- * and HSAILJavaCallArguments The derived classes specify how to push
- * args onto their data structure
- ***/
-
+// Base class which iterates thru a signature and pulls from a
+// objArrayOop of boxed values.  Used as base for HSAILKernelArguments
+// and HSAILJavaCallArguments The derived classes specify how to push
+// args onto their data structure
 class HSAILArgumentsBase : public SignatureIterator {
 
 public:
@@ -49,7 +46,7 @@
   // number of parameters in the signature
   int _parameter_count;
 
-  Symbol * _signature;
+  Symbol* _signature;
   bool _is_static;
 
   // records first null parameter seen
@@ -58,8 +55,8 @@
   // Get next java argument
   oop next_arg(BasicType expectedType);
 
-    virtual char *argsBuilderName() = 0;
-    virtual void pushObject(void * obj) = 0;
+    virtual char* argsBuilderName() = 0;
+    virtual void pushObject(void* obj) = 0;
     virtual void pushBool(jboolean z) = 0;
     virtual void pushByte(jbyte b) = 0;
     virtual void pushDouble(jdouble d) = 0;
@@ -67,13 +64,9 @@
     virtual void pushInt(jint i) = 0;
     virtual void pushLong(jlong j) = 0;
     virtual void handleFinalIntParameter() = 0;
-    virtual void handleFinalObjParameter(void *obj) = 0;
+    virtual void handleFinalObjParameter(void* obj) = 0;
     virtual void pushTrailingArgs() = 0;
 
-    void recordNullObjectParameter() {
-        if (_first_null_parameter_index == -1) _first_null_parameter_index = _parameter_index;
-    }
-
  public:
   HSAILArgumentsBase(Symbol* signature, objArrayOop args, bool is_static) : SignatureIterator(signature) {
     this->_return_type = T_ILLEGAL;
@@ -89,32 +82,29 @@
 
   }
 
+  void recordNullObjectParameter() {
+    if (_first_null_parameter_index == -1) {
+      _first_null_parameter_index = _parameter_index;
+    }
+  }
+
+  bool is_static() {
+    return _is_static;
+  }
+
+  int length() {
+    return _length;
+  }
+
+  objArrayOop args() {
+    return _args;
+  }
+
   int getFirstNullParameterIndex() {
     return _first_null_parameter_index;
   }
 
-  void collectArgs() {
-    if (TraceGPUInteraction) {
-      tty->print_cr("[HSAIL] %s::collectArgs, sig:%s  args length=%d", argsBuilderName(), _signature->as_C_string(), _length);
-    }    
-    if (!_is_static) {      
-      // First object in args should be 'this'
-      oop arg = _args->obj_at(_index++);
-      assert(arg->is_instance() && (! arg->is_array()), "First arg should be 'this'");
-      if (TraceGPUInteraction) {
-        tty->print_cr("[HSAIL] %s, instance method, this " PTR_FORMAT ", is a %s", argsBuilderName(), (address) arg, arg->klass()->external_name());
-      }
-      pushObject(arg);
-    } else {
-      if (TraceGPUInteraction) {
-          tty->print_cr("[HSAIL] %s, static method", argsBuilderName());
-      }
-    }
-    // Iterate over the entire signature
-    iterate();
-    
-    pushTrailingArgs();
-  }
+  virtual void collectArgs();
 
   void do_bool();
   void do_byte();
@@ -143,4 +133,4 @@
 
 };
 
-#endif  // BASE_ARGUMENTS_HSAIL_HPP
+#endif  // GPU_HSAIL_VM_HSAIL_ARGUMENTS_BASE_HPP
--- a/src/gpu/hsail/vm/hsailJavaCallArguments.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/gpu/hsail/vm/hsailJavaCallArguments.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -22,8 +22,8 @@
  *
  */
 
-#ifndef JAVACALL_ARGUMENTS_HSAIL_HPP
-#define JAVACALL_ARGUMENTS_HSAIL_HPP
+#ifndef GPU_HSAIL_VM_HSAIL_JAVACALL_ARGUMENTS_HPP
+#define GPU_HSAIL_VM_HSAIL_JAVACALL_ARGUMENTS_HPP
 
 #include "hsailArgumentsBase.hpp"
 #include "runtime/javaCalls.hpp"
@@ -33,17 +33,17 @@
 public:
 
 private:
-  // JavaCall Args to push into
-  JavaCallArguments *_javaArgs;
+  // JavaCall args to push into
+  JavaCallArguments* _javaArgs;
   int _workitemid;
  public:
-    HSAILJavaCallArguments(JavaCallArguments *javaArgs, int workitemid, Symbol* signature, objArrayOop args, bool is_static) : HSAILArgumentsBase(signature, args, is_static) {
+    HSAILJavaCallArguments(JavaCallArguments* javaArgs, int workitemid, Symbol* signature, objArrayOop args, bool is_static) : HSAILArgumentsBase(signature, args, is_static) {
         _javaArgs = javaArgs;
         _workitemid = workitemid;
         collectArgs();
     }
-    virtual char *argsBuilderName() {return (char *)"HSAILJavaCallArguments";}
-    virtual void pushObject(void *obj) { _javaArgs->push_oop((oop) obj);  }
+    virtual char* argsBuilderName() {return (char*)"HSAILJavaCallArguments";}
+    virtual void pushObject(void* obj) { _javaArgs->push_oop((oop) obj);  }
     virtual void pushBool(jboolean z) { pushInt(z); }
     virtual void pushByte(jbyte b) { pushInt(b); }
     virtual void pushDouble(jdouble d) { _javaArgs->push_double(d); }
@@ -64,7 +64,7 @@
     // stream source array (already checked in the base class) so for
     // a javacall we need to extract the correct obj from it based on
     // the workitemid
-    virtual void handleFinalObjParameter(void *arg) {
+    virtual void handleFinalObjParameter(void* arg) {
       objArrayOop objArrayArg = (objArrayOop) arg;
       oop extractedObj = objArrayArg->obj_at(_workitemid);
       if (TraceGPUInteraction) {
@@ -77,5 +77,5 @@
 
 };
 
-#endif  // JAVACALL_ARGUMENTS_HSAIL_HPP
+#endif  // GPU_HSAIL_VM_HSAIL_JAVACALL_ARGUMENTS_HPP
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/hsail/vm/hsailKernelArguments.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "hsailKernelArguments.hpp"
+
+void HSAILKernelArguments::collectArgs() {
+  int index = 0;
+  if (TraceGPUInteraction) {
+    tty->print_cr("[HSAIL] %s::collectArgs, args length=%d", argsBuilderName(), length());
+  }
+
+  // Manually iterate over the actual args array without looking at method signature
+  while (index < length()) {
+    oop arg = args()->obj_at(index++);
+    jvalue jValue;
+    if (arg == NULL) {
+      if (TraceGPUInteraction) {
+        tty->print_cr("[HSAIL] %s::collectArgs object, _index=%d, value = " PTR_FORMAT " is a %s", argsBuilderName(), index, (void*) arg, "null");
+      }
+      recordNullObjectParameter();
+      pushObject(arg);
+    } else {
+      java_lang_boxing_object::get_value(arg, &jValue);
+      BasicType basic_type = java_lang_boxing_object::basic_type(arg);
+      if (basic_type == T_ILLEGAL && (!(arg->is_array()))) {
+        if (TraceGPUInteraction) {
+          tty->print_cr("[HSAIL] %s::collectArgs object, _index=%d, value = " PTR_FORMAT " is a %s", argsBuilderName(), index, (void*) arg, arg == NULL ? "null" : arg->klass()->external_name());
+        }
+        pushObject(arg);
+      } else if (arg->is_array()) {
+        if (TraceGPUInteraction) {
+          int array_length = ((objArrayOop) arg)->length();
+          tty->print_cr("[HSAIL] %s::collectArgs array, length=%d, _index=%d, value = " PTR_FORMAT, argsBuilderName(), array_length, index, (void*) arg);
+        }
+        pushObject(arg);
+      } else {
+        switch (basic_type) {
+          case T_INT:
+            if (TraceGPUInteraction) {
+              tty->print_cr("[HSAIL] %s::collectArgs, T_INT _index=%d, value = %d", argsBuilderName(), index, jValue.i);
+            }
+            pushInt(jValue.i);
+            break;
+          case T_LONG:
+            if (TraceGPUInteraction) {
+              tty->print_cr("[HSAIL] %s::collectArgs, T_LONG _index=%d, value = %d", argsBuilderName(), index, jValue.j);
+            }
+            pushLong(jValue.j);
+            break;
+          case T_FLOAT:
+            if (TraceGPUInteraction) {
+              tty->print_cr("[HSAIL] %s::collectArgs, T_FLOAT _index=%d, value = %d", argsBuilderName(), index, jValue.f);
+            }
+            pushFloat(jValue.f);
+            break;
+          case T_DOUBLE:
+            if (TraceGPUInteraction) {
+              tty->print_cr("[HSAIL] %s::collectArgs, T_DOUBLE _index=%d, value = %d", argsBuilderName(), index, jValue.d);
+            }
+            pushDouble(jValue.d);
+            break;
+          case T_BYTE:
+            if (TraceGPUInteraction) {
+              tty->print_cr("[HSAIL] %s::collectArgs, T_BYTE _index=%d, value = %d", argsBuilderName(), index, jValue.b);
+            }
+            pushByte(jValue.b);
+            break;
+          case T_BOOLEAN:
+            if (TraceGPUInteraction) {
+              tty->print_cr("[HSAIL] %s::collectArgs, T_BOOLEAN _index=%d, value = %d", argsBuilderName(), index, jValue.z);
+            }
+            pushBool(jValue.z);
+            break;
+        }
+      }
+    }
+  }
+
+  pushTrailingArgs();
+}
+
--- a/src/gpu/hsail/vm/hsailKernelArguments.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/gpu/hsail/vm/hsailKernelArguments.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -22,8 +22,8 @@
  *
  */
 
-#ifndef KERNEL_ARGUMENTS_HSAIL_HPP
-#define KERNEL_ARGUMENTS_HSAIL_HPP
+#ifndef GPU_HSAIL_VM_HSAIL_KERNEL_ARGUMENTS_HPP
+#define GPU_HSAIL_VM_HSAIL_KERNEL_ARGUMENTS_HPP
 
 #include "gpu_hsail.hpp"
 #include "runtime/signature.hpp"
@@ -37,7 +37,7 @@
 private:
   // Kernel to push into
   address _kernel;
-  void * _exceptionHolder;
+  void* _exceptionHolder;
 
  public:
     HSAILKernelArguments(address kernel, Symbol* signature, objArrayOop args, bool is_static, void* exceptionHolder) : HSAILArgumentsBase(signature, args, is_static) {
@@ -45,8 +45,8 @@
         _exceptionHolder = exceptionHolder;
         collectArgs();
     }
-    virtual char *argsBuilderName() {return (char *)"HSAILKernelArguments";}
-    virtual void pushObject(void *obj) {
+    virtual char* argsBuilderName() {return (char*)"HSAILKernelArguments";}
+    virtual void pushObject(void* obj) {
         bool pushed = Hsail::_okra_push_object(_kernel, obj);
         assert(pushed == true, "arg push failed");
     }
@@ -91,16 +91,17 @@
     // For kernel arguments we don't pass the final int parameter
     // since we use the HSAIL workitemid instruction in place of that int value
     virtual void handleFinalIntParameter() {
-      if (TraceGPUInteraction) {
-        tty->print_cr("[HSAIL] HSAILKernelArguments, not pushing trailing int");
-      }
+      ShouldNotReachHere();
     }
 
-    // for kernel arguments, final obj parameter should be an object
+    // For kernel arguments, final obj parameter should be an object
     // stream source array (already checked in the base class) so here we just pass it
-    virtual void handleFinalObjParameter(void *arg) {
-      pushObject(arg);
+    virtual void handleFinalObjParameter(void* arg) {
+      ShouldNotReachHere();
     }
+
+    virtual void collectArgs();
+
 };
 
-#endif  // KERNEL_ARGUMENTS_HSAIL_HPP
+#endif  // GPU_HSAIL_VM_HSAIL_KERNEL_ARGUMENTS_HPP
--- a/src/gpu/hsail/vm/vmStructs_hsail.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/gpu/hsail/vm/vmStructs_hsail.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -41,16 +41,32 @@
   nonstatic_field(Hsail::HSAILKernelDeoptimization, _workitemid,                                jint)                                 \
   nonstatic_field(Hsail::HSAILKernelDeoptimization, _actionAndReason,                           jint)                                 \
                                                                                                                                       \
-  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _notice_safepoints,                      jint*)                                     \
+  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _notice_safepoints,                      jint*) \
   nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_occurred,                         jint)                                      \
   nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_next_index,                       jint)                                      \
-  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _donor_threads,                          JavaThread**)                              \
-  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _never_ran_array,                        jboolean *)                                \
+  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _cur_tlab_info,                          HSAILTlabInfo**)                           \
+  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _alloc_info,                             HSAILAllocationInfo*)                      \
+  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _never_ran_array,                        jboolean*)                                 \
+                                                                                                                                      \
+  nonstatic_field(HSAILAllocationInfo, _tlab_infos_pool_start,                             HSAILTlabInfo*)                            \
+  nonstatic_field(HSAILAllocationInfo, _tlab_infos_pool_next,                              HSAILTlabInfo*)                            \
+  nonstatic_field(HSAILAllocationInfo, _tlab_infos_pool_end,                               HSAILTlabInfo*)                            \
+  nonstatic_field(HSAILAllocationInfo, _tlab_align_reserve_bytes,                          size_t)                                    \
+                                                                                                                                      \
+  nonstatic_field(HSAILTlabInfo, _start,                                                   HeapWord*)                                 \
+  nonstatic_field(HSAILTlabInfo, _top,                                                     HeapWord*)                                 \
+  nonstatic_field(HSAILTlabInfo, _end,                                                     HeapWord*)                                 \
+  nonstatic_field(HSAILTlabInfo, _last_good_top,                                           HeapWord*)                                 \
+  nonstatic_field(HSAILTlabInfo, _original_top,                                            HeapWord*)                                 \
+  nonstatic_field(HSAILTlabInfo, _donor_thread,                                            JavaThread*)                               \
+  nonstatic_field(HSAILTlabInfo, _alloc_info,                                              HSAILAllocationInfo*)                      \
 
-#define VM_TYPES_GPU_HSAIL(declare_type, declare_toplevel_type)                 \
+#define VM_TYPES_GPU_HSAIL(declare_type, declare_toplevel_type)      \
   declare_toplevel_type(HSAILFrame)                                  \
   declare_toplevel_type(HSAILFrame*)                                 \
   declare_toplevel_type(Hsail::HSAILKernelDeoptimization)            \
+  declare_toplevel_type(HSAILAllocationInfo)                         \
+  declare_toplevel_type(HSAILTlabInfo)                               \
   declare_toplevel_type(Hsail::HSAILDeoptimizationInfo)
 
 #endif // GPU_HSAIL_VM_VMSTRUCTS_HSAIL_HPP
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java	Mon Jun 30 12:02:19 2014 +0200
@@ -68,29 +68,31 @@
     private final int from;
     private final int to;
     private final String label;
+    private final String type;
     private State state;
 
     public InputEdge(char toIndex, int from, int to) {
-        this((char) 0, toIndex, from, to, null);
+        this((char) 0, toIndex, from, to, null, null);
     }
 
     public InputEdge(char fromIndex, char toIndex, int from, int to) {
-        this(fromIndex, toIndex, from, to, null);
+        this(fromIndex, toIndex, from, to, null, null);
     }
 
-    public InputEdge(char fromIndex, char toIndex, int from, int to, String label) {
+    public InputEdge(char fromIndex, char toIndex, int from, int to, String label, String type) {
         this.toIndex = toIndex;
         this.fromIndex = fromIndex;
         this.from = from;
         this.to = to;
         this.state = State.SAME;
         this.label = label;
+        this.type = type;
     }
 
     static WeakHashMap<InputEdge, WeakReference<InputEdge>> immutableCache = new WeakHashMap<>();
 
-    public static synchronized InputEdge createImmutable(char fromIndex, char toIndex, int from, int to, String label) {
-        InputEdge edge = new InputEdge(fromIndex, toIndex, from, to, label, State.IMMUTABLE);
+    public static synchronized InputEdge createImmutable(char fromIndex, char toIndex, int from, int to, String label, String type) {
+        InputEdge edge = new InputEdge(fromIndex, toIndex, from, to, label, type, State.IMMUTABLE);
         WeakReference<InputEdge> result = immutableCache.get(edge);
         if (result != null) {
             InputEdge edge2 = result.get();
@@ -102,13 +104,14 @@
         return edge;
     }
 
-    public InputEdge(char fromIndex, char toIndex, int from, int to, String label, State state) {
+    public InputEdge(char fromIndex, char toIndex, int from, int to, String label, String type, State state) {
         this.toIndex = toIndex;
         this.fromIndex = fromIndex;
         this.from = from;
         this.to = to;
         this.state = state;
         this.label = label;
+        this.type = type;
     }
 
     public State getState() {
@@ -145,6 +148,10 @@
     public String getLabel() {
         return label;
     }
+    
+    public String getType() {
+        return type;
+    }
 
     @Override
     public boolean equals(Object o) {
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Mon Jun 30 12:02:19 2014 +0200
@@ -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
@@ -215,12 +215,20 @@
         }
     }
     
+    private static class TypedPort extends Port {
+        public final EnumValue type;
+        private TypedPort(boolean isList, String name, EnumValue type) {
+            super(isList, name);
+            this.type = type;
+        }
+    }
+    
     private static class NodeClass {
         public final String className;
         public final String nameTemplate;
-        public final List<Port> inputs;
+        public final List<TypedPort> inputs;
         public final List<Port> sux;
-        private NodeClass(String className, String nameTemplate, List<Port> inputs, List<Port> sux) {
+        private NodeClass(String className, String nameTemplate, List<TypedPort> inputs, List<Port> sux) {
             this.className = className;
             this.nameTemplate = nameTemplate;
             this.inputs = inputs;
@@ -464,11 +472,12 @@
                 String className = readString();
                 String nameTemplate = readString();
                 int inputCount = readShort();
-                List<Port> inputs = new ArrayList<>(inputCount);
+                List<TypedPort> inputs = new ArrayList<>(inputCount);
                 for (int i = 0; i < inputCount; i++) {
                     boolean isList = readByte() != 0;
                     String name = readPoolObject(String.class);
-                    inputs.add(new Port(isList, name));
+                    EnumValue inputType = readPoolObject(EnumValue.class);
+                    inputs.add(new TypedPort(isList, name, inputType));
                 }
                 int suxCount = readShort();
                 List<Port> sux = new ArrayList<>(suxCount);
@@ -726,20 +735,20 @@
             }
             int edgesStart = edges.size();
             int portNum = 0;
-            for (Port p : nodeClass.inputs) {
+            for (TypedPort p : nodeClass.inputs) {
                 if (p.isList) {
                     int size = readShort();
                     for (int j = 0; j < size; j++) {
                         int in = readInt();
                         if (in >= 0) {
-                            edges.add(new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", true));
+                            edges.add(new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", p.type.toString(Length.S), true));
                             portNum++;
                         }
                     }
                 } else {
                     int in = readInt();
                     if (in >= 0) {
-                        edges.add(new Edge(in, id, (char) (preds + portNum), p.name, true));
+                        edges.add(new Edge(in, id, (char) (preds + portNum), p.name, p.type.toString(Length.S), true));
                         portNum++;
                     }
                 }
@@ -752,14 +761,14 @@
                     for (int j = 0; j < size; j++) {
                         int sux = readInt();
                         if (sux >= 0) {
-                            edges.add(new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", false));
+                            edges.add(new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", "Successor", false));
                             portNum++;
                         }
                     }
                 } else {
                     int sux = readInt();
                     if (sux >= 0) {
-                        edges.add(new Edge(id, sux, (char) portNum, p.name, false));
+                        edges.add(new Edge(id, sux, (char) portNum, p.name, "Successor", false));
                         portNum++;
                     }
                 }
@@ -780,7 +789,7 @@
         for (Edge e : edges) {
             char fromIndex = e.input ? 1 : e.num;
             char toIndex = e.input ? e.num : 0;
-            graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label));
+            graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label, e.type));
         }
     }
     
@@ -845,14 +854,16 @@
         final int to;
         final char num;
         final String label;
+        final String type;
         final boolean input;
         public Edge(int from, int to) {
-            this(from, to, (char) 0, null, false);
+            this(from, to, (char) 0, null, null, false);
         }
-        public Edge(int from, int to, char num, String label, boolean input) {
+        public Edge(int from, int to, char num, String label, String type, boolean input) {
             this.from = from;
             this.to = to;
             this.label = label != null ? label.intern() : label;
+            this.type = type != null ? type.intern() : type;
             this.num = num;
             this.input = input;
         }
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Mon Jun 30 12:02:19 2014 +0200
@@ -410,7 +410,7 @@
                 throw new SAXException(e);
             }
 
-            InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label);
+            InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label, "");
             return start(conn);
         }
 
--- a/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java	Mon Jun 30 12:02:19 2014 +0200
@@ -211,7 +211,7 @@
             if (nodeFrom == null || nodeTo == null) {
                 System.out.println("Unexpected edge : " + from + " -> " + to);
             } else {
-                InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId());
+                InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId(), e.getLabel(), e.getType());
                 if (!newEdges.contains(newEdge)) {
                     markAsDeleted(newEdge);
                     newEdges.add(newEdge);
@@ -231,7 +231,7 @@
             if (nodeFrom == null || nodeTo == null) {
                 System.out.println("Unexpected edge : " + from + " -> " + to);
             } else {
-                InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId());
+                InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId(), e.getLabel(), e.getType());
                 if (!newEdges.contains(newEdge)) {
                     markAsNew(newEdge);
                     newEdges.add(newEdge);
--- a/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CombineFilter.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CombineFilter.java	Mon Jun 30 12:02:19 2014 +0200
@@ -97,7 +97,7 @@
 
                         for (InputSlot s : f.getInputSlots()) {
                             for (Connection c : s.getConnections()) {
-                                Connection newConn = diagram.createConnection(slot, c.getOutputSlot(), c.getLabel());
+                                Connection newConn = diagram.createConnection(slot, c.getOutputSlot(), c.getLabel(), c.getType());
                                 newConn.setColor(c.getColor());
                                 newConn.setStyle(c.getStyle());
                             }
@@ -154,7 +154,7 @@
                                     }
                                 }
                                 for (Connection c : nextSlot.getConnections()) {
-                                    Connection newConn = diagram.createConnection(c.getInputSlot(), slot, c.getLabel());
+                                    Connection newConn = diagram.createConnection(c.getInputSlot(), slot, c.getLabel(), c.getType());
                                     newConn.setColor(c.getColor());
                                     newConn.setStyle(c.getStyle());
                                 }
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java	Mon Jun 30 12:02:19 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -31,6 +31,7 @@
 import com.sun.hotspot.igv.graph.Figure;
 import com.sun.hotspot.igv.graph.InputSlot;
 import java.awt.Color;
+import java.util.HashMap;
 import java.util.List;
 import java.util.regex.Pattern;
 
@@ -41,9 +42,8 @@
  */
 public class GraalEdgeColorFilter extends AbstractFilter {
 
-    private Color successorColor = Color.BLUE;
-    private Color usageColor = Color.RED;
-    private Color memoryColor = Color.GREEN;
+    private HashMap<String,Color> usageColor = new HashMap<>();
+    private Color otherUsageColor = Color.BLACK;
 
     public GraalEdgeColorFilter() {
     }
@@ -56,66 +56,43 @@
     @Override
     public void apply(Diagram d) {
         List<Figure> figures = d.getFigures();
-        Pattern ndf = Pattern.compile(".*#NDF(\\[[0-9]*\\])?");
         for (Figure f : figures) {
-            Properties p = f.getProperties();
-            int predCount;
-            String predCountString = p.get("predecessorCount");
-            if (predCountString != null) {
-                predCount = Integer.parseInt(predCountString);
-            } else if (Boolean.parseBoolean(p.get("hasPredecessor"))) {
-                predCount = 1;
-            } else {
-                predCount = 0;
-            }
             for (InputSlot is : f.getInputSlots()) {
-                Color color;
-                ConnectionStyle style = ConnectionStyle.NORMAL;
-                if (is.getPosition() < predCount) {
-                    color = successorColor;
-                    style = ConnectionStyle.BOLD;
-                } else {
-                    color = usageColor;
-                }
-
-                is.setColor(color);
                 for (Connection c : is.getConnections()) {
-                    if (c.getLabel() == null || !ndf.matcher(c.getLabel()).matches()) {
-                        c.setColor(color);
-                        if (c.getStyle() != ConnectionStyle.DASHED) {
-                            c.setStyle(style);
+                    String type = c.getType();
+                    if (type == "Association" && "EndNode".equals(c.getOutputSlot().getFigure().getProperties().get("class"))) {
+                        type = "Successor";
+                    }
+                    
+                    if (type != null) {
+                        Color typeColor = usageColor.get(type);
+                        if (typeColor == null) {
+                            c.setColor(otherUsageColor);
+                        } else {
+                            c.setColor(typeColor);
                         }
-                    } else if ("EndNode".equals(c.getOutputSlot().getFigure().getProperties().get("class"))
-                            || "EndNode".equals(c.getOutputSlot().getProperties().get("class"))) {
-                        c.setColor(successorColor);
-                        c.setStyle(ConnectionStyle.BOLD);
+                        if (c.getStyle() != ConnectionStyle.DASHED && type == "Successor") {
+                            c.setStyle(ConnectionStyle.BOLD);
+                        }
                     }
                 }
             }
         }
     }
 
-    public Color getUsageColor() {
-        return usageColor;
-    }
-
-    public void setUsageColor(Color usageColor) {
-        this.usageColor = usageColor;
-    }
-
-    public void setMemoryColor(Color memoryColor) {
-        this.memoryColor = memoryColor;
+    public Color getUsageColor(String type) {
+        return usageColor.get(type);
     }
 
-    public Color getMemoryColor() {
-        return memoryColor;
+    public void setUsageColor(String type, Color usageColor) {
+        this.usageColor.put(type, usageColor);
     }
-
-    public Color getSuccessorColor() {
-        return successorColor;
+    
+    public Color getOtherUsageColor() {
+        return otherUsageColor;
     }
-
-    public void setSuccessorColor(Color successorColor) {
-        this.successorColor = successorColor;
+    
+    public void setOtherUsageColor(Color otherUsageColor) {
+        this.otherUsageColor = otherUsageColor;
     }
 }
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/edgeColor.filter	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/edgeColor.filter	Mon Jun 30 12:02:19 2014 +0200
@@ -1,4 +1,5 @@
 var f = new com.sun.hotspot.igv.graal.filters.GraalEdgeColorFilter();
-f.setUsageColor(blue);
-f.setSuccessorColor(red);
+f.setUsageColor("Successor", red);
+f.setUsageColor("Value", blue);
+f.setUsageColor("Memory", new Color(0.0, 0.5, 0.0));
 f.apply(graph);
--- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Connection.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Connection.java	Mon Jun 30 12:02:19 2014 +0200
@@ -55,11 +55,13 @@
     private ConnectionStyle style;
     private List<Point> controlPoints;
     private String label;
+    private String type;
 
-    protected Connection(InputSlot inputSlot, OutputSlot outputSlot, String label) {
+    protected Connection(InputSlot inputSlot, OutputSlot outputSlot, String label, String type) {
         this.inputSlot = inputSlot;
         this.outputSlot = outputSlot;
         this.label = label;
+        this.type = type;
         this.inputSlot.connections.add(this);
         this.outputSlot.connections.add(this);
         controlPoints = new ArrayList<>();
@@ -105,6 +107,10 @@
     public String getLabel() {
         return label;
     }
+    
+    public String getType() {
+        return type;
+    }
 
     public void remove() {
         inputSlot.getFigure().removePredecessor(outputSlot.getFigure());
@@ -116,10 +122,12 @@
     public String getToolTipText() {
         StringBuilder builder = new StringBuilder();
         if (label != null) {
-            builder.append(label).append(": from ");
-        } else {
-            builder.append("From ");
+            builder.append(label).append(": ");
         }
+        if (type != null) {
+            builder.append(type).append(" ");
+        }
+        builder.append("from ");
         builder.append(getOutputSlot().getFigure().getSource().getSourceNodes().get(0).getId());
         builder.append(" to ");
         builder.append(getInputSlot().getFigure().getSource().getSourceNodes().get(0).getId());
--- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java	Mon Jun 30 12:02:19 2014 +0200
@@ -82,10 +82,10 @@
         return f;
     }
 
-    public Connection createConnection(InputSlot inputSlot, OutputSlot outputSlot, String label) {
+    public Connection createConnection(InputSlot inputSlot, OutputSlot outputSlot, String label, String type) {
         assert inputSlot.getFigure().getDiagram() == this;
         assert outputSlot.getFigure().getDiagram() == this;
-        return new Connection(inputSlot, outputSlot, label);
+        return new Connection(inputSlot, outputSlot, label, type);
     }
     
     public Map<InputNode, Set<Figure>> calcSourceToFigureRelation() {
@@ -145,7 +145,7 @@
             }
             InputSlot inputSlot = toFigure.getInputSlots().get(toIndex);
 
-            Connection c = d.createConnection(inputSlot, outputSlot, e.getLabel());
+            Connection c = d.createConnection(inputSlot, outputSlot, e.getLabel(), e.getType());
 
             if (e.getState() == InputEdge.State.NEW) {
                 c.setStyle(Connection.ConnectionStyle.BOLD);
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Compilation.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Compilation.java	Mon Jun 30 12:02:19 2014 +0200
@@ -26,6 +26,7 @@
 
 import java.io.PrintStream;
 import java.util.ArrayList;
+import java.util.List;
 
 public class Compilation implements LogEvent {
 
@@ -44,6 +45,7 @@
     private NMethod nmethod;
     private ArrayList<Phase> phases = new ArrayList<Phase>(4);
     private String failureReason;
+    private List<JVMState> eliminatedLocks = new ArrayList<JVMState>();
 
     Compilation(int id) {
         this.id = id;
@@ -77,9 +79,11 @@
         sb.append("+");
         sb.append(getBcount());
         sb.append("\n");
-        for (CallSite site : getCall().getCalls()) {
-            sb.append(site);
-            sb.append("\n");
+        if (getCall().getCalls() != null) {
+            for (CallSite site : getCall().getCalls()) {
+                sb.append(site);
+                sb.append("\n");
+            }
         }
         if (getLateInlineCall().getCalls() != null) {
             sb.append("late inline:\n");
@@ -91,15 +95,19 @@
         return sb.toString();
     }
 
-    public void printShort(PrintStream stream) {
+    public String shortName() {
         if (getMethod() == null) {
-            stream.println(getSpecial());
+            return getSpecial();
         } else {
             int bc = isOsr() ? getOsr_bci() : -1;
-            stream.print(getId() + getMethod().decodeFlags(bc) + getMethod().format(bc));
+            return getId() + getMethod().decodeFlags(bc) + getMethod().format(bc);
         }
     }
 
+    public void printShort(PrintStream stream) {
+        stream.println(shortName());
+    }
+
     public void print(PrintStream stream) {
         print(stream, 0, false);
     }
@@ -255,4 +263,12 @@
     public Compilation getCompilation() {
         return this;
     }
+
+    public void addEliminatedLock(JVMState jvms) {
+        eliminatedLocks.add(jvms);
+    }
+
+    public List<JVMState> getEliminatedLocks() {
+        return eliminatedLocks;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/JVMState.java	Mon Jun 30 12:02:19 2014 +0200
@@ -0,0 +1,43 @@
+/*
+ * 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.sun.hotspot.tools.compiler;
+
+public class JVMState {
+    final Method method;
+    final int bci;
+    JVMState outer;
+    
+    JVMState(Method method, int bci) {
+        this.method = method;
+        this.bci = bci;
+    }
+    
+    void push(JVMState jvms) {
+        if (outer == null) {
+            outer = jvms;
+        } else {
+            outer.push(jvms);
+        }
+    }
+}
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java	Mon Jun 30 12:02:19 2014 +0200
@@ -44,6 +44,7 @@
         System.out.println("  -s:   sort events by start time");
         System.out.println("  -e:   sort events by elapsed time");
         System.out.println("  -n:   sort events by name and start");
+        System.out.println("  -L:   print eliminated locks");
         System.exit(exitcode);
     }
 
@@ -52,6 +53,7 @@
         boolean statistics = false;
         boolean printInlining = false;
         boolean cleanup = false;
+        boolean printEliminatedLocks = false;
         int index = 0;
 
         while (args.length > index) {
@@ -75,6 +77,9 @@
             } else if (args[index].equals("-i")) {
                 printInlining = true;
                 index++;
+            } else if (args[index].equals("-L")) {
+                printEliminatedLocks = true;
+                index++;
             } else {
                 break;
             }
@@ -87,11 +92,34 @@
         while (index < args.length) {
             ArrayList<LogEvent> events = LogParser.parse(args[index], cleanup);
 
-            if (statistics) {
+            if (printEliminatedLocks) {
+                Collections.sort(events, defaultSort);
+                for (LogEvent e : events) {
+                    if (e instanceof Compilation) {
+                        Compilation c = (Compilation) e;
+                        List<JVMState> eliminated = c.getEliminatedLocks();
+                        if (!eliminated.isEmpty()) {
+                            c.print(System.out);
+                            System.out.println("  Eliminated locks");
+                            for (JVMState jvms : eliminated) {
+                                System.err.print("   ");
+                                while (jvms != null) {
+                                    System.out.printf(" %s.%s@%d", jvms.method.getHolder().replace('/', '.'), jvms.method.getName(), jvms.bci);
+                                    jvms = jvms.outer;
+                                }
+                                System.out.println();
+                            }
+                        }
+                    }
+                }
+            } else if (statistics) {
                 printStatistics(events, System.out);
             } else {
                 Collections.sort(events, defaultSort);
                 for (LogEvent c : events) {
+                    if (c instanceof NMethod) continue;
+
+                    System.out.printf("%f ", c.getStart());
                     if (printInlining && c instanceof Compilation) {
                         Compilation comp = (Compilation)c;
                         comp.print(System.out, true);
@@ -141,7 +169,7 @@
                        nodes created in the phase, live nodes at the start of the phase,
                        live nodes added in the phase.
                     */
-                    out.printf("\t%s %6.4f %d %d %d %d\n", phase.getName(), phase.getElapsedTime(), phase.getStartNodes(), phase.getNodes(), phase.getStartLiveNodes(), phase.getLiveNodes());
+                    // out.printf("\t%s %6.4f %d %d %d %d\n", phase.getName(), phase.getElapsedTime(), phase.getStartNodes(), phase.getNodes(), phase.getStartLiveNodes(), phase.getLiveNodes());
                 }
             } else if (e instanceof MakeNotEntrantEvent) {
                 MakeNotEntrantEvent mne = (MakeNotEntrantEvent) e;
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java	Mon Jun 30 12:02:19 2014 +0200
@@ -89,15 +89,12 @@
                 if (result != 0) {
                     return result;
                 }
-            }
-            double difference = (a.getStart() - b.getStart());
-            if (difference < 0) {
+            } else if (c1 == null && c2 != null) {
                 return -1;
-            }
-            if (difference > 0) {
+            } else if (c2 == null && c1 != null) {
                 return 1;
             }
-            return 0;
+            return Double.compare(a.getStart(), b.getStart());
         }
 
         public boolean equals(Object other) {
@@ -138,6 +135,7 @@
     private HashMap<String, String> types = new HashMap<String, String>();
     private HashMap<String, Method> methods = new HashMap<String, Method>();
     private LinkedHashMap<String, NMethod> nmethods = new LinkedHashMap<String, NMethod>();
+    private ArrayList<MakeNotEntrantEvent> notEntrantEvents = new ArrayList<MakeNotEntrantEvent>();
     private HashMap<String, Compilation> compiles = new HashMap<String, Compilation>();
     private String failureReason;
     private int bci;
@@ -147,6 +145,8 @@
     private Stack<Phase> phaseStack = new Stack<Phase>();
     private UncommonTrapEvent currentTrap;
     private Stack<CallSite> late_inline_scope;
+    private JVMState eliminated_lock;
+    private boolean in_eliminate_lock;
 
     long parseLong(String l) {
         try {
@@ -191,15 +191,34 @@
         p.parse(new InputSource(reader), log);
 
         // Associate compilations with their NMethods
-        for (NMethod nm : log.nmethods.values()) {
-            Compilation c = log.compiles.get(nm.getId());
-            nm.setCompilation(c);
-            // Native wrappers for methods don't have a compilation
-            if (c != null) {
-                c.setNMethod(nm);
+        for (LogEvent le : log.events) {
+            if (le instanceof BasicLogEvent) {
+                BasicLogEvent ble = (BasicLogEvent) le;
+                Compilation c = log.compiles.get(ble.getId());
+                ble.setCompilation(c);
+                if (ble instanceof NMethod) {
+                    NMethod nm = (NMethod) ble;
+                    // Native wrappers for methods don't have a compilation and Graal methods don't either.
+                    if (c != null) {
+                        c.setNMethod(nm);
+                    }
+                } else {
+                    if (c == null) {
+                        throw new InternalError("can't find compilation " + ble.getId() + " for " + ble);
+                    }
+                }
             }
         }
 
+
+        for (MakeNotEntrantEvent ne : log.notEntrantEvents) {
+            Compilation c = log.compiles.get(ne.getId());
+            if (c == null) {
+                throw new InternalError("can't find compilation " + ne.getId());
+            }
+            ne.setCompilation(c);
+        }
+
         // Initially we want the LogEvent log sorted by timestamp
         Collections.sort(log.events, sortByStart);
 
@@ -353,8 +372,9 @@
             String id = makeId(atts);
             NMethod nm = nmethods.get(id);
             if (nm == null) throw new InternalError();
-            LogEvent e = new MakeNotEntrantEvent(Double.parseDouble(search(atts, "stamp")), id,
-                                                 atts.getValue("zombie") != null, nm);
+            MakeNotEntrantEvent e = new MakeNotEntrantEvent(Double.parseDouble(search(atts, "stamp")), id,
+                                                            atts.getValue("zombie") != null, nm);
+            notEntrantEvents.add(e);
             events.add(e);
         } else if (qname.equals("uncommon_trap")) {
             String id = atts.getValue("compile_id");
@@ -374,6 +394,8 @@
             late_inline_scope = new Stack<CallSite>();
             site = new CallSite(-999, method(search(atts, "method")));
             late_inline_scope.push(site);
+        } else if (qname.equals("eliminate_lock")) {
+            in_eliminate_lock = true;
         } else if (qname.equals("jvms")) {
             // <jvms bci='4' method='java/io/DataInputStream readChar ()C' bytes='40' count='5815' iicount='20815'/>
             if (currentTrap != null) {
@@ -382,6 +404,13 @@
                 bci = Integer.parseInt(search(atts, "bci"));
                 site = new CallSite(bci, method(search(atts, "method")));
                 late_inline_scope.push(site);
+            } else if (in_eliminate_lock) {
+                JVMState jvms = new JVMState(method(atts.getValue("method")), Integer.parseInt(atts.getValue("bci")));
+                if (eliminated_lock == null) {
+                    eliminated_lock = jvms;
+                } else {
+                    eliminated_lock.push(jvms);
+                }
             } else {
                 // Ignore <eliminate_allocation type='667'>,
                 //        <eliminate_lock lock='1'>,
@@ -390,9 +419,10 @@
         } else if (qname.equals("nmethod")) {
             String id = makeId(atts);
             NMethod nm = new NMethod(Double.parseDouble(search(atts, "stamp")),
-                    id,
-                    parseLong(atts.getValue("address")),
-                    parseLong(atts.getValue("size")));
+                                     id,
+                                     atts.getValue("compile_kind"),
+                                     parseLong(atts.getValue("address")),
+                                     parseLong(atts.getValue("size")));
             nmethods.put(id, nm);
             events.add(nm);
         } else if (qname.equals("parse")) {
@@ -429,6 +459,13 @@
             scopes.pop();
         } else if (qname.equals("uncommon_trap")) {
             currentTrap = null;
+        } else if (qname.equals("eliminate_lock")) {
+            if (eliminated_lock != null) {
+                // There's no JVM state on the unlock, so ignore it
+                compile.addEliminatedLock(eliminated_lock);
+            }
+            eliminated_lock = null;
+            in_eliminate_lock = false;
         } else if (qname.equals("late_inline")) {
             // Populate late inlining info.
 
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/MakeNotEntrantEvent.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/MakeNotEntrantEvent.java	Mon Jun 30 12:02:19 2014 +0200
@@ -43,9 +43,9 @@
 
     public void print(PrintStream stream) {
         if (isZombie()) {
-            stream.printf("%s make_zombie\n", getId());
+            stream.printf("%s make_zombie\n", compilation.shortName());
         } else {
-            stream.printf("%s make_not_entrant\n", getId());
+            stream.printf("%s make_not_entrant\n", compilation.shortName());
         }
     }
 
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/NMethod.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/NMethod.java	Mon Jun 30 12:02:19 2014 +0200
@@ -30,11 +30,17 @@
 
     private long address;
     private long size;
+    private String compileKind;
 
-    NMethod(double s, String i, long a, long sz) {
+    NMethod(double s, String i, String k, long a, long sz) {
         super(s, i);
         address = a;
         size = sz;
+        if (k == null) {
+            compileKind = "normal";
+        } else {
+            compileKind = k;
+        }
     }
 
     public void print(PrintStream out) {
@@ -50,6 +56,10 @@
         this.address = address;
     }
 
+    public String getKind() {
+        return compileKind;
+    }
+
     public long getSize() {
         return size;
     }
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrapEvent.java	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrapEvent.java	Mon Jun 30 12:02:19 2014 +0200
@@ -40,7 +40,6 @@
         count = c;
     }
 
-
     public void addJVMS(String method, int bci) {
         setJvms(getJvms() + "  @" + bci + " " + method + "\n");
     }
@@ -50,7 +49,7 @@
     }
 
     public void print(PrintStream stream) {
-        stream.printf("%s uncommon trap %s %s\n", getId(), getReason(), getAction());
+        stream.printf("%s uncommon trap %s %s\n", compilation.shortName(), getReason(), getAction());
         stream.print(getJvms());
     }
 
@@ -77,8 +76,4 @@
     public void setJvms(String jvms) {
         this.jvms = jvms;
     }
-
-    public void setCompilation(Compilation compilation) {
-        this.compilation = compilation;
-    }
 }
--- a/src/share/vm/classfile/javaClasses.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/classfile/javaClasses.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -1532,6 +1532,7 @@
     return;
   }
   
+#ifdef GRAAL
   // Check for gpu exception to add as top frame
   Method* gpu_method = thread->get_gpu_exception_method();
   if (gpu_method != NULL) {
@@ -1541,6 +1542,7 @@
     thread->set_gpu_exception_bci(0);
     thread->set_gpu_exception_method(NULL);  
   }
+#endif
 
   // Instead of using vframe directly, this version of fill_in_stack_trace
   // basically handles everything by hand. This significantly improved the
--- a/src/share/vm/classfile/systemDictionary.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/classfile/systemDictionary.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -2286,7 +2286,7 @@
     spe = NULL;
     // Must create lots of stuff here, but outside of the SystemDictionary lock.
     m = Method::make_method_handle_intrinsic(iid, signature, CHECK_(empty));
-    CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_highest_tier,
+    nmethod* nm = CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_highest_tier,
                                   methodHandle(), CompileThreshold, "MH", CHECK_(empty));
 
     // Now grab the lock.  We might have to throw away the new method,
@@ -2299,9 +2299,12 @@
       if (spe->method() == NULL)
         spe->set_method(m());
     }
+  } else if (spe->method()->code() == NULL) {
+    nmethod* nm = CompileBroker::compile_method(spe->method(), InvocationEntryBci, CompLevel_highest_tier,
+                                      methodHandle(), CompileThreshold, "MH", CHECK_(empty));
   }
 
-  assert(spe != NULL && spe->method() != NULL, "");
+  guarantee(spe != NULL && spe->method() != NULL && spe->method()->code() != NULL, "Could not compile a method handle intrinsic");
   return spe->method();
 }
 
--- a/src/share/vm/compiler/compileBroker.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/compiler/compileBroker.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -383,7 +383,7 @@
     st->print("%7d ", (int) st->time_stamp().milliseconds());  // print timestamp
   }
   // print compiler name if requested
-  if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level));
+  if (CIPrintCompilerName) st->print("%s:", CompileBroker::compiler_name(comp_level));
   st->print("%4d ", compile_id);    // print compilation number
 
   // For unloaded methods the transition to zombie occurs after the
@@ -805,7 +805,19 @@
 
 #if defined(COMPILERGRAAL)
   _compilers[1] = graal;
-  c2_count = UseGraalCompilationQueue ? 0 : c2_count;
+  if (UseGraalCompilationQueue) {
+    c2_count = 0;
+  } else {
+    if (FLAG_IS_DEFAULT(GraalThreads)) {
+      if (!TieredCompilation && FLAG_IS_DEFAULT(BootstrapGraal) || BootstrapGraal) {
+        // Graal will bootstrap so give it the same number of threads
+        // as we would give the Java based compilation queue.
+        c2_count = os::active_processor_count();
+      }
+    } else {
+      c2_count = GraalThreads;
+    }
+  }
 #endif // COMPILERGRAAL
 
 #ifdef COMPILER2
@@ -1031,7 +1043,7 @@
   char name_buffer[256];
   for (int i = 0; i < c2_compiler_count; i++) {
     // Create a name for our thread.
-    sprintf(name_buffer, "C2 CompilerThread%d", i);
+    sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i);
     CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK);
     // Shark and C2
     CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_method_queue, counters, _compilers[1], CHECK);
@@ -1199,6 +1211,13 @@
     // Should this thread wait for completion of the compile?
     blocking = is_compile_blocking(method, osr_bci);
 
+#ifdef COMPILERGRAAL
+    // Don't allow blocking compiles for requests triggered by Graal.
+    if (blocking && thread->is_Compiler_thread()) {
+      blocking = false;
+    }
+#endif
+
     // We will enter the compilation in the queue.
     // 14012000: Note that this sets the queued_for_compile bits in
     // the target method. We can now reason that a method cannot be
--- a/src/share/vm/gc_interface/collectedHeap.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/gc_interface/collectedHeap.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -84,7 +84,7 @@
 class CollectedHeap : public CHeapObj<mtInternal> {
   friend class VMStructs;
   friend class IsGCActiveMark; // Block structured external access to _is_gc_active
-  friend class Hsail;  // access to allocate_new_tlab
+  friend class HSAILAllocationInfo;  // access to allocate_new_tlab
 
 #ifdef ASSERT
   static int       _fire_out_of_memory_count;
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -88,6 +88,26 @@
   return arr->length() * MapWordBits;
 }
 
+static void set_vmreg_oops(OopMap* map, VMReg reg, oop bitset, int idx) {
+  bool is_oop = is_bit_set(bitset, 3 * idx);
+  if (is_oop) {
+    bool narrow1 = is_bit_set(bitset, 3 * idx + 1);
+    bool narrow2 = is_bit_set(bitset, 3 * idx + 2);
+    if (narrow1 || narrow2) {
+      if (narrow1) {
+        map->set_narrowoop(reg);
+      }
+      if (narrow2) {
+        map->set_narrowoop(reg->next());
+      }
+    } else {
+      map->set_oop(reg);
+    }
+  } else {
+    map->set_value(reg);
+  }
+}
+
 // creates a HotSpot oop map out of the byte arrays provided by DebugInfo
 static OopMap* create_oop_map(jint total_frame_size, jint parameter_count, oop debug_info) {
   OopMap* map = new OopMap(total_frame_size, parameter_count);
@@ -98,41 +118,23 @@
 
   if (register_map != NULL) {
     for (jint i = 0; i < RegisterImpl::number_of_registers; i++) {
-      bool is_oop = is_bit_set(register_map, 2 * i);
-      VMReg hotspot_reg = get_hotspot_reg(i);
-      if (is_oop) {
-        if (is_bit_set(register_map, 2 * i + 1)) {
-          map->set_narrowoop(hotspot_reg);
-        } else {
-          map->set_oop(hotspot_reg);
-        }
-      } else {
-        map->set_value(hotspot_reg);
+      set_vmreg_oops(map, as_Register(i)->as_VMReg(), register_map, i);
+    }
+#ifdef TARGET_ARCH_x86
+    for (jint i = 0; i < XMMRegisterImpl::number_of_registers; i++) {
+      VMReg reg = as_XMMRegister(i)->as_VMReg();
+      int idx = RegisterImpl::number_of_registers + 4 * i;
+      for (jint j = 0; j < 4; j++) {
+        set_vmreg_oops(map, reg->next(2 * j), register_map, idx + j);
       }
     }
+#endif
   }
 
   for (jint i = 0; i < bitset_size(frame_map) / 3; i++) {
-    bool is_oop = is_bit_set(frame_map, i * 3);
     // HotSpot stack slots are 4 bytes
     VMReg reg = VMRegImpl::stack2reg(i * VMRegImpl::slots_per_word);
-    if (is_oop) {
-      bool narrow1 = is_bit_set(frame_map, i * 3 + 1);
-      bool narrow2 = is_bit_set(frame_map, i * 3 + 2);
-      if(narrow1 || narrow2) {
-        if(narrow1) {
-          map->set_narrowoop(reg);
-        }
-        if(narrow2) {
-          VMReg reg2 = VMRegImpl::stack2reg(i * VMRegImpl::slots_per_word + 1);
-          map->set_narrowoop(reg2);
-        }
-      } else {
-        map->set_oop(reg);
-      }
-    } else {
-      map->set_value(reg);
-    }
+    set_vmreg_oops(map, reg, frame_map, i);
   }
 
   if (callee_save_info != NULL) {
--- a/src/share/vm/graal/graalCompiler.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -35,6 +35,7 @@
 GraalCompiler::GraalCompiler() : AbstractCompiler(graal) {
 #ifdef COMPILERGRAAL
   _bootstrapping = false;
+  _compiled = 0;
 #endif
   assert(_instance == NULL, "only one instance allowed");
   _instance = this;
@@ -62,9 +63,10 @@
   {
     HandleMark hm;
 
-    _bootstrapping = UseGraalCompilationQueue && (FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal);
+    bool bootstrap_now = UseGraalCompilationQueue && (FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal);
 
     if (UseGraalCompilationQueue) {
+      _bootstrapping = bootstrap_now;
       start_compilation_queue();
     }
 
@@ -72,7 +74,7 @@
     // stop the VM deferring compilation now.
     CompilationPolicy::completed_vm_startup();
 
-    if (_bootstrapping) {
+    if (bootstrap_now) {
       // Avoid -Xcomp and -Xbatch problems by turning on interpreter and background compilation for bootstrapping.
       FlagSetting a(UseInterpreter, true);
       FlagSetting b(BackgroundCompilation, true);
@@ -119,13 +121,56 @@
 
 void GraalCompiler::bootstrap() {
   JavaThread* THREAD = JavaThread::current();
-  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/CompilationQueue", THREAD);
-  KlassHandle klass = GraalRuntime::load_required_class(name);
-  JavaValue result(T_VOID);
-  TempNewSymbol bootstrap = SymbolTable::new_symbol("bootstrap", THREAD);
-  NoGraalCompilationScheduling ngcs(THREAD);
-  JavaCalls::call_static(&result, klass, bootstrap, vmSymbols::void_method_signature(), THREAD);
-  GUARANTEE_NO_PENDING_EXCEPTION("Error while calling bootstrap");
+  _bootstrapping = true;
+  if (!UseGraalCompilationQueue) {
+    ResourceMark rm;
+    HandleMark hm;
+    if (PrintBootstrap) {
+      tty->print("Bootstrapping Graal");
+    }
+    jlong start = os::javaTimeMillis();
+
+    Array<Method*>* objectMethods = InstanceKlass::cast(SystemDictionary::Object_klass())->methods();
+    // Initialize compile queue with a selected set of methods.
+    int len = objectMethods->length();
+    for (int i = 0; i < len; i++) {
+      methodHandle mh = objectMethods->at(i);
+      if (!mh->is_native() && !mh->is_static() && !mh->is_initializer()) {
+        ResourceMark rm;
+        int hot_count = 10; // TODO: what's the appropriate value?
+        CompileBroker::compile_method(mh, InvocationEntryBci, CompLevel_full_optimization, mh, hot_count, "bootstrap", THREAD);
+      }
+    }
+
+    int qsize;
+    jlong sleep_time = 1000;
+    int z = 0;
+    do {
+      os::sleep(THREAD, sleep_time, true);
+      sleep_time = 100;
+      qsize = CompileBroker::queue_size(CompLevel_full_optimization);
+      if (PrintBootstrap) {
+        while (z < (_compiled / 100)) {
+          ++z;
+          tty->print_raw(".");
+        }
+      }
+    } while (qsize != 0);
+
+    if (PrintBootstrap) {
+      tty->print_cr(" in %d ms (compiled %d methods)", os::javaTimeMillis() - start, _compiled);
+    }
+  } else {
+
+    TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/CompilationQueue", THREAD);
+    KlassHandle klass = GraalRuntime::load_required_class(name);
+    JavaValue result(T_VOID);
+    TempNewSymbol bootstrap = SymbolTable::new_symbol("bootstrap", THREAD);
+    NoGraalCompilationScheduling ngcs(THREAD);
+    JavaCalls::call_static(&result, klass, bootstrap, vmSymbols::void_method_signature(), THREAD);
+    GUARANTEE_NO_PENDING_EXCEPTION("Error while calling bootstrap");
+  }
+  _bootstrapping = false;
 }
 
 void GraalCompiler::compile_method(methodHandle method, int entry_bci, CompileTask* task, jboolean blocking) {
@@ -138,6 +183,7 @@
       return;
   }
 
+  HandleMark hm;
   ResourceMark rm;
   JavaValue result(T_VOID);
   JavaCallArguments args;
@@ -147,6 +193,8 @@
   args.push_int(blocking);
   JavaCalls::call_static(&result, SystemDictionary::CompilationTask_klass(), vmSymbols::compileMetaspaceMethod_name(), vmSymbols::compileMetaspaceMethod_signature(), &args, THREAD);
   GUARANTEE_NO_PENDING_EXCEPTION("Error while calling compile_method");
+
+  _compiled++;
 }
 
 
--- a/src/share/vm/graal/graalCompiler.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/graal/graalCompiler.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -32,10 +32,10 @@
 
 #ifdef COMPILERGRAAL
   bool _bootstrapping;
+  volatile int  _compiled; // no synchronization so may not be 100% accurate
 
   void start_compilation_queue();
   void shutdown_compilation_queue();
-  void bootstrap();
 #endif
 
   static GraalCompiler* _instance;
@@ -61,6 +61,9 @@
   virtual void initialize();
 
 #ifdef COMPILERGRAAL
+
+  void bootstrap();
+  
   // Compilation entry point for methods
   virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
 
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -194,9 +194,9 @@
   return (jlong) (address) method();
 }
 
-C2V_VMENTRY(jlong, findUniqueConcreteMethod, (JNIEnv *, jobject, jlong metaspace_method))
+C2V_VMENTRY(jlong, findUniqueConcreteMethod, (JNIEnv *, jobject, jlong metaspace_klass, jlong metaspace_method))
   methodHandle method = asMethod(metaspace_method);
-  KlassHandle holder = method->method_holder();
+  KlassHandle holder = asKlass(metaspace_klass);
   assert(!holder->is_interface(), "should be handled in Java code");
   ResourceMark rm;
   MutexLocker locker(Compile_lock);
@@ -367,7 +367,7 @@
       methodHandle resolved_method;
       LinkResolver::linktime_resolve_interface_method(resolved_method, holder_klass, method_name, method_signature, caller_klass, true, CHECK_AND_CLEAR_0);
       if (resolved_method->is_private()) {
-        return (jlong) NULL;
+        return (jlong) (address) NULL;
       }
       assert(recv_klass->is_subtype_of(holder_klass), "");
       // do actual lookup
@@ -413,7 +413,7 @@
       return (jlong) (address) selected_method;
     }
   }
-  return (jlong) NULL;
+  return (jlong) (address) NULL;
 C2V_END
 
 C2V_VMENTRY(jboolean, hasFinalizableSubclass,(JNIEnv *, jobject, jlong metaspace_klass))
@@ -897,6 +897,14 @@
   cp_cache_entry->set_dynamic_call(cp, callInfo);
 C2V_END
 
+C2V_VMENTRY(jboolean, shouldDebugNonSafepoints, (JNIEnv*, jobject))
+  //see compute_recording_non_safepoints in debugInfroRec.cpp
+  if (JvmtiExport::should_post_compiled_method_load() && FLAG_IS_DEFAULT(DebugNonSafepoints)) {
+    return true;
+  }
+  return DebugNonSafepoints;
+C2V_END
+
 // public native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate);
 C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv*, jobject, jobject hs_frame, bool invalidate))
   ResourceMark rm;
@@ -1019,7 +1027,7 @@
   {CC"exceptionTableStart",                          CC"("METASPACE_METHOD")J",                                                FN_PTR(exceptionTableStart)},
   {CC"exceptionTableLength",                         CC"("METASPACE_METHOD")I",                                                FN_PTR(exceptionTableLength)},
   {CC"hasBalancedMonitors",                          CC"("METASPACE_METHOD")Z",                                                FN_PTR(hasBalancedMonitors)},
-  {CC"findUniqueConcreteMethod",                     CC"("METASPACE_METHOD")"METASPACE_METHOD,                                 FN_PTR(findUniqueConcreteMethod)},
+  {CC"findUniqueConcreteMethod",                     CC"("METASPACE_KLASS METASPACE_METHOD")"METASPACE_METHOD,                 FN_PTR(findUniqueConcreteMethod)},
   {CC"getKlassImplementor",                          CC"("METASPACE_KLASS")"METASPACE_KLASS,                                   FN_PTR(getKlassImplementor)},
   {CC"getStackTraceElement",                         CC"("METASPACE_METHOD"I)"STACK_TRACE_ELEMENT,                             FN_PTR(getStackTraceElement)},
   {CC"methodIsIgnoredBySecurityStackWalk",           CC"("METASPACE_METHOD")Z",                                                FN_PTR(methodIsIgnoredBySecurityStackWalk)},
@@ -1068,6 +1076,7 @@
   {CC"getTimeStamp",                                 CC"()J",                                                                  FN_PTR(getTimeStamp)},
   {CC"getNextStackFrame",                            CC"("HS_STACK_FRAME_REF "[JI)"HS_STACK_FRAME_REF,                         FN_PTR(getNextStackFrame)},
   {CC"materializeVirtualObjects",                    CC"("HS_STACK_FRAME_REF"Z)V",                                             FN_PTR(materializeVirtualObjects)},
+  {CC"shouldDebugNonSafepoints",                     CC"()Z",                                                                  FN_PTR(shouldDebugNonSafepoints)},
 };
 
 int CompilerToVM_methods_count() {
--- a/src/share/vm/graal/graalGlobals.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/graal/graalGlobals.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -52,7 +52,13 @@
   COMPILERGRAAL_PRESENT(product(bool, BootstrapGraal, true,                 \
           "Bootstrap Graal before running Java main method"))               \
                                                                             \
-  COMPILERGRAAL_PRESENT(product(bool, UseGraalCompilationQueue, true,       \
+  COMPILERGRAAL_PRESENT(product(bool, PrintBootstrap, true,                 \
+          "Print Graal bootstrap progress and summary"))                    \
+                                                                            \
+  COMPILERGRAAL_PRESENT(product(intx, GraalThreads, 1,                      \
+          "Force number of Graal compiler threads to use"))                 \
+                                                                            \
+  COMPILERGRAAL_PRESENT(product(bool, UseGraalCompilationQueue, false,      \
           "Use non-native compilation queue for Graal"))                    \
                                                                             \
   product(bool, ForceGraalInitialization, false,                            \
--- a/src/share/vm/graal/graalRuntime.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -701,6 +701,35 @@
 JVM_END
 #endif
 
+jint GraalRuntime::check_arguments(TRAPS) {
+  KlassHandle nullHandle;
+  parse_arguments(nullHandle, THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    // Errors in parsing Graal arguments cause exceptions.
+    // We now load and initialize HotSpotOptions which in turn
+    // causes argument parsing to be redone with better error messages.
+    CLEAR_PENDING_EXCEPTION;
+    TempNewSymbol name = SymbolTable::new_symbol("Lcom/oracle/graal/hotspot/HotSpotOptions;", THREAD);
+    instanceKlassHandle hotSpotOptionsClass = SystemDictionary::resolve_or_fail(name, true, THREAD);
+    GUARANTEE_NO_PENDING_EXCEPTION("Error in check_arguments");
+
+    parse_arguments(hotSpotOptionsClass, THREAD);
+    assert(HAS_PENDING_EXCEPTION, "must be");
+
+    ResourceMark rm;
+    Handle exception = PENDING_EXCEPTION;
+    CLEAR_PENDING_EXCEPTION;
+    oop message = java_lang_Throwable::message(exception);
+    if (message != NULL) {
+      tty->print_cr("Error parsing Graal options: %s", java_lang_String::as_utf8_string(message));
+    } else {
+      call_printStackTrace(exception, THREAD);
+    }
+    return JNI_ERR;
+  }
+  return JNI_OK;
+}
+
 bool GraalRuntime::parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS) {
   ResourceMark rm(THREAD);
 
@@ -716,43 +745,51 @@
   return CITime || CITimeEach;
 }
 
+void GraalRuntime::check_required_value(const char* name, int name_len, const char* value, TRAPS) {
+  if (value == NULL) {
+    char buf[200];
+    jio_snprintf(buf, sizeof(buf), "Must use '-G:%.*s=<value>' format for %.*s option", name_len, name, name_len, name);
+    THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
+  }
+}
+
 void GraalRuntime::parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS) {
   char first = arg[0];
   char* name;
   size_t name_len;
-  Handle name_handle;
-  bool valid = true;
+  bool recognized = true;
   if (first == '+' || first == '-') {
     name = arg + 1;
     name_len = strlen(name);
-    name_handle = java_lang_String::create_from_str(name, CHECK);
-    valid = set_option(hotSpotOptionsClass, name, (int)name_len, name_handle, arg, CHECK);
+    recognized = set_option(hotSpotOptionsClass, name, (int)name_len, arg, CHECK);
   } else {
     char* sep = strchr(arg, '=');
+    name = arg;
+    char* value = NULL;
     if (sep != NULL) {
-      name = arg;
       name_len = sep - name;
-      // Temporarily replace '=' with NULL to create the Java string for the option name
-      *sep = '\0';
-      name_handle = java_lang_String::create_from_str(arg, THREAD);
-      *sep = '=';
-      if (HAS_PENDING_EXCEPTION) {
-        return;
+      value = sep + 1;
+    } else {
+      name_len = strlen(name);
+    }
+    recognized = set_option(hotSpotOptionsClass, name, (int)name_len, value, CHECK);
+  }
+
+  if (!recognized) {
+    bool throw_err = hotSpotOptionsClass.is_null();
+    if (!hotSpotOptionsClass.is_null()) {
+      set_option_helper(hotSpotOptionsClass, name, name_len, Handle(), ' ', Handle(), 0L);
+      if (!HAS_PENDING_EXCEPTION) {
+        throw_err = true;
       }
-      valid = set_option(hotSpotOptionsClass, name, (int)name_len, name_handle, sep + 1, CHECK);
-    } else {
+    }
+
+    if (throw_err) {
       char buf[200];
-      jio_snprintf(buf, sizeof(buf), "Value for option %s must use '-G:%s=<value>' format", arg, arg);
+      jio_snprintf(buf, sizeof(buf), "Unrecognized Graal option %.*s", name_len, name);
       THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
     }
   }
-
-  if (!valid) {
-    set_option_helper(hotSpotOptionsClass, name_handle, Handle(), ' ', Handle(), 0L);
-    char buf[200];
-    jio_snprintf(buf, sizeof(buf), "Invalid Graal option %s", arg);
-    THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
-  }
 }
 
 void GraalRuntime::parse_graal_options_file(KlassHandle hotSpotOptionsClass, TRAPS) {
@@ -802,7 +839,8 @@
   }
 }
 
-jlong GraalRuntime::parse_primitive_option_value(char spec, Handle name, const char* value, TRAPS) {
+jlong GraalRuntime::parse_primitive_option_value(char spec, const char* name, int name_len, const char* value, TRAPS) {
+  check_required_value(name, name_len, value, CHECK_(0L));
   union {
     jint i;
     jlong l;
@@ -829,23 +867,44 @@
   }
   ResourceMark rm(THREAD);
   char buf[200];
-  jio_snprintf(buf, sizeof(buf), "Invalid %s value for Graal option %s: %s", (spec == 'i' ? "numeric" : "float/double"), java_lang_String::as_utf8_string(name()), value);
+  bool missing = strlen(value) == 0;
+  if (missing) {
+    jio_snprintf(buf, sizeof(buf), "Missing %s value for Graal option %.*s", (spec == 'i' ? "numeric" : "float/double"), name_len, name);
+  } else {
+    jio_snprintf(buf, sizeof(buf), "Invalid %s value for Graal option %.*s: %s", (spec == 'i' ? "numeric" : "float/double"), name_len, name, value);
+  }
   THROW_MSG_(vmSymbols::java_lang_InternalError(), buf, 0L);
 }
 
-void GraalRuntime::set_option_helper(KlassHandle hotSpotOptionsClass, Handle name, Handle option, jchar spec, Handle stringValue, jlong primitiveValue) {
+void GraalRuntime::set_option_helper(KlassHandle hotSpotOptionsClass, char* name, int name_len, Handle option, jchar spec, Handle stringValue, jlong primitiveValue) {
   Thread* THREAD = Thread::current();
+  Handle name_handle;
+  if (name != NULL) {
+    if ((int) strlen(name) > name_len) {
+      // Temporarily replace '=' with NULL to create the Java string for the option name
+      char save = name[name_len];
+      name[name_len] = '\0';
+      name_handle = java_lang_String::create_from_str(name, THREAD);
+      name[name_len] = '=';
+      if (HAS_PENDING_EXCEPTION) {
+        return;
+      }
+    } else {
+      assert((int) strlen(name) == name_len, "must be");
+      name_handle = java_lang_String::create_from_str(name, CHECK);
+    }
+  }
+
   TempNewSymbol setOption = SymbolTable::new_symbol("setOption", THREAD);
   TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/String;Lcom/oracle/graal/options/OptionValue;CLjava/lang/String;J)V", THREAD);
   JavaValue result(T_VOID);
   JavaCallArguments args;
-  args.push_oop(name());
+  args.push_oop(name_handle());
   args.push_oop(option());
   args.push_int(spec);
   args.push_oop(stringValue());
   args.push_long(primitiveValue);
-  JavaCalls::call_static(&result, hotSpotOptionsClass, setOption, sig, &args, THREAD);
-  GUARANTEE_NO_PENDING_EXCEPTION("Error while calling set_option_helper");
+  JavaCalls::call_static(&result, hotSpotOptionsClass, setOption, sig, &args, CHECK);
 }
 
 Handle GraalRuntime::get_OptionValue(const char* declaringClass, const char* fieldName, const char* fieldSig, TRAPS) {
@@ -900,20 +959,23 @@
   }
 }
 
-void GraalRuntime::abort_on_pending_exception(Handle exception, const char* message, bool dump_core) {
-  Thread* THREAD = Thread::current();
-  CLEAR_PENDING_EXCEPTION;
-
+void GraalRuntime::call_printStackTrace(Handle exception, Thread* thread) {
   assert(exception->is_a(SystemDictionary::Throwable_klass()), "Throwable instance expected");
   JavaValue result(T_VOID);
   JavaCalls::call_virtual(&result,
                           exception,
-                          KlassHandle(THREAD,
+                          KlassHandle(thread,
                           SystemDictionary::Throwable_klass()),
                           vmSymbols::printStackTrace_name(),
                           vmSymbols::void_method_signature(),
-                          THREAD);
+                          thread);
+}
 
+void GraalRuntime::abort_on_pending_exception(Handle exception, const char* message, bool dump_core) {
+  Thread* THREAD = Thread::current();
+  CLEAR_PENDING_EXCEPTION;
+  tty->print_cr(message);
+  call_printStackTrace(exception, THREAD);
   vm_abort(dump_core);
 }
 
--- a/src/share/vm/graal/graalRuntime.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -45,11 +45,12 @@
    * Parses the string form of a numeric, float or double option into a jlong (using raw bits for floats/doubles).
    *
    * @param spec 'i', 'f' or 'd' (see HotSpotOptions.setOption())
-   * @param name name option option
+   * @param name option name
+   * @param name_len length of option name
    * @param value string value to parse
    * @throws InternalError if value could not be parsed according to spec
    */
-  static jlong parse_primitive_option_value(char spec, Handle name, const char* value, TRAPS);
+  static jlong parse_primitive_option_value(char spec, const char* name, int name_len, const char* value, TRAPS);
 
   /**
    * Loads default option value overrides from a <jre_home>/lib/graal.options if it exists. Each
@@ -72,15 +73,26 @@
    * The definition of this method is in graalRuntime.inline.hpp
    * which is generated by com.oracle.graal.hotspot.sourcegen.GenGraalRuntimeInlineHpp.
    *
+   * @param hotSpotOptionsClass the HotSpotOptions klass or NULL if only checking for valid option
+   * @param name option name
+   * @param name_len length of option name
    * @returns true if the option was found
    * @throws InternalError if there was a problem setting the option's value
    */
-  static bool set_option(KlassHandle hotSpotOptionsClass, const char* name, int name_len, Handle name_handle, const char* value, TRAPS);
+  static bool set_option(KlassHandle hotSpotOptionsClass, char* name, int name_len, const char* value, TRAPS);
+
+  /**
+   * Raises an InternalError for an option that expects a value but was specified without a "=<value>" prefix.
+   */
+  static void check_required_value(const char* name, int name_len, const char* value, TRAPS);
 
   /**
    * Java call to HotSpotOptions.setOption(String name, OptionValue<?> option, char spec, String stringValue, long primitiveValue)
+   *
+   * @param name option name
+   * @param name_len length of option name
    */
-  static void set_option_helper(KlassHandle hotSpotOptionsClass, Handle name, Handle option, jchar spec, Handle stringValue, jlong primitiveValue);
+  static void set_option_helper(KlassHandle hotSpotOptionsClass, char* name, int name_len, Handle option, jchar spec, Handle stringValue, jlong primitiveValue);
 
   /**
    * Instantiates a service object, calls its default constructor and returns it.
@@ -122,6 +134,11 @@
    */
   static void abort_on_pending_exception(Handle exception, const char* message, bool dump_core = false);
 
+  /**
+   * Calls Throwable.printStackTrace() on a given exception.
+   */
+  static void call_printStackTrace(Handle exception, Thread* thread);
+
 #define GUARANTEE_NO_PENDING_EXCEPTION(error_message) do { \
     if (HAS_PENDING_EXCEPTION) { \
       GraalRuntime::abort_on_pending_exception(PENDING_EXCEPTION, error_message); \
@@ -132,6 +149,18 @@
 
   static BufferBlob* initialize_buffer_blob();
 
+  /**
+   * Checks that all Graal specific VM options presented by the launcher are recognized
+   * and formatted correctly. To set relevant Java fields from the option, parse_arguments()
+   * must be called. This method makes no Java calls apart from creating exception objects
+   * if there is an errors in the Graal options.
+   */
+  static jint check_arguments(TRAPS);
+
+  /**
+   * Parses the Graal specific VM options that were presented by the launcher and sets
+   * the relevants Java fields.
+   */
   static bool parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS);
 
   static BasicType kindToBasicType(jchar ch);
--- a/src/share/vm/prims/jni.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/prims/jni.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -5188,6 +5188,9 @@
       }
     } else {
       // Graal is initialized on a CompilerThread
+      if (FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal) {
+        GraalCompiler::instance()->bootstrap();
+      }
     }
 #endif
 
--- a/src/share/vm/runtime/advancedThresholdPolicy.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/runtime/advancedThresholdPolicy.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -345,6 +345,17 @@
       if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) {
         next_level = CompLevel_full_optimization;
       } else if ((this->*p)(i, b, cur_level)) {
+#ifdef COMPILERGRAAL
+        // Since Graal takes a while to warm up, its queue inevitably backs up during
+        // early VM execution. As of 2014-06-13, Graal's inliner assumes that the root
+        // compilation method and all potential inlinees have mature profiles (which
+        // includes type profiling). If it sees immature profiles, Graal's inliner
+        // can perform pathologically bad (e.g., causing OutOfMemoryErrors due to
+        // exploring/inlining too many graphs). Since a rewrite of the inliner is
+        // in progress, we simply disable the dialing back heuristic for now and will
+        // revisit this decision once the new inliner is completed.
+        next_level = CompLevel_full_profile;
+#else
         // C1-generated fully profiled code is about 30% slower than the limited profile
         // code that has only invocation and backedge counters. The observation is that
         // if C2 queue is large enough we can spend too much time in the fully profiled code
@@ -358,6 +369,7 @@
         } else {
           next_level = CompLevel_full_profile;
         }
+#endif
       }
       break;
     case CompLevel_limited_profile:
--- a/src/share/vm/runtime/deoptimization.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/runtime/deoptimization.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -1981,19 +1981,19 @@
   // Note:  Keep this in sync. with enum DeoptReason.
   "none",
   "null_check",
-  "null_assert" GRAAL_ONLY("|unreached0"),
+  "null_assert" GRAAL_ONLY("_or_unreached0"),
   "range_check",
   "class_check",
   "array_check",
-  "intrinsic" GRAAL_ONLY("|type_checked_inlining"),
-  "bimorphic" GRAAL_ONLY("|optimized_type_check"),
+  "intrinsic" GRAAL_ONLY("_or_type_checked_inlining"),
+  "bimorphic" GRAAL_ONLY("_or_optimized_type_check"),
   "unloaded",
-  "uninitialized" GRAAL_ONLY("|unresolved"),
+  "uninitialized" GRAAL_ONLY("_or_unresolved"),
   "unreached",
-  "unhandled" GRAAL_ONLY("|not_compiled_exception_handler"),
+  "unhandled" GRAAL_ONLY("_or_not_compiled_exception_handler"),
   "constraint",
   "div0_check",
-  "age" GRAAL_ONLY("|jsr_mismatch"),
+  "age" GRAAL_ONLY("_or_jsr_mismatch"),
   "predicate",
   "loop_limit_check",
   GRAAL_ONLY("aliasing")
--- a/src/share/vm/runtime/sharedRuntime.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/runtime/sharedRuntime.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -886,7 +886,7 @@
             // If there's no PcDesc then we'll die way down inside of
             // deopt instead of just getting normal error reporting,
             // so only go there if it will succeed.
-            target_pc = deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_null_check);
+            return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_null_check);
           } else {
 #endif
           target_pc = nm->continuation_for_implicit_exception(pc);
@@ -910,7 +910,7 @@
 #endif
 #ifdef GRAAL
         if (nm->is_compiled_by_graal() && nm->pc_desc_at(pc) != NULL) {
-          target_pc = deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_div0_check);
+          return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_div0_check);
         } else {
 #endif
         target_pc = nm->continuation_for_implicit_exception(pc);
@@ -928,11 +928,17 @@
 
     assert(exception_kind == IMPLICIT_NULL || exception_kind == IMPLICIT_DIVIDE_BY_ZERO, "wrong implicit exception kind");
 
-    // for AbortVMOnException flag
-    NOT_PRODUCT(Exceptions::debug_check_abort("java.lang.NullPointerException"));
     if (exception_kind == IMPLICIT_NULL) {
+#ifndef PRODUCT
+      // for AbortVMOnException flag
+      Exceptions::debug_check_abort("java.lang.NullPointerException");
+#endif //PRODUCT
       Events::log_exception(thread, "Implicit null exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc);
     } else {
+#ifndef PRODUCT
+      // for AbortVMOnException flag
+      Exceptions::debug_check_abort("java.lang.ArithmeticException");
+#endif //PRODUCT
       Events::log_exception(thread, "Implicit division by zero exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc);
     }
     return target_pc;
--- a/src/share/vm/runtime/thread.cpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/runtime/thread.cpp	Mon Jun 30 12:02:19 2014 +0200
@@ -31,6 +31,7 @@
 #include "compiler/compileBroker.hpp"
 #ifdef GRAAL
 #include "graal/graalCompiler.hpp"
+#include "graal/graalRuntime.hpp"
 #endif
 #include "interpreter/interpreter.hpp"
 #include "interpreter/linkResolver.hpp"
@@ -54,6 +55,9 @@
 #include "runtime/fprofiler.hpp"
 #include "runtime/frame.inline.hpp"
 #include "runtime/gpu.hpp"
+#ifdef GRAAL
+# include "hsail/vm/gpu_hsail.hpp"
+#endif
 #include "runtime/init.hpp"
 #include "runtime/interfaceSupport.hpp"
 #include "runtime/java.hpp"
@@ -1467,8 +1471,11 @@
   clear_must_deopt_id();
   set_monitor_chunks(NULL);
   set_next(NULL);
+#ifdef GRAAL
   set_gpu_exception_bci(0);
   set_gpu_exception_method(NULL);  
+  set_gpu_hsail_deopt_info(NULL);  
+#endif
   set_thread_state(_thread_new);
 #if INCLUDE_NMT
   set_recorder(NULL);
@@ -2853,6 +2860,13 @@
     // a scan.
     cf->do_code_blob(_scanned_nmethod);
   }
+
+#ifdef GRAAL
+  Hsail::HSAILDeoptimizationInfo* gpu_hsail_deopt_info = (Hsail::HSAILDeoptimizationInfo*) get_gpu_hsail_deopt_info();
+  if (gpu_hsail_deopt_info != NULL) {
+    gpu_hsail_deopt_info->oops_do(f);
+  }
+#endif
 }
 
 void JavaThread::nmethods_do(CodeBlobClosure* cf) {
@@ -3718,6 +3732,14 @@
     Chunk::start_chunk_pool_cleaner_task();
   }
 
+#ifdef GRAAL
+  status = GraalRuntime::check_arguments(main_thread);
+  if (status != JNI_OK) {
+    *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
+    return status;
+  }
+#endif
+
   // initialize compiler(s)
 #if defined(COMPILER1) || defined(COMPILER2) || defined(SHARK) || defined(COMPILERGRAAL)
   CompileBroker::compilation_init();
--- a/src/share/vm/runtime/thread.hpp	Mon Jun 30 08:50:26 2014 +0200
+++ b/src/share/vm/runtime/thread.hpp	Mon Jun 30 12:02:19 2014 +0200
@@ -944,15 +944,24 @@
   volatile address _exception_handler_pc;        // PC for handler of exception
   volatile int     _is_method_handle_return;     // true (== 1) if the current exception PC is a MethodHandle call site.
 
+#ifdef GRAAL
   // Record the method and bci from a gpu kernel exception so
   // it can be added into the exception stack trace
   jint    _gpu_exception_bci;
   Method* _gpu_exception_method;
+  // Record the hsailDeoptimization info so gc oops_do processing can find it
+  void*   _gpu_hsail_deopt_info;
+#endif
+
  public:
+#ifdef GRAAL
   void set_gpu_exception_bci(jint bci)           { _gpu_exception_bci = bci; } 
   jint get_gpu_exception_bci()                   { return _gpu_exception_bci; }
   void set_gpu_exception_method(Method* method)  { _gpu_exception_method = method; }
   Method* get_gpu_exception_method()             { return _gpu_exception_method; }
+  void set_gpu_hsail_deopt_info(void * deoptInfo) { _gpu_hsail_deopt_info = deoptInfo; }
+  void* get_gpu_hsail_deopt_info()               { return _gpu_hsail_deopt_info; }
+#endif
   
  private:  
   // support for JNI critical regions