changeset 12387:aff825fef0fd

Merge.
author Christian Humer <christian.humer@gmail.com>
date Wed, 02 Oct 2013 13:26:31 +0200
parents 91dbb0b7dc8b (current diff) 04b039d82e86 (diff)
children 96c1d057a5ed
files graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DeoptimizationAction.java graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ArrayTest.java graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlTest.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCSafepointOp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ArrayRangeWriteBarrier.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1ArrayRangePostWriteBarrier.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1ArrayRangePreWriteBarrier.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1PostWriteBarrier.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1PreWriteBarrier.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1ReferentFieldReadBarrier.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialArrayRangeWriteBarrier.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitAndNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitBooleanNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/WriteBarrier.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractCallNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InsertStateAfterPlaceholderPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/SafepointInsertionPhase.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/InlineTrivialGettersPhase.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/SlowPathExceptionSubstitutions.java mx/.pylintrc src/gpu/ptx/vm/kernelArguments.cpp src/gpu/ptx/vm/kernelArguments.hpp
diffstat 508 files changed, 12251 insertions(+), 7723 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri Sep 06 21:37:50 2013 +0200
+++ b/.hgignore	Wed Oct 02 13:26:31 2013 +0200
@@ -1,5 +1,7 @@
 ^mx/env
 ^mx/checkstyle-timestamps
+^mx/eclipseinit.timestamp
+^mx/netbeansinit.timestamp
 ^mx/eclipse-launches
 ^mx/ecj.jar
 ^mx/includes
--- a/README_GRAAL.txt	Fri Sep 06 21:37:50 2013 +0200
+++ b/README_GRAAL.txt	Wed Oct 02 13:26:31 2013 +0200
@@ -11,11 +11,30 @@
 
 % mx build
 
-This builds the 'product' version of HotSpot with the Graal modifications.
-To build the debug or fastdebug versions:
+There are a number of VM configurations supported by mx which can
+be explicitly specified using the --vm option. However, you'll typically
+want one of these VM configurations:
 
-  mx build debug
-  mx build fastdebug
+1. The 'server' configuration is a standard HotSpot VM that includes the
+   runtime support for Graal but uses the existing compilers for normal
+   compilation (e.g., when the interpreter threshold is hit for a method).
+   Compilation with Graal is only done by explicit requests to the
+   Graal API. This is how Truffle uses Graal.
+   
+2. The 'graal' configuration is a VM where all compilation is performed
+   by Graal and no other compilers are built into the VM binary. This
+   VM will bootstrap Graal itself at startup unless the -XX:-BootstrapGraal
+   VM option is given.   
+
+Unless you use the --vm option with the build command, you will be presented
+with a dialogue to choose one of the above VM configurations for the build
+as well as have the option to make it your default for subsequent commands
+that need a VM specified.
+
+To build the debug or fastdebug builds:
+
+% mx --vmbuild debug build
+% mx --vmbuild fastdebug build
 
 Running Graal
 -------------
@@ -24,47 +43,28 @@
 
 % mx vm ...
 
-To select the fastdebug or debug versions of the VM:
-
-% mx --fastdebug vm ...
-% mx --debug vm ...
+To select the fastdebug or debug builds of the VM:
 
-Graal has an optional bootstrap step where it compiles itself before
-compiling any application code. This bootstrap step currently takes about 7 seconds
-on a fast x64 machine. It's useful to disable this bootstrap step when running small
-programs with the -XX:-BootstrapGraal options. For example:
+% mx --vmbuild fastdebug vm ...
+% mx --vmbuild debug vm ...
 
-% mx vm -XX:-BootstrapGraal ...
-
+Other VM Configurations
+-----------------------
 
-Other Build Configurations
---------------------------
-
-By default the build commands above create a HotSpot binary where Graal
-is the only compiler. This binary is the Graal VM binary and identifies as
-such with the -version option:
+In addition to the VM configurations described above, there are
+VM configurations that omit all VM support for Graal:
 
-% mx vm -XX:-BootstrapGraal -version
-java version "1.7.0_07"
-Java(TM) SE Runtime Environment (build 1.7.0_07-b10)
-OpenJDK 64-Bit Graal VM (build 25.0-b10-internal, mixed mode)
-
-It's also possible to build and execute the standard HotSpot binaries
-using the --vm option:
+% mx --vm server-nograal build
+% mx --vm server-nograal vm -version
+java version "1.7.0_25"
+Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
+OpenJDK 64-Bit Server VM (build 25.0-b43-internal, mixed mode)
 
-% mx --vm server build
-% mx --vm server vm -version
-java version "1.7.0_07"
-Java(TM) SE Runtime Environment (build 1.7.0_07-b10)
-OpenJDK 64-Bit Server VM (build 25.0-b10-internal, mixed mode)
+% mx --vm client-nograal build
+% mx --vm client-nograal vm -version
+java version "1.7.0_25"
+Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
+OpenJDK 64-Bit Cleint VM (build 25.0-b43-internal, mixed mode)
 
-These standard binaries still include the code necessary to support use of the
-Graal compiler for explicit compilation requests. However, in this configuration
-the Graal compiler will not service VM issued compilation requests (e.g., upon
-counter overflow in the interpreter).
-
-To build a HotSpot binary that completely omits all VM support for Graal,
-define an environment variable OMIT_GRAAL (its value does not matter) and build
-with the --vm option as above (doing a clean first if necessary):
-
-% env OMIT_GRAAL= mx --vm server build
+These configurations aim to match as closely as possible the
+VM(s) included in the OpenJDK binaries one can download.
\ No newline at end of file
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ArithmeticOperation.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ArithmeticOperation.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,9 +22,13 @@
  */
 package com.oracle.graal.api.code;
 
+import com.oracle.graal.api.meta.*;
+
 /**
  * An {@code ArithmeticOperation} is an operation that does primitive value arithmetic without side
  * effect.
  */
 public interface ArithmeticOperation {
+
+    Constant evalConst(Constant... inputs);
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Wed Oct 02 13:26:31 2013 +0200
@@ -151,7 +151,7 @@
     private boolean verify() {
         for (int i = 0; i < argumentLocations.length; i++) {
             Value location = argumentLocations[i];
-            assert isStackSlot(location) || isRegister(location);
+            assert isStackSlot(location) || isAllocatableValue(location);
         }
         return true;
     }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Wed Oct 02 13:26:31 2013 +0200
@@ -72,13 +72,6 @@
     ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor);
 
     /**
-     * Encodes a deoptimization action and a deoptimization reason in an integer value.
-     * 
-     * @return the encoded value as an integer
-     */
-    int encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason);
-
-    /**
      * Determines if a {@link DataPatch} should be created for a given
      * {@linkplain Constant#getPrimitiveAnnotation() annotated} primitive constant that part of a
      * {@link CompilationResult}. A data patch is always created for an object constant.
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java	Wed Oct 02 13:26:31 2013 +0200
@@ -44,7 +44,6 @@
     private final BytecodePosition bytecodePosition;
     private final BitSet registerRefMap;
     private final BitSet frameRefMap;
-    private final short deoptimizationReason;
     private RegisterSaveLayout calleeSaveInfo;
 
     /**
@@ -55,11 +54,10 @@
      * @param registerRefMap the register map
      * @param frameRefMap the reference map for {@code frame}, which may be {@code null}
      */
-    public DebugInfo(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap, short deoptimizationReason) {
+    public DebugInfo(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap) {
         this.bytecodePosition = codePos;
         this.registerRefMap = registerRefMap;
         this.frameRefMap = frameRefMap;
-        this.deoptimizationReason = deoptimizationReason;
     }
 
     /**
@@ -127,15 +125,6 @@
     }
 
     /**
-     * Identifies the reason in case a deoptimization happens at this program counter.
-     * 
-     * @return the reason of the deoptimization
-     */
-    public short getDeoptimizationReason() {
-        return deoptimizationReason;
-    }
-
-    /**
      * Sets the map from the registers (in the caller's frame) to the slots where they are saved in
      * the current frame.
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DelegatingCodeCacheProvider.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,68 @@
+/*
+ * 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.api.code;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * A {@link CodeCacheProvider} that delegates to another {@link CodeCacheProvider}.
+ */
+public class DelegatingCodeCacheProvider extends DelegatingMetaAccessProvider implements CodeCacheProvider {
+
+    public DelegatingCodeCacheProvider(CodeCacheProvider delegate) {
+        super(delegate);
+    }
+
+    @Override
+    protected CodeCacheProvider delegate() {
+        return (CodeCacheProvider) super.delegate();
+    }
+
+    public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) {
+        return delegate().addMethod(method, compResult);
+    }
+
+    public String disassemble(CompilationResult compResult, InstalledCode installedCode) {
+        return delegate().disassemble(compResult, installedCode);
+    }
+
+    public RegisterConfig lookupRegisterConfig() {
+        return delegate().lookupRegisterConfig();
+    }
+
+    public int getMinimumOutgoingSize() {
+        return delegate().getMinimumOutgoingSize();
+    }
+
+    public ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) {
+        return delegate().lookupForeignCall(descriptor);
+    }
+
+    public boolean needsDataPatch(Constant constant) {
+        return delegate().needsDataPatch(constant);
+    }
+
+    public TargetDescription getTarget() {
+        return delegate().getTarget();
+    }
+}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DeoptimizationAction.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * 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.api.code;
-
-/**
- * Specifies the action that should be taken by the runtime in case a certain deoptimization is
- * triggered.
- */
-public enum DeoptimizationAction {
-    /**
-     * Do not invalidate the machine code. This is typically used when deoptimizing at a point where
-     * it's highly likely nothing will change the likelihood of the deoptimization happening again.
-     * For example, a compiled array allocation where the size is negative.
-     */
-    None(false),
-
-    /**
-     * Do not invalidate the machine code, but schedule a recompilation if this deoptimization is
-     * triggered too often.
-     */
-    RecompileIfTooManyDeopts(true),
-
-    /**
-     * Invalidate the machine code and reset the profiling information.
-     */
-    InvalidateReprofile(true),
-
-    /**
-     * Invalidate the machine code and immediately schedule a recompilation. This is typically used
-     * when deoptimizing to resolve an unresolved symbol in which case extra profiling is not
-     * required to determine that the deoptimization will not re-occur.
-     */
-    InvalidateRecompile(true),
-
-    /**
-     * Invalidate the machine code and stop compiling the outermost method of this compilation.
-     */
-    InvalidateStopCompiling(true);
-
-    private final boolean invalidatesCompilation;
-
-    private DeoptimizationAction(boolean invalidatesCompilation) {
-        this.invalidatesCompilation = invalidatesCompilation;
-    }
-
-    public boolean doesInvalidateCompilation() {
-        return invalidatesCompilation;
-    }
-
-}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/SpeculationLog.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/SpeculationLog.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,11 +36,11 @@
 
     public static final int MAX_CACHE_SIZE = 1 << 15;
 
-    private List<DeoptimizationReason> speculations = new ArrayList<>();
+    private List<Object> speculations = new ArrayList<>();
     private boolean[] map = new boolean[10];
-    private Set<DeoptimizationReason> snapshot = new HashSet<>();
+    private Set<Object> snapshot = new HashSet<>();
 
-    public short addSpeculation(DeoptimizationReason reason) {
+    private short addSpeculation(Object reason) {
         short index = (short) speculations.indexOf(reason);
         if (index != -1) {
             // Nothing to add, reason already registered.
@@ -68,7 +68,10 @@
         }
     }
 
-    public boolean maySpeculate(DeoptimizationReason reason) {
-        return !snapshot.contains(reason);
+    public Constant maySpeculate(Object reason) {
+        if (snapshot.contains(reason)) {
+            return null;
+        }
+        return Constant.forShort(addSpeculation(reason));
     }
 }
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java	Wed Oct 02 13:26:31 2013 +0200
@@ -107,15 +107,13 @@
     @Test
     public void lookupArrayLengthTest() {
         for (Constant c : constants) {
+            Integer actual = runtime.lookupArrayLength(c);
             if (c.getKind() != Kind.Object || c.isNull() || !c.asObject().getClass().isArray()) {
-                try {
-                    int length = runtime.lookupArrayLength(c);
-                    fail("Expected " + IllegalArgumentException.class.getName() + " for " + c + ", not " + length);
-                } catch (IllegalArgumentException e) {
-                    // pass
-                }
+                assertNull(actual);
             } else {
-                assertEquals(Array.getLength(c.asObject()), runtime.lookupArrayLength(c));
+                assertNotNull(actual);
+                int actualInt = actual;
+                assertEquals(Array.getLength(c.asObject()), actualInt);
             }
         }
     }
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Wed Oct 02 13:26:31 2013 +0200
@@ -265,7 +265,9 @@
         ResolvedJavaMethod method2 = runtime.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class));
         assertEquals(0, method1.getMaxStackSize());
         // some versions of javac produce bytecode with a stacksize of 2 for this method
-        assertTrue(3 == method2.getMaxStackSize() || 2 == method2.getMaxStackSize());
+        // JSR 292 also sometimes need one more stack slot
+        int method2StackSize = method2.getMaxStackSize();
+        assertTrue(2 <= method2StackSize && method2StackSize <= 4);
     }
 
     private Method findTestMethod(Method apiMethod) {
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Wed Oct 02 13:26:31 2013 +0200
@@ -399,9 +399,11 @@
             }
             for (Method m : c.getDeclaredMethods()) {
                 if (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers())) {
-                    Method overridden = vtable.methods.put(new NameAndSignature(m), m);
-                    if (overridden != null) {
-                        // println(m + " overrides " + overridden);
+                    if (isAbstract(m.getModifiers())) {
+                        // A subclass makes a concrete method in a superclass abstract
+                        vtable.methods.remove(new NameAndSignature(m));
+                    } else {
+                        vtable.methods.put(new NameAndSignature(m), m);
                     }
                 }
             }
@@ -438,7 +440,13 @@
     @Test
     public void resolveMethodTest() {
         for (Class c : classes) {
-            if (!c.isPrimitive() && !c.isInterface()) {
+            if (c.isInterface() || c.isPrimitive()) {
+                ResolvedJavaType type = runtime.lookupJavaType(c);
+                for (Method m : c.getDeclaredMethods()) {
+                    ResolvedJavaMethod impl = type.resolveMethod(runtime.lookupJavaMethod(m));
+                    assertEquals(m.toString(), null, impl);
+                }
+            } else {
                 ResolvedJavaType type = runtime.lookupJavaType(c);
                 VTable vtable = getVTable(c);
                 for (Method impl : vtable.methods.values()) {
@@ -449,6 +457,11 @@
                         checkResolveMethod(type, m, i);
                     }
                 }
+                for (Method m : c.getDeclaredMethods()) {
+                    ResolvedJavaMethod impl = type.resolveMethod(runtime.lookupJavaMethod(m));
+                    ResolvedJavaMethod expected = isAbstract(m.getModifiers()) ? null : impl;
+                    assertEquals(type + " " + m.toString(), expected, impl);
+                }
             }
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DelegatingMetaAccessProvider.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,93 @@
+/*
+ * 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.api.meta;
+
+import java.lang.reflect.*;
+
+/**
+ * A {@link MetaAccessProvider} that delegates to another {@link MetaAccessProvider}.
+ */
+public class DelegatingMetaAccessProvider implements MetaAccessProvider {
+
+    private final MetaAccessProvider delegate;
+
+    public DelegatingMetaAccessProvider(MetaAccessProvider delegate) {
+        this.delegate = delegate;
+    }
+
+    protected MetaAccessProvider delegate() {
+        return delegate;
+    }
+
+    public ResolvedJavaType lookupJavaType(Class<?> clazz) {
+        return delegate.lookupJavaType(clazz);
+    }
+
+    public ResolvedJavaMethod lookupJavaMethod(Method reflectionMethod) {
+        return delegate.lookupJavaMethod(reflectionMethod);
+    }
+
+    public ResolvedJavaMethod lookupJavaConstructor(Constructor reflectionConstructor) {
+        return delegate.lookupJavaConstructor(reflectionConstructor);
+    }
+
+    public ResolvedJavaField lookupJavaField(Field reflectionField) {
+        return delegate.lookupJavaField(reflectionField);
+    }
+
+    public ResolvedJavaType lookupJavaType(Constant constant) {
+        return delegate.lookupJavaType(constant);
+    }
+
+    public Signature parseMethodDescriptor(String methodDescriptor) {
+        return delegate.parseMethodDescriptor(methodDescriptor);
+    }
+
+    public boolean constantEquals(Constant x, Constant y) {
+        return delegate.constantEquals(x, y);
+    }
+
+    public Integer lookupArrayLength(Constant array) {
+        return delegate.lookupArrayLength(array);
+    }
+
+    public Constant readUnsafeConstant(Kind kind, Object base, long displacement, boolean compressible) {
+        return delegate.readUnsafeConstant(kind, base, displacement, compressible);
+    }
+
+    public boolean isReexecutable(ForeignCallDescriptor descriptor) {
+        return delegate.isReexecutable(descriptor);
+    }
+
+    public LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor) {
+        return delegate.getKilledLocations(descriptor);
+    }
+
+    public boolean canDeoptimize(ForeignCallDescriptor descriptor) {
+        return delegate.canDeoptimize(descriptor);
+    }
+
+    public Constant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason) {
+        return delegate().encodeDeoptActionAndReason(action, reason);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationAction.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,70 @@
+/*
+ * 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.api.meta;
+
+/**
+ * Specifies the action that should be taken by the runtime in case a certain deoptimization is
+ * triggered.
+ */
+public enum DeoptimizationAction {
+    /**
+     * Do not invalidate the machine code. This is typically used when deoptimizing at a point where
+     * it's highly likely nothing will change the likelihood of the deoptimization happening again.
+     * For example, a compiled array allocation where the size is negative.
+     */
+    None(false),
+
+    /**
+     * Do not invalidate the machine code, but schedule a recompilation if this deoptimization is
+     * triggered too often.
+     */
+    RecompileIfTooManyDeopts(true),
+
+    /**
+     * Invalidate the machine code and reset the profiling information.
+     */
+    InvalidateReprofile(true),
+
+    /**
+     * Invalidate the machine code and immediately schedule a recompilation. This is typically used
+     * when deoptimizing to resolve an unresolved symbol in which case extra profiling is not
+     * required to determine that the deoptimization will not re-occur.
+     */
+    InvalidateRecompile(true),
+
+    /**
+     * Invalidate the machine code and stop compiling the outermost method of this compilation.
+     */
+    InvalidateStopCompiling(true);
+
+    private final boolean invalidatesCompilation;
+
+    private DeoptimizationAction(boolean invalidatesCompilation) {
+        this.invalidatesCompilation = invalidatesCompilation;
+    }
+
+    public boolean doesInvalidateCompilation() {
+        return invalidatesCompilation;
+    }
+
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java	Wed Oct 02 13:26:31 2013 +0200
@@ -79,11 +79,11 @@
     boolean constantEquals(Constant x, Constant y);
 
     /**
-     * Returns the length of an array that is wrapped in a {@link Constant} object.
-     * 
-     * @throws IllegalArgumentException if {@code array} is not an array
+     * Returns the length of an array that is wrapped in a {@link Constant} object. If {@code array}
+     * is not an array, or the array length is not available at this point, the return value is
+     * {@code null}.
      */
-    int lookupArrayLength(Constant array);
+    Integer lookupArrayLength(Constant array);
 
     /**
      * Reads a value of this kind using a base address and a displacement.
@@ -113,4 +113,11 @@
      * Determines if deoptimization can occur during a given foreign call.
      */
     boolean canDeoptimize(ForeignCallDescriptor descriptor);
+
+    /**
+     * Encodes a deoptimization action and a deoptimization reason in an integer value.
+     * 
+     * @return the encoded value as an integer
+     */
+    Constant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason);
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Wed Oct 02 13:26:31 2013 +0200
@@ -50,17 +50,21 @@
     boolean isSynthetic();
 
     /**
-     * Gets the constant value of this field for a given object, if available.
+     * Gets the constant value of this field. Note that a {@code static final} field may not be
+     * considered constant if its declaring class is not yet initialized or if it is a well known
+     * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}).
      * 
      * @param receiver object from which this field's value is to be read. This value is ignored if
      *            this field is static.
-     * @return the constant value of this field or {@code null} if the constant value is not
-     *         available
+     * @return the constant value of this field or {@code null} if this field is not considered
+     *         constant by the runtime
      */
     Constant readConstantValue(Constant receiver);
 
     /**
-     * Gets the current value of this field for a given object, if available.
+     * Gets the current value of this field for a given object, if available. There is no guarantee
+     * that the same value will be returned by this method for a field unless the field is
+     * considered to be {@link #readConstantValue(Constant)} by the runtime.
      * 
      * @param receiver object from which this field's value is to be read. This value is ignored if
      *            this field is static.
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Wed Oct 02 13:26:31 2013 +0200
@@ -175,12 +175,14 @@
     boolean canBeInlined();
 
     /**
-     * Returns the LineNumberTable of this method.
+     * Returns the LineNumberTable of this method or null if this method does not have a line
+     * numbers table.
      */
     LineNumberTable getLineNumberTable();
 
     /**
-     * Returns the localvariable table of this method.
+     * Returns the local variable table of this method or null if this method does not have a local
+     * variable table.
      */
     LocalVariableTable getLocalVariableTable();
 
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Wed Oct 02 13:26:31 2013 +0200
@@ -112,7 +112,7 @@
     int getModifiers();
 
     /**
-     * Checks whether this type is initialized. If a type is initialized it implies that is was
+     * Checks whether this type is initialized. If a type is initialized it implies that it was
      * {@link #isLinked() linked} and that the static initializer has run.
      * 
      * @return {@code true} if this type is initialized
@@ -205,10 +205,13 @@
 
     /**
      * Resolves the method implementation for virtual dispatches on objects of this dynamic type.
+     * This resolution process only searches "up" the class hierarchy of this type. A broader search
+     * that also walks "down" the hierarchy is implemented by
+     * {@link #findUniqueConcreteMethod(ResolvedJavaMethod)}.
      * 
      * @param method the method to select the implementation of
-     * @return the method implementation that would be selected at runtime, or {@code null} if the
-     *         runtime cannot resolve the method at this point in time.
+     * @return the concrete method that would be selected at runtime, or {@code null} if there is no
+     *         concrete implementation of {@code method} in this type or any of its superclasses
      */
     ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method);
 
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Wed Oct 02 13:26:31 2013 +0200
@@ -747,7 +747,7 @@
         emitOperandHelper(0, dst);
     }
 
-    private void jcc(ConditionFlag cc, int jumpTarget, boolean forceDisp32) {
+    public void jcc(ConditionFlag cc, int jumpTarget, boolean forceDisp32) {
         int shortSize = 2;
         int longSize = 6;
         long disp = jumpTarget - codeBuffer.position();
--- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAddress.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAddress.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.asm.ptx;
 
+import com.oracle.graal.lir.Variable;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 
@@ -31,7 +32,7 @@
  */
 public final class PTXAddress extends AbstractAddress {
 
-    private final Register base;
+    private final Variable base;
     private final long displacement;
 
     /**
@@ -39,7 +40,7 @@
      * 
      * @param base the base register
      */
-    public PTXAddress(Register base) {
+    public PTXAddress(Variable base) {
         this(base, 0);
     }
 
@@ -50,7 +51,7 @@
      * @param base the base register
      * @param displacement the displacement
      */
-    public PTXAddress(Register base, long displacement) {
+    public PTXAddress(Variable base, long displacement) {
         this.base = base;
         this.displacement = displacement;
     }
@@ -59,7 +60,7 @@
      * @return Base register that defines the start of the address computation. If not present, is
      *         denoted by {@link Value#ILLEGAL}.
      */
-    public Register getBase() {
+    public Variable getBase() {
         return base;
     }
 
--- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,17 @@
  */
 package com.oracle.graal.asm.ptx;
 
-import com.oracle.graal.api.code.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import com.oracle.graal.api.code.Register;
+import com.oracle.graal.api.code.RegisterConfig;
+import com.oracle.graal.api.code.TargetDescription;
+import com.oracle.graal.api.meta.Constant;
+import com.oracle.graal.api.meta.Kind;
+import com.oracle.graal.api.meta.Value;
+import com.oracle.graal.nodes.calc.Condition;
+import com.oracle.graal.graph.GraalInternalError;
+import com.oracle.graal.lir.Variable;
 
 public class PTXAssembler extends AbstractPTXAssembler {
 
@@ -30,535 +40,549 @@
         super(target);
     }
 
-    public final void at() {
-        emitString("@%p" + " " + "");
+    public enum ConditionOperator {
+        // @formatter:off
+
+        // Signed integer operators
+        S_EQ("eq"),
+        S_NE("ne"),
+        S_LT("lt"),
+        S_LE("le"),
+        S_GT("gt"),
+        S_GE("ge"),
+
+        // Unsigned integer operators
+        U_EQ("eq"),
+        U_NE("ne"),
+        U_LO("lo"),
+        U_LS("ls"),
+        U_HI("hi"),
+        U_HS("hs"),
+
+        // Bit-size integer operators
+        B_EQ("eq"),
+        B_NE("ne"),
+
+        // Floating-point operators
+        F_EQ("eq"),
+        F_NE("ne"),
+        F_LT("lt"),
+        F_LE("le"),
+        F_GT("gt"),
+        F_GE("ge"),
+
+        // Floating-point operators accepting NaN
+        F_EQU("equ"),
+        F_NEU("neu"),
+        F_LTU("ltu"),
+        F_LEU("leu"),
+        F_GTU("gtu"),
+        F_GEU("geu"),
+
+        // Floating-point operators testing for NaN
+        F_NUM("num"),
+        F_NAN("nan");
+
+        // @formatter:on
+
+        private final String operator;
+
+        private ConditionOperator(String op) {
+            this.operator = op;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+    }
+
+    public static class StandardFormat {
+
+        protected Kind valueKind;
+        protected Variable dest;
+        protected Value source1;
+        protected Value source2;
+        private boolean logicInstruction = false;
+
+        public StandardFormat(Variable dst, Value src1, Value src2) {
+            setDestination(dst);
+            setSource1(src1);
+            setSource2(src2);
+            setKind(dst.getKind());
+
+            // testAdd2B fails this assertion
+            // assert valueKind == src1.getKind();
+        }
+
+        public void setKind(Kind k) {
+            valueKind = k;
+        }
+
+        public void setDestination(Variable var) {
+            assert var != null;
+            dest = var;
+        }
+
+        public void setSource1(Value val) {
+            assert val != null;
+            source1 = val;
+        }
+
+        public void setSource2(Value val) {
+            assert val != null;
+            source2 = val;
+        }
+
+        public void setLogicInstruction(boolean b) {
+            logicInstruction = b;
+        }
+
+        public String typeForKind(Kind k) {
+            if (logicInstruction) {
+                switch (k.getTypeChar()) {
+                    case 's':
+                        return "b16";
+                    case 'i':
+                        return "b32";
+                    case 'j':
+                        return "b64";
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            } else {
+                switch (k.getTypeChar()) {
+                    case 'z':
+                        return "u8";
+                    case 'b':
+                        return "s8";
+                    case 's':
+                        return "s16";
+                    case 'c':
+                        return "u16";
+                    case 'i':
+                        return "s32";
+                    case 'f':
+                        return "f32";
+                    case 'j':
+                        return "s64";
+                    case 'd':
+                        return "f64";
+                    case 'a':
+                        return "u64";
+                    case '-':
+                        return "u32";
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+        }
+
+        public String emit() {
+            return (typeForKind(valueKind) + emitRegister(dest, true) + emitValue(source1, true) + emitValue(source2, false) + ";");
+        }
+
+        public String emitValue(Value v, boolean comma) {
+            assert v != null;
+
+            if (isConstant(v)) {
+                return (emitConstant(v));
+            } else {
+                return (emitRegister((Variable) v, comma));
+            }
+        }
+
+        public String emitRegister(Variable v, boolean comma) {
+            return (" %r" + v.index + (comma ? "," : ""));
+        }
+
+        public String emitConstant(Value v) {
+            Constant constant = (Constant) v;
+
+            switch (v.getKind().getTypeChar()) {
+                case 'i':
+                    return (String.valueOf((int) constant.asLong()));
+                case 'f':
+                    return (String.valueOf(constant.asFloat()));
+                case 'j':
+                    return (String.valueOf(constant.asLong()));
+                case 'd':
+                    return (String.valueOf(constant.asDouble()));
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
     }
 
-    public final void atq() {
-        emitString("@%q" + " " + "");
+    public static class SingleOperandFormat {
+
+        protected Variable dest;
+        protected Value    source;
+
+        public SingleOperandFormat(Variable dst, Value src) {
+            setDestination(dst);
+            setSource(src);
+        }
+
+        public void setDestination(Variable var) {
+            dest = var;
+        }
+
+        public void setSource(Value var) {
+            source = var;
+        }
+
+        public String typeForKind(Kind k) {
+            switch (k.getTypeChar()) {
+                case 'z':
+                    return "u8";
+                case 'b':
+                    return "s8";
+                case 's':
+                    return "s16";
+                case 'c':
+                    return "u16";
+                case 'i':
+                    return "s32";
+                case 'f':
+                    return "f32";
+                case 'j':
+                    return "s64";
+                case 'd':
+                    return "f64";
+                case 'a':
+                    return "u64";
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+
+        public String emit() {
+            return (typeForKind(dest.getKind()) + " " + emitVariable(dest) + ", " + emitValue(source) + ";");
+        }
+
+        public String emitValue(Value v) {
+            assert v != null;
+
+            if (isConstant(v)) {
+                return (emitConstant(v));
+            } else {
+                return (emitVariable((Variable) v));
+            }
+        }
+
+        public String emitConstant(Value v) {
+            Constant constant = (Constant) v;
+
+            switch (v.getKind().getTypeChar()) {
+                case 'i':
+                    return (String.valueOf((int) constant.asLong()));
+                case 'f':
+                    return (String.valueOf(constant.asFloat()));
+                case 'j':
+                    return (String.valueOf(constant.asLong()));
+                case 'd':
+                    return (String.valueOf(constant.asDouble()));
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+
+        public String emitVariable(Variable v) {
+            String name = v.getName();
+
+            if (name == null) {
+                return (" %r" + v.index);
+            } else {
+                return name;
+            }
+        }
+    }
+
+    public static class ConversionFormat extends SingleOperandFormat {
+
+        public ConversionFormat(Variable dst, Value src) {
+            super(dst, src);
+        }
+
+        @Override
+        public String emit() {
+            return (typeForKind(dest.getKind()) + "." + typeForKind(source.getKind()) + " " +
+                    emitVariable(dest) + ", " + emitValue(source) + ";");
+        }
+    }
+
+    public static class LoadStoreFormat extends StandardFormat {
+
+        protected PTXStateSpace space;
+
+        public LoadStoreFormat(PTXStateSpace space, Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+            setStateSpace(space);
+        }
+
+        public void setStateSpace(PTXStateSpace ss) {
+            space = ss;
+        }
+
+        public String emitAddress(Value var, Value val) {
+            assert var instanceof Variable;
+            assert val instanceof Constant;
+            Constant constant = (Constant) val;
+            return ("[" + emitRegister((Variable) var, false) + " + " + constant.asBoxedValue() + "]");
+        }
+
+        @Override
+        public String emitRegister(Variable var, boolean comma) {
+            /* if (space == Parameter) {
+                return ("param" + var.index);
+            } else {
+                return ("%r" + var.index);
+            } */
+            return ("%r" + var.index);
+        }
+
+        public String emit(boolean isLoad) {
+            if (isLoad) {
+                return (space.getStateName() + "." + typeForKind(valueKind) + " " +
+                        emitRegister(dest, false) + ", " + emitAddress(source1, source2) + ";");
+            } else {
+                return (space.getStateName() + "." + typeForKind(valueKind) + " " +
+                        emitAddress(source1, source2) + ", " + emitRegister(dest, false) + ";");
+            }
+        }
+    }
+
+    public static class Add extends StandardFormat {
+
+        public Add(Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+        }
+
+        public void emit(PTXAssembler asm) {
+            asm.emitString("add." + super.emit());
+        }
+    }
+
+    public static class And extends StandardFormat {
+
+        public And(Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+            setLogicInstruction(true);
+        }
+
+        public void emit(PTXAssembler asm) {
+            asm.emitString("and." + super.emit());
+        }
+    }
+
+    public static class Div extends StandardFormat {
+
+        public Div(Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+        }
+
+        public void emit(PTXAssembler asm) {
+            asm.emitString("div." + super.emit());
+        }
+    }
+
+    public static class Mul extends StandardFormat {
+
+        public Mul(Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+        }
+
+        public void emit(PTXAssembler asm) {
+            asm.emitString("mul.lo." + super.emit());
+        }
+    }
+
+    public static class Or extends StandardFormat {
+
+        public Or(Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+            setLogicInstruction(true);
+        }
+
+        public void emit(PTXAssembler asm) {
+            asm.emitString("or." + super.emit());
+        }
+    }
+
+    public static class Rem extends StandardFormat {
+
+        public Rem(Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+        }
+
+        public void emit(PTXAssembler asm) {
+            asm.emitString("rem." + super.emit());
+        }
+    }
+
+    public static class Shl extends StandardFormat {
+
+        public Shl(Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+            setLogicInstruction(true);
+        }
+
+        public void emit(PTXAssembler asm) {
+            asm.emitString("shl." + super.emit());
+        }
+    }
+
+    public static class Shr extends StandardFormat {
+
+        public Shr(Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+        }
+
+        public void emit(PTXAssembler asm) {
+            asm.emitString("shr." + super.emit());
+        }
+    }
+
+    public static class Sub extends StandardFormat {
+
+        public Sub(Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+        }
+
+        public void emit(PTXAssembler asm) {
+            asm.emitString("sub." + super.emit());
+        }
+    }
+
+    public static class Ushr extends StandardFormat {
+
+        public Ushr(Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+            setKind(Kind.Illegal);  // get around not having an Unsigned Kind
+        }
+
+        public void emit(PTXAssembler asm) {
+            asm.emitString("shr." + super.emit());
+        }
+    }
+
+    public static class Xor extends StandardFormat {
+
+        public Xor(Variable dst, Value src1, Value src2) {
+            super(dst, src1, src2);
+            setLogicInstruction(true);
+        }
+
+        public void emit(PTXAssembler asm) {
+            asm.emitString("xor." + super.emit());
+        }
     }
 
     // Checkstyle: stop method name check
-    public final void add_f32(Register d, Register a, Register b) {
-        emitString("add.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void add_f64(Register d, Register a, Register b) {
-        emitString("add.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void add_s16(Register d, Register a, Register b) {
-        emitString("add.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void add_s32(Register d, Register a, Register b) {
-        emitString("add.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void add_s64(Register d, Register a, Register b) {
-        emitString("add.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void add_s16(Register d, Register a, short s16) {
-        emitString("add.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s16 + ";" + "");
-    }
-
-    public final void add_s32(Register d, Register a, int s32) {
-        emitString("add.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void add_s64(Register d, Register a, long s64) {
-        emitString("add.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + "");
-    }
-
-    public final void add_f32(Register d, Register a, float f32) {
-        emitString("add.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f32 + ";" + "");
-    }
-
-    public final void add_f64(Register d, Register a, double f64) {
-        emitString("add.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f64 + ";" + "");
-    }
-
-    public final void add_u16(Register d, Register a, Register b) {
-        emitString("add.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void add_u32(Register d, Register a, Register b) {
-        emitString("add.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void add_u64(Register d, Register a, Register b) {
-        emitString("add.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void add_u16(Register d, Register a, short u16) {
-        emitString("add.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u16 + ";" + "");
-    }
-
-    public final void add_u32(Register d, Register a, int u32) {
-        emitString("add.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void add_u64(Register d, Register a, long u64) {
-        emitString("add.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u64 + ";" + "");
-    }
-
-    public final void add_sat_s32(Register d, Register a, Register b) {
-        emitString("add.sat.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void add_sat_s32(Register d, Register a, int s32) {
-        emitString("add.sat.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void and_b16(Register d, Register a, Register b) {
-        emitString("and.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void and_b32(Register d, Register a, Register b) {
-        emitString("and.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void and_b64(Register d, Register a, Register b) {
-        emitString("and.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void and_b16(Register d, Register a, short b16) {
-        emitString("and.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b16 + ";" + "");
-    }
-
-    public final void and_b32(Register d, Register a, int b32) {
-        emitString("and.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b32 + ";" + "");
-    }
-
-    public final void and_b64(Register d, Register a, long b64) {
-        emitString("and.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b64 + ";" + "");
-    }
-
-    public final void bra(String tgt) {
-        emitString("bra" + " " + tgt + ";" + "");
+    public final void bra(String tgt, int pred) {
+        emitString((pred >= 0) ? "" : ("@%p" + pred + "  ") + "bra" + " " + tgt + ";" + "");
     }
 
     public final void bra_uni(String tgt) {
         emitString("bra.uni" + " " + tgt + ";" + "");
     }
 
-    public final void cvt_s32_f32(Register d, Register a) {
-        emitString("cvt.s32.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
+    public static class Cvt extends ConversionFormat {
+
+        public Cvt(Variable dst, Variable src) {
+            super(dst, src);
+        }
 
-    public final void cvt_s64_f32(Register d, Register a) {
-        emitString("cvt.s64.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
+        public void emit(PTXAssembler asm) {
+            asm.emitString("cvt." + super.emit());
+        }
     }
-
-    public final void cvt_f64_f32(Register d, Register a) {
-        emitString("cvt.f64.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
+    
+    public static class Mov extends SingleOperandFormat {
 
-    public final void cvt_f32_f64(Register d, Register a) {
-        emitString("cvt.f32.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void cvt_s32_f64(Register d, Register a) {
-        emitString("cvt.s32.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
+        public Mov(Variable dst, Value src) {
+            super(dst, src);
+        }
 
-    public final void cvt_s64_f64(Register d, Register a) {
-        emitString("cvt.s64.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
+        /*
+        public Mov(Variable dst, AbstractAddress src) {
+            throw GraalInternalError.unimplemented("AbstractAddress Mov");
+        }
+        */
+        
+        public void emit(PTXAssembler asm) {
+            asm.emitString("mov." + super.emit());
+        }
     }
-
-    public final void cvt_f32_s32(Register d, Register a) {
-        emitString("cvt.f32.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
+    
+    public static class Neg extends SingleOperandFormat {
 
-    public final void cvt_f64_s32(Register d, Register a) {
-        emitString("cvt.f64.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
+        public Neg(Variable dst, Variable src) {
+            super(dst, src);
+        }
 
-    public final void cvt_s8_s32(Register d, Register a) {
-        emitString("cvt.s8.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void cvt_b16_s32(Register d, Register a) {
-        emitString("cvt.b16.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void cvt_s64_s32(Register d, Register a) {
-        emitString("cvt.s64.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
+        public void emit(PTXAssembler asm) {
+            asm.emitString("neg." + super.emit());
+        }
     }
+    
+    public static class Not extends SingleOperandFormat {
 
-    public final void cvt_s32_s64(Register d, Register a) {
-        emitString("cvt.s32.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
+        public Not(Variable dst, Variable src) {
+            super(dst, src);
+        }
 
-    public final void div_f32(Register d, Register a, Register b) {
-        emitString("div.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
+        public void emit(PTXAssembler asm) {
+            asm.emitString("not." + super.emit());
+        }
     }
+    
+    public static class Ld extends LoadStoreFormat {
 
-    public final void div_f64(Register d, Register a, Register b) {
-        emitString("div.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
+        public Ld(PTXStateSpace space, Variable dst, Variable src1, Value src2) {
+            super(space, dst, src1, src2);
+        }
 
-    public final void div_s16(Register d, Register a, Register b) {
-        emitString("div.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
+        public void emit(PTXAssembler asm) {
+            asm.emitString("ld." + super.emit(true));
+        }
     }
 
-    public final void div_s32(Register d, Register a, Register b) {
-        emitString("div.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void div_s64(Register d, Register a, Register b) {
-        emitString("div.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void div_s16(Register d, Register a, short s16) {
-        emitString("div.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s16 + ";" + "");
-    }
-
-    public final void div_s32(Register d, Register a, int s32) {
-        emitString("div.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void div_s32(Register d, int s32, Register b) {
-        emitString("div.s32" + " " + "%r" + d.encoding() + ", " + s32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void div_f32(Register d, float f32, Register b) {
-        emitString("div.f32" + " " + "%r" + d.encoding() + ", " + f32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void div_f64(Register d, double f64, Register b) {
-        emitString("div.f64" + " " + "%r" + d.encoding() + ", " + f64 + ", %r" + b.encoding() + ";" + "");
-    }
+    public static class St extends LoadStoreFormat {
 
-    public final void div_s64(Register d, Register a, long s64) {
-        emitString("div.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + "");
-    }
-
-    public final void div_f32(Register d, Register a, float f32) {
-        emitString("div.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f32 + ";" + "");
-    }
-
-    public final void div_f64(Register d, Register a, double f64) {
-        emitString("div.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f64 + ";" + "");
-    }
-
-    public final void div_u16(Register d, Register a, Register b) {
-        emitString("div.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
+        public St(PTXStateSpace space, Variable dst, Variable src1, Value src2) {
+            super(space, dst, src1, src2);
+        }
 
-    public final void div_u32(Register d, Register a, Register b) {
-        emitString("div.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void div_u64(Register d, Register a, Register b) {
-        emitString("div.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void div_u16(Register d, Register a, short u16) {
-        emitString("div.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u16 + ";" + "");
-    }
-
-    public final void div_u32(Register d, Register a, int u32) {
-        emitString("div.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void div_u64(Register d, Register a, long u64) {
-        emitString("div.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u64 + ";" + "");
+        public void emit(PTXAssembler asm) {
+            asm.emitString("st." + super.emit(false));
+        }
     }
 
     public final void exit() {
         emitString("exit;" + " " + "");
     }
 
-    public final void ld_global_b8(Register d, Register a, long immOff) {
-        emitString("ld.global.b8" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_b16(Register d, Register a, long immOff) {
-        emitString("ld.global.b16" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_b32(Register d, Register a, long immOff) {
-        emitString("ld.global.b32" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_b64(Register d, Register a, long immOff) {
-        emitString("ld.global.b64" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_u8(Register d, Register a, long immOff) {
-        emitString("ld.global.u8" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_u16(Register d, Register a, long immOff) {
-        emitString("ld.global.u16" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_u32(Register d, Register a, long immOff) {
-        emitString("ld.global.u32" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_u64(Register d, Register a, long immOff) {
-        emitString("ld.global.u64" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
+    public static class Param extends SingleOperandFormat {
 
-    public final void ld_global_s8(Register d, Register a, long immOff) {
-        emitString("ld.global.s8" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_s16(Register d, Register a, long immOff) {
-        emitString("ld.global.s16" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_s32(Register d, Register a, long immOff) {
-        emitString("ld.global.s32" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_s64(Register d, Register a, long immOff) {
-        emitString("ld.global.s64" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_f32(Register d, Register a, long immOff) {
-        emitString("ld.global.f32" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void ld_global_f64(Register d, Register a, long immOff) {
-        emitString("ld.global.f64" + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    // Load from state space to destination register
-    public final void ld_from_state_space(String s, Register d, Register a, long immOff) {
-        emitString("ld" + s + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    // Load return address from return parameter which is in .param state space
-    public final void ld_return_address(String s, Register d, Register a, long immOff) {
-        emitString("ld.param." + s + " " + "%r" + d.encoding() + ", [" + a + " + " + immOff + "]" + ";" + "");
-    }
-
-    public final void mov_b16(Register d, Register a) {
-        emitString("mov.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
+        private boolean lastParameter;
 
-    public final void mov_b32(Register d, Register a) {
-        emitString("mov.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void mov_b64(Register d, Register a) {
-        emitString("mov.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void mov_u16(Register d, Register a) {
-        emitString("mov.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void mov_u32(Register d, Register a) {
-        emitString("mov.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void mov_u64(Register d, Register a) {
-        emitString("mov.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void mov_u64(@SuppressWarnings("unused") Register d, @SuppressWarnings("unused") AbstractAddress a) {
-        // emitString("mov.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void mov_s16(Register d, Register a) {
-        emitString("mov.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void mov_s32(Register d, Register a) {
-        emitString("mov.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void mov_s64(Register d, Register a) {
-        emitString("mov.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void mov_f32(Register d, Register a) {
-        emitString("mov.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void mov_f64(Register d, Register a) {
-        emitString("mov.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void mov_b16(Register d, short b16) {
-        emitString("mov.b16" + " " + "%r" + d.encoding() + ", " + b16 + ";" + "");
-    }
-
-    public final void mov_b32(Register d, int b32) {
-        emitString("mov.b32" + " " + "%r" + d.encoding() + ", " + b32 + ";" + "");
-    }
-
-    public final void mov_b64(Register d, long b64) {
-        emitString("mov.b64" + " " + "%r" + d.encoding() + ", " + b64 + ";" + "");
-    }
-
-    public final void mov_u16(Register d, short u16) {
-        emitString("mov.u16" + " " + "%r" + d.encoding() + ", " + u16 + ";" + "");
-    }
-
-    public final void mov_u32(Register d, int u32) {
-        emitString("mov.u32" + " " + "%r" + d.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void mov_u64(Register d, long u64) {
-        emitString("mov.u64" + " " + "%r" + d.encoding() + ", " + u64 + ";" + "");
-    }
-
-    public final void mov_s16(Register d, short s16) {
-        emitString("mov.s16" + " " + "%r" + d.encoding() + ", " + s16 + ";" + "");
-    }
+        public Param(Variable d, boolean lastParam) {
+            super(d, null);
+            setLastParameter(lastParam);
+        }
 
-    public final void mov_s32(Register d, int s32) {
-        emitString("mov.s32" + " " + "%r" + d.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void mov_s64(Register d, long s64) {
-        emitString("mov.s64" + " " + "%r" + d.encoding() + ", " + s64 + ";" + "");
-    }
-
-    public final void mov_f32(Register d, float f32) {
-        emitString("mov.f32" + " " + "%r" + d.encoding() + ", " + f32 + ";" + "");
-    }
-
-    public final void mov_f64(Register d, double f64) {
-        emitString("mov.f64" + " " + "%r" + d.encoding() + ", " + f64 + ";" + "");
-    }
-
-    public final void mul_lo_f32(Register d, Register a, Register b) {
-        emitString("mul.lo.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void mul_lo_f64(Register d, Register a, Register b) {
-        emitString("mul.lo.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void mul_lo_s16(Register d, Register a, Register b) {
-        emitString("mul.lo.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void mul_lo_s32(Register d, Register a, Register b) {
-        emitString("mul.lo.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void mul_lo_s64(Register d, Register a, Register b) {
-        emitString("mul.lo.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void mul_lo_s16(Register d, Register a, short s16) {
-        emitString("mul.lo.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s16 + ";" + "");
-    }
-
-    public final void mul_lo_s32(Register d, Register a, int s32) {
-        emitString("mul.lo.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void mul_lo_s64(Register d, Register a, long s64) {
-        emitString("mul.lo.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + "");
-    }
-
-    public final void mul_lo_f32(Register d, Register a, float f32) {
-        emitString("mul.lo.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f32 + ";" + "");
-    }
-
-    public final void mul_lo_f64(Register d, Register a, double f64) {
-        emitString("mul.lo.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f64 + ";" + "");
-    }
-
-    public final void mul_lo_u16(Register d, Register a, Register b) {
-        emitString("mul.lo.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void mul_lo_u32(Register d, Register a, Register b) {
-        emitString("mul.lo.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void mul_lo_u64(Register d, Register a, Register b) {
-        emitString("mul.lo.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void mul_lo_u16(Register d, Register a, short u16) {
-        emitString("mul.lo.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u16 + ";" + "");
-    }
+        public void setLastParameter(boolean value) {
+            lastParameter = value;
+        }
 
-    public final void mul_lo_u32(Register d, Register a, int u32) {
-        emitString("mul.lo.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void mul_lo_u64(Register d, Register a, long u64) {
-        emitString("mul.lo.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u64 + ";" + "");
-    }
-
-    public final void neg_f32(Register d, Register a) {
-        emitString("neg.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void neg_f64(Register d, Register a) {
-        emitString("neg.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void neg_s16(Register d, Register a) {
-        emitString("neg.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void neg_s32(Register d, Register a) {
-        emitString("neg.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void neg_s64(Register d, Register a) {
-        emitString("neg.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void not_s16(Register d, Register a) {
-        emitString("not.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void not_s32(Register d, Register a) {
-        emitString("not.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
+        public String emitParameter(Variable v) {
+            return (" %r" + v.index);
+        }
 
-    public final void not_s64(Register d, Register a) {
-        emitString("not.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
-    }
-
-    public final void or_b16(Register d, Register a, Register b) {
-        emitString("or.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void or_b32(Register d, Register a, Register b) {
-        emitString("or.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void or_b64(Register d, Register a, Register b) {
-        emitString("or.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void or_b16(Register d, Register a, short b16) {
-        emitString("or.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b16 + ";" + "");
-    }
-
-    public final void or_b32(Register d, Register a, int b32) {
-        emitString("or.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b32 + ";" + "");
-    }
-
-    public final void or_b64(Register d, Register a, long b64) {
-        emitString("or.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b64 + ";" + "");
-    }
-
-    public final void param_8_decl(Register d, boolean lastParam) {
-        emitString(".param" + " " + ".s8" + " " + d + (lastParam ? "" : ","));
-    }
-
-    public final void param_32_decl(Register d, boolean lastParam) {
-        emitString(".param" + " " + ".s32" + " " + d + (lastParam ? "" : ","));
-    }
-
-    public final void param_64_decl(Register d, boolean lastParam) {
-        emitString(".param" + " " + ".s64" + " " + d + (lastParam ? "" : ","));
+        public void emit(PTXAssembler asm) {
+            asm.emitString(".param ." + typeForKind(dest.getKind()) + emitParameter(dest)  + (lastParameter ? "" : ","));
+        }
     }
 
     public final void popc_b32(Register d, Register a) {
@@ -569,54 +593,6 @@
         emitString("popc.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + "");
     }
 
-    public final void rem_s16(Register d, Register a, Register b) {
-        emitString("rem.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void rem_s32(Register d, Register a, Register b) {
-        emitString("rem.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void rem_s64(Register d, Register a, Register b) {
-        emitString("rem.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void rem_s16(Register d, Register a, short s16) {
-        emitString("rem.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s16 + ";" + "");
-    }
-
-    public final void rem_s32(Register d, Register a, int s32) {
-        emitString("rem.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void rem_s64(Register d, Register a, long s64) {
-        emitString("rem.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + "");
-    }
-
-    public final void rem_u16(Register d, Register a, Register b) {
-        emitString("rem.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void rem_u32(Register d, Register a, Register b) {
-        emitString("rem.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void rem_u64(Register d, Register a, Register b) {
-        emitString("rem.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void rem_u16(Register d, Register a, short u16) {
-        emitString("rem.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u16 + ";" + "");
-    }
-
-    public final void rem_u32(Register d, Register a, int u32) {
-        emitString("rem.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void rem_u64(Register d, Register a, long u64) {
-        emitString("rem.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u64 + ";" + "");
-    }
-
     public final void ret() {
         emitString("ret;" + " " + "");
     }
@@ -625,501 +601,168 @@
         emitString("ret.uni;" + " " + "");
     }
 
-    public final void setp_eq_f32(Register a, Register b) {
-        emitString("setp.eq.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ne_f32(Register a, Register b) {
-        emitString("setp.ne.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_lt_f32(Register a, Register b) {
-        emitString("setp.lt.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
+    public static class Setp  {
 
-    public final void setp_le_f32(Register a, Register b) {
-        emitString("setp.le.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_gt_f32(Register a, Register b) {
-        emitString("setp.gt.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ge_f32(Register a, Register b) {
-        emitString("setp.ge.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_eq_f32(float f32, Register b) {
-        emitString("setp.eq.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + "");
-    }
+        private ConditionOperator  operator;
+        private Value first, second;
+        private Kind kind;
+        private int predicate;
 
-    public final void setp_ne_f32(float f32, Register b) {
-        emitString("setp.ne.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_lt_f32(float f32, Register b) {
-        emitString("setp.lt.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_le_f32(float f32, Register b) {
-        emitString("setp.le.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_gt_f32(float f32, Register b) {
-        emitString("setp.gt.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ge_f32(float f32, Register b) {
-        emitString("setp.ge.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_eq_f64(double f64, Register b) {
-        emitString("setp.eq.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ne_f64(double f64, Register b) {
-        emitString("setp.ne.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_lt_f64(double f64, Register b) {
-        emitString("setp.lt.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + "");
-    }
+        public Setp(Condition condition, Value first, Value second, int predicateRegisterNumber) {
+            setFirst(first);
+            setSecond(second);
+            setPredicate(predicateRegisterNumber);
+            setKind();
+            setConditionOperator(operatorForConditon(condition));
+        }
 
-    public final void setp_le_f64(double f64, Register b) {
-        emitString("setp.le.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_gt_f64(double f64, Register b) {
-        emitString("setp.gt.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ge_f64(double f64, Register b) {
-        emitString("setp.ge.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + "");
-    }
+        public void setFirst(Value v) {
+            first = v;
+        }
 
-    public final void setp_eq_s64(Register a, Register b) {
-        emitString("setp.eq.s64" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_eq_s64(long s64, Register b) {
-        emitString("setp.eq.s64" + " " + "%p" + ", " + s64 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_eq_s32(Register a, Register b) {
-        emitString("setp.eq.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ne_s32(Register a, Register b) {
-        emitString("setp.ne.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
+        public void setSecond(Value v) {
+            second = v;
+        }
 
-    public final void setp_lt_s32(Register a, Register b) {
-        emitString("setp.lt.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_le_s32(Register a, Register b) {
-        emitString("setp.le.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_gt_s32(Register a, Register b) {
-        emitString("setp.gt.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ge_s32(Register a, Register b) {
-        emitString("setp.ge.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
+        public void setPredicate(int p) {
+            predicate = p;
+        }
 
-    public final void setp_eq_s32(Register a, int s32) {
-        emitString("setp.eq.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void setp_ne_s32(Register a, int s32) {
-        emitString("setp.ne.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
+        public void setConditionOperator(ConditionOperator co) {
+            operator = co;
+        }
 
-    public final void setp_lt_s32(Register a, int s32) {
-        emitString("setp.lt.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void setp_le_s32(Register a, int s32) {
-        emitString("setp.le.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
+        private ConditionOperator operatorForConditon(Condition condition) {
+            char typeChar = kind.getTypeChar();
 
-    public final void setp_gt_s32(Register a, int s32) {
-        emitString("setp.gt.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void setp_ge_s32(Register a, int s32) {
-        emitString("setp.ge.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void setp_eq_s32(int s32, Register b) {
-        emitString("setp.eq.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ne_s32(int s32, Register b) {
-        emitString("setp.ne.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_lt_s32(int s32, Register b) {
-        emitString("setp.lt.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_le_s32(int s32, Register b) {
-        emitString("setp.le.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_gt_s32(int s32, Register b) {
-        emitString("setp.gt.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + "");
-    }
+            switch (typeChar) {
+                case 'z':
+                case 'c':
+                case 'a':
+                    // unsigned
+                    switch (condition) {
+                        case EQ: return ConditionOperator.U_EQ;
+                        case NE: return ConditionOperator.U_NE;
+                        case LT: return ConditionOperator.U_LO;
+                        case LE: return ConditionOperator.U_LS;
+                        case GT: return ConditionOperator.U_HI;
+                        case GE: return ConditionOperator.U_HS;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
+                case 'b':
+                case 's':
+                case 'i':
+                case 'j':
+                    // signed
+                    switch (condition) {
+                        case EQ: return ConditionOperator.S_EQ;
+                        case NE: return ConditionOperator.S_NE;
+                        case LT: return ConditionOperator.S_LT;
+                        case LE: return ConditionOperator.S_LE;
+                        case GT: return ConditionOperator.S_GT;
+                        case GE:
+                        case AE:
+                            return ConditionOperator.S_GE;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
+                case 'f':
+                case 'd':
+                    // floating point - do these need to accept NaN??
+                    switch (condition) {
+                        case EQ: return ConditionOperator.F_EQ;
+                        case NE: return ConditionOperator.F_NE;
+                        case LT: return ConditionOperator.F_LT;
+                        case LE: return ConditionOperator.F_LE;
+                        case GT: return ConditionOperator.F_GT;
+                        case GE: return ConditionOperator.F_GE;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
 
-    public final void setp_ge_s32(int s32, Register b) {
-        emitString("setp.ge.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_eq_u32(Register a, Register b) {
-        emitString("setp.eq.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ne_u32(Register a, Register b) {
-        emitString("setp.ne.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_lt_u32(Register a, Register b) {
-        emitString("setp.lt.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_le_u32(Register a, Register b) {
-        emitString("setp.le.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_gt_u32(Register a, Register b) {
-        emitString("setp.gt.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ge_u32(Register a, Register b) {
-        emitString("setp.ge.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_eq_u32(Register a, int u32) {
-        emitString("setp.eq.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
+        public void setKind() {
+            // assert isConstant(first) && isConstant(second) == false;
 
-    public final void setp_ne_u32(Register a, int u32) {
-        emitString("setp.ne.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void setp_lt_u32(Register a, int u32) {
-        emitString("setp.lt.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void setp_le_u32(Register a, int u32) {
-        emitString("setp.le.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void setp_gt_u32(Register a, int u32) {
-        emitString("setp.gt.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
+            if (isConstant(first)) {
+                kind = second.getKind();
+            } else {
+                kind = first.getKind();
+            }
+        }
+        
+        public String emitValue(Value v) {
+            assert v != null;
 
-    public final void setp_ge_u32(Register a, int u32) {
-        emitString("setp.ge.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void setp_eq_u32(int u32, Register b) {
-        emitString("setp.eq.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ne_u32(int u32, Register b) {
-        emitString("setp.ne.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_lt_u32(int u32, Register b) {
-        emitString("setp.lt.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + "");
-    }
+            if (isConstant(v)) {
+                return (", " + emitConstant(v));
+            } else {
+                return (", " + emitVariable((Variable) v));
+            }
+        }
 
-    public final void setp_le_u32(int u32, Register b) {
-        emitString("setp.le.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_gt_u32(int u32, Register b) {
-        emitString("setp.gt.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void setp_ge_u32(int u32, Register b) {
-        emitString("setp.ge.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + "");
-    }
+        public String typeForKind(Kind k) {
+            switch (k.getTypeChar()) {
+                case 'z':
+                    return "u8";
+                case 'b':
+                    return "s8";
+                case 's':
+                    return "s16";
+                case 'c':
+                    return "u16";
+                case 'i':
+                    return "s32";
+                case 'f':
+                    return "f32";
+                case 'j':
+                    return "s64";
+                case 'd':
+                    return "f64";
+                case 'a':
+                    return "u64";
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
 
-    // Shift left - only types supported are .b16, .b32 and .b64
-    public final void shl_b16(Register d, Register a, Register b) {
-        emitString("shl.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void shl_b32(Register d, Register a, Register b) {
-        emitString("shl.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
+        public String emitConstant(Value v) {
+            Constant constant = (Constant) v;
 
-    public final void shl_b64(Register d, Register a, Register b) {
-        emitString("shl.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
+            switch (v.getKind().getTypeChar()) {
+                case 'i':
+                    return (String.valueOf((int) constant.asLong()));
+                case 'f':
+                    return (String.valueOf(constant.asFloat()));
+                case 'j':
+                    return (String.valueOf(constant.asLong()));
+                case 'd':
+                    return (String.valueOf(constant.asDouble()));
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+        
+        public String emitVariable(Variable v) {
+            return ("%r" + v.index);
+        }
 
-    public final void shl_b16_const(Register d, Register a, int b) {
-        emitString("shl.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b + ";" + "");
-    }
-
-    public final void shl_b32_const(Register d, Register a, int b) {
-        emitString("shl.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b + ";" + "");
+        public void emit(PTXAssembler asm) {
+            asm.emitString("setp." + operator.getOperator() + "." + typeForKind(kind) +
+                           " %p" + predicate + emitValue(first) + emitValue(second) + ";");
+        }
     }
-
-    public final void shl_b64_const(Register d, Register a, int b) {
-        emitString("shl.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b + ";" + "");
-    }
-
-    // Shift Right instruction
-    public final void shr_s16(Register d, Register a, Register b) {
-        emitString("shr.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void shr_s32(Register d, Register a, Register b) {
-        emitString("shr.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void shr_s64(Register d, Register a, Register b) {
-        emitString("shr.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void shr_s16(Register d, Register a, int u32) {
-        emitString("shr.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void shr_s32(Register d, Register a, int u32) {
-        emitString("shr.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void shr_s64(Register d, Register a, int u32) {
-        emitString("shr.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void shr_u16(Register d, Register a, Register b) {
-        emitString("shr.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void shr_u32(Register d, Register a, Register b) {
-        emitString("shr.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void shr_u64(Register d, Register a, Register b) {
-        emitString("shr.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void shr_u16(Register d, Register a, int u32) {
-        emitString("shr.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void shr_u32(Register d, Register a, int u32) {
-        emitString("shr.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + "");
-    }
-
-    public final void shr_u64(Register d, Register a, long u64) {
-        emitString("shr.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u64 + ";" + "");
-    }
-
-    // Store in global state space
-
-    public final void st_global_b8(Register a, long immOff, Register b) {
-        emitString("st.global.b8" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_b16(Register a, long immOff, Register b) {
-        emitString("st.global.b16" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_b32(Register a, long immOff, Register b) {
-        emitString("st.global.b32" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_b64(Register a, long immOff, Register b) {
-        emitString("st.global.b64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_u8(Register a, long immOff, Register b) {
-        emitString("st.global.u8" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_u16(Register a, long immOff, Register b) {
-        emitString("st.global.u16" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_u32(Register a, long immOff, Register b) {
-        emitString("st.global.u32" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_u64(Register a, long immOff, Register b) {
-        emitString("st.global.u64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_s8(Register a, long immOff, Register b) {
-        emitString("st.global.s8" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_s16(Register a, long immOff, Register b) {
-        emitString("st.global.s16" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_s32(Register a, long immOff, Register b) {
-        emitString("st.global.s32" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_s64(Register a, long immOff, Register b) {
-        emitString("st.global.s64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_f32(Register a, long immOff, Register b) {
-        emitString("st.global.f32" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_f64(Register a, long immOff, Register b) {
-        emitString("st.global.f64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    // Store return value
-    public final void st_global_return_value_s8(Register a, long immOff, Register b) {
-        emitString("st.global.s8" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_return_value_s32(Register a, long immOff, Register b) {
-        emitString("st.global.s32" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_return_value_s64(Register a, long immOff, Register b) {
-        emitString("st.global.s64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_return_value_f32(Register a, long immOff, Register b) {
-        emitString("st.global.f32" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_return_value_f64(Register a, long immOff, Register b) {
-        emitString("st.global.f64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_return_value_u32(Register a, long immOff, Register b) {
-        emitString("st.global.u32" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    public final void st_global_return_value_u64(Register a, long immOff, Register b) {
-        emitString("st.global.u64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + "");
-    }
-
-    // Subtract instruction
-
-    public final void sub_f32(Register d, Register a, Register b) {
-        emitString("sub.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void sub_f64(Register d, Register a, Register b) {
-        emitString("sub.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void sub_s16(Register d, Register a, Register b) {
-        emitString("sub.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void sub_s32(Register d, Register a, Register b) {
-        emitString("sub.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void sub_s64(Register d, Register a, Register b) {
-        emitString("sub.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void sub_s16(Register d, Register a, short s16) {
-        emitString("sub.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s16 + ";" + "");
-    }
-
-    public final void sub_s32(Register d, Register a, int s32) {
-        emitString("sub.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void sub_s64(Register d, Register a, int s32) {
-        emitString("sub.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void sub_s64(Register d, Register a, long s64) {
-        emitString("sub.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + "");
-    }
-
-    public final void sub_f32(Register d, Register a, float f32) {
-        emitString("sub.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f32 + ";" + "");
-    }
-
-    public final void sub_f64(Register d, Register a, double f64) {
-        emitString("sub.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f64 + ";" + "");
-    }
-
-    public final void sub_s16(Register d, short s16, Register b) {
-        emitString("sub.s16" + " " + "%r" + d.encoding() + ", " + s16 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void sub_s32(Register d, int s32, Register b) {
-        emitString("sub.s32" + " " + "%r" + d.encoding() + ", " + s32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void sub_s64(Register d, long s64, Register b) {
-        emitString("sub.s64" + " " + "%r" + d.encoding() + ", " + s64 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void sub_f32(Register d, float f32, Register b) {
-        emitString("sub.f32" + " " + "%r" + d.encoding() + ", %r" + b.encoding() + ", " + f32 + ";" + "");
-    }
-
-    public final void sub_f64(Register d, double f64, Register b) {
-        emitString("sub.f64" + " " + "%r" + d.encoding() + ", %r" + b.encoding() + ", " + f64 + ";" + "");
-    }
-
-    public final void sub_sat_s32(Register d, Register a, Register b) {
-        emitString("sub.sat.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void sub_sat_s32(Register d, Register a, int s32) {
-        emitString("sub.sat.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + "");
-    }
-
-    public final void sub_sat_s32(Register d, int s32, Register b) {
-        emitString("sub.sat.s32" + " " + "%r" + d.encoding() + ", " + s32 + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void xor_b16(Register d, Register a, Register b) {
-        emitString("xor.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void xor_b32(Register d, Register a, Register b) {
-        emitString("xor.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void xor_b64(Register d, Register a, Register b) {
-        emitString("xor.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + "");
-    }
-
-    public final void xor_b16(Register d, Register a, short b16) {
-        emitString("xor.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b16 + ";" + "");
-    }
-
-    public final void xor_b32(Register d, Register a, int b32) {
-        emitString("xor.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b32 + ";" + "");
-    }
-
-    public final void xor_b64(Register d, Register a, long b64) {
-        emitString("xor.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b64 + ";" + "");
-    }
-
     @Override
     public PTXAddress makeAddress(Register base, int displacement) {
-        return new PTXAddress(base, displacement);
+        throw GraalInternalError.shouldNotReachHere();
     }
 
     @Override
     public PTXAddress getPlaceholder() {
-        // TODO Auto-generated method stub
         return null;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXStateSpace.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,49 @@
+/*
+ * 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.asm.ptx;
+
+/**
+ * Represents the various PTX state spaces.
+ */
+public enum PTXStateSpace {
+
+    Parameter("param"),
+
+    Shared("shared"),
+
+    Local("local"),
+
+    Global("global"),
+
+    Const("const");
+
+    private final String stateName;
+
+    private PTXStateSpace(String name) {
+        this.stateName = name;
+    }
+
+    public String getStateName() {
+        return stateName;
+    }
+}
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAddress.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAddress.java	Wed Oct 02 13:26:31 2013 +0200
@@ -121,7 +121,7 @@
             throw GraalInternalError.shouldNotReachHere("address has index register");
         }
         // TODO Should we also hide the register save area size here?
-        if (getBase() == sp || getBase() == fp) {
+        if (getBase().equals(sp) || getBase().equals(fp)) {
             return displacement + STACK_BIAS;
         }
         return displacement;
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Wed Oct 02 13:26:31 2013 +0200
@@ -890,6 +890,6 @@
 
     @Override
     public void visitInfopointNode(InfopointNode i) {
-        append(new InfopointOp(stateFor(i.stateAfter(), DeoptimizationReason.None), i.reason));
+        append(new InfopointOp(stateFor(i.getState()), i.reason));
     }
 }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,7 +25,8 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import org.junit.Test;
+
+import org.junit.*;
 
 /**
  * Tests the spilling of double variables into memory.
@@ -118,6 +119,7 @@
     }
 
     // Marked to only run on hardware until simulator spill bug is fixed.
+    @Ignore
     @Test
     public void test() {
         testGeneratedHsail();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,7 +25,8 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import org.junit.Test;
+
+import org.junit.*;
 
 /**
  * Tests the spilling of integers into memory.
@@ -87,6 +88,7 @@
     }
 
     // Marked to only run on hardware until simulator spill bug is fixed.
+    @Ignore
     @Test
     public void test() {
         testGeneratedHsail();
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILBackend.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILBackend.java	Wed Oct 02 13:26:31 2013 +0200
@@ -60,8 +60,16 @@
     }
 
     @Override
+    public boolean shouldAllocateRegisters() {
+        return true;
+    }
+
+    /**
+     * Use the HSAIL register set when the compilation target is HSAIL.
+     */
+    @Override
     public FrameMap newFrameMap() {
-        return new HSAILFrameMap(runtime(), target, runtime().lookupRegisterConfig());
+        return new HSAILFrameMap(runtime(), target, new HSAILRegisterConfig());
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILCompilationResult.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILCompilationResult.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,33 +23,25 @@
 
 package com.oracle.graal.compiler.hsail;
 
-import static com.oracle.graal.api.code.CodeUtil.*;
-
+import java.lang.reflect.*;
 import java.util.logging.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.CallingConvention.*;
-import com.oracle.graal.api.runtime.Graal;
-import com.oracle.graal.compiler.GraalCompiler;
-import com.oracle.graal.java.GraphBuilderConfiguration;
-import com.oracle.graal.java.GraphBuilderPhase;
-import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.nodes.spi.GraalCodeCacheProvider;
-import com.oracle.graal.phases.OptimisticOptimizations;
-import com.oracle.graal.phases.PhasePlan;
-import com.oracle.graal.phases.PhasePlan.PhasePosition;
+import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.graph.GraalInternalError;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hsail.*;
+import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.nodes.spi.Replacements;
-import com.oracle.graal.compiler.target.Backend;
-import com.oracle.graal.hsail.*;
-
-import java.lang.reflect.Method;
 
 /**
  * Class that represents a HSAIL compilation result. Includes the compiled HSAIL code.
@@ -96,6 +88,33 @@
         return getHSAILCompilationResult(graph);
     }
 
+    /**
+     * HSAIL doesn't have a calling convention as such. Function arguments are actually passed in
+     * memory but then loaded into registers in the function body. This routine makes sure that
+     * arguments to a kernel or function are loaded (by the kernel or function body) into registers
+     * of the appropriate sizes. For example, int and float parameters should appear in S registers,
+     * whereas double and long parameters should appear in d registers.
+     */
+    public static CallingConvention getHSAILCallingConvention(CallingConvention.Type type, TargetDescription target, ResolvedJavaMethod method, boolean stackOnly) {
+        Signature sig = method.getSignature();
+        JavaType retType = sig.getReturnType(null);
+        int sigCount = sig.getParameterCount(false);
+        JavaType[] argTypes;
+        int argIndex = 0;
+        if (!Modifier.isStatic(method.getModifiers())) {
+            argTypes = new JavaType[sigCount + 1];
+            argTypes[argIndex++] = method.getDeclaringClass();
+        } else {
+            argTypes = new JavaType[sigCount];
+        }
+        for (int i = 0; i < sigCount; i++) {
+            argTypes[argIndex++] = sig.getParameterType(i, null);
+        }
+
+        RegisterConfig registerConfig = new HSAILRegisterConfig();
+        return registerConfig.getCallingConvention(type, retType, argTypes, target, stackOnly);
+    }
+
     public static HSAILCompilationResult getHSAILCompilationResult(StructuredGraph graph) {
         Debug.dump(graph, "Graph");
         TargetDescription target = new TargetDescription(new HSAIL(), true, 8, 0, true);
@@ -105,7 +124,7 @@
         phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
         phasePlan.addPhase(PhasePosition.AFTER_PARSING, new HSAILPhase());
         new HSAILPhase().apply(graph);
-        CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false);
+        CallingConvention cc = getHSAILCallingConvention(Type.JavaCallee, target, graph.method(), false);
         try {
             CompilationResult compResult = GraalCompiler.compileGraph(graph, cc, graph.method(), runtime, replacements, hsailBackend, target, null, phasePlan, OptimisticOptimizations.NONE,
                             new SpeculationLog(), suitesProvider.getDefaultSuites(), new CompilationResult());
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Wed Oct 02 13:26:31 2013 +0200
@@ -143,12 +143,12 @@
             } else {
                 baseRegister = load(base);
             }
-        } else if (base == Value.ILLEGAL) {
+        } else if (base.equals(Value.ILLEGAL)) {
             baseRegister = Value.ILLEGAL;
         } else {
             baseRegister = asAllocatable(base);
         }
-        if (index != Value.ILLEGAL) {
+        if (!index.equals(Value.ILLEGAL)) {
             if (isConstant(index)) {
                 finalDisp += asConstant(index).asLong() * scale;
             } else {
@@ -160,7 +160,7 @@
                 } else {
                     indexRegister = convertedIndex;
                 }
-                if (baseRegister == Value.ILLEGAL) {
+                if (baseRegister.equals(Value.ILLEGAL)) {
                     baseRegister = asAllocatable(indexRegister);
                 } else {
                     baseRegister = emitAdd(baseRegister, indexRegister);
@@ -579,7 +579,7 @@
     }
 
     @Override
-    public void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, DeoptimizingNode deopting) {
         append(new ReturnOp(Value.ILLEGAL));
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ArrayPTXTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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.compiler.ptx.test;
+
+import static com.oracle.graal.lir.ptx.ThreadDimension.*;
+
+import com.oracle.graal.lir.ptx.ParallelOver;
+import com.oracle.graal.lir.ptx.Warp;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import org.junit.Test;
+
+public class ArrayPTXTest extends PTXTestBase {
+
+    @Test
+    public void testArray() {
+        int[] array1 = {
+            1, 2, 3, 4, 5, 6, 7, 8, 9
+        };
+        int[] array2 = {
+            1, 2, 3, 4, 5, 6, 7, 8, 9
+        };
+        int[] array3 = {
+            1, 2, 3, 4, 5, 6, 7, 8, 9
+        };
+
+        invoke(compile("testStoreArray1I"), array1, 2);
+        printReport("testStoreArray1I: " + Arrays.toString(array1));
+
+        invoke(compile("testStoreArrayWarp0"), array2, 2);
+        printReport("testStoreArrayWarp0: " + Arrays.toString(array2));
+
+        invoke(compile("testStoreArrayWarp1I"), array3, 2);
+        printReport("testStoreArrayWarp1I: " + Arrays.toString(array3));
+
+    }
+
+    public static void testStoreArray1I(int[] array, int i) {
+        array[i] = 42;
+    }
+
+    public static void testStoreArrayWarp0(int[] array,
+                                           @Warp(dimension = X) int i) {
+        array[i] = 42;
+    }
+
+    public static void testStoreArrayWarp1I(@ParallelOver(dimension = X) int[] array,
+                                            @Warp(dimension = X) int i) {
+        array[i] = 42;
+    }
+
+
+    public static void printReport(String message) {
+        // CheckStyle: stop system..print check
+        System.out.println(message);
+        // CheckStyle: resume system..print check
+    }
+
+    public static void main(String[] args) {
+        ArrayPTXTest test = new ArrayPTXTest();
+        for (Method m : ArrayPTXTest.class.getMethods()) {
+            String name = m.getName();
+            if (m.getAnnotation(Test.class) == null && name.startsWith("test")) {
+                // CheckStyle: stop system..print check
+                System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
+                // CheckStyle: resume system..print check
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ArrayTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +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.compiler.ptx.test;
-
-import java.lang.reflect.Method;
-
-import org.junit.*;
-
-public class ArrayTest extends PTXTestBase {
-
-    @Ignore
-    @Test
-    public void testArray() {
-        compile("testArray1I");
-        compile("testArray1J");
-        compile("testArray1B");
-        compile("testArray1S");
-        compile("testArray1C");
-        compile("testArray1F");
-        compile("testArray1D");
-        compile("testArray1L");
-        compile("testStoreArray1I");
-        compile("testStoreArray1J");
-        compile("testStoreArray1B");
-        compile("testStoreArray1S");
-        compile("testStoreArray1F");
-        compile("testStoreArray1D");
-    }
-
-    public static int testArray1I(int[] array, int i) {
-        return array[i];
-    }
-
-    public static long testArray1J(long[] array, int i) {
-        return array[i];
-    }
-
-    public static byte testArray1B(byte[] array, int i) {
-        return array[i];
-    }
-
-    public static short testArray1S(short[] array, int i) {
-        return array[i];
-    }
-
-    public static char testArray1C(char[] array, int i) {
-        return array[i];
-    }
-
-    public static float testArray1F(float[] array, int i) {
-        return array[i];
-    }
-
-    public static double testArray1D(double[] array, int i) {
-        return array[i];
-    }
-
-    public static Object testArray1L(Object[] array, int i) {
-        return array[i];
-    }
-
-    public static void testStoreArray1I(int[] array, int i, int val) {
-        array[i] = val;
-    }
-
-    public static void testStoreArray1B(byte[] array, int i, byte val) {
-        array[i] = val;
-    }
-
-    public static void testStoreArray1S(short[] array, int i, short val) {
-        array[i] = val;
-    }
-
-    public static void testStoreArray1J(long[] array, int i, long val) {
-        array[i] = val;
-    }
-
-    public static void testStoreArray1F(float[] array, int i, float val) {
-        array[i] = val;
-    }
-
-    public static void testStoreArray1D(double[] array, int i, double val) {
-        array[i] = val;
-    }
-
-    public static void main(String[] args) {
-        ArrayTest test = new ArrayTest();
-        for (Method m : ArrayTest.class.getMethods()) {
-            String name = m.getName();
-            if (m.getAnnotation(Test.class) == null && name.startsWith("test")) {
-                // CheckStyle: stop system..print check
-                System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
-                // CheckStyle: resume system..print check
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,11 +24,13 @@
 
 import java.lang.reflect.Method;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
 /**
  * Test class for small Java methods compiled to PTX kernels.
  */
+@Ignore
 public class BasicPTXTest extends PTXTestBase {
 
     @Test
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,118 @@
+/*
+ * 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.compiler.ptx.test;
+
+import org.junit.*;
+
+import java.lang.reflect.Method;
+
+public class ControlPTXTest extends PTXTestBase {
+
+    @Ignore
+    @Test
+    public void testControl() {
+        compile("testLoop");
+        // compile("testSwitch1I");
+        // compile("testStatic");
+        // compile("testCall");
+        // compile("testLookupSwitch1I");
+    }
+
+    public static int testLoop(int n) {
+        int sum = 0;
+
+        for (int i = 0; i < n; i++) {
+            sum++;
+        }
+        return sum;
+    }
+
+    public static int testSwitch1I(int a) {
+        switch (a) {
+            case 1:
+                return 2;
+            case 2:
+                return 3;
+            default:
+                return 4;
+        }
+    }
+
+    public static int testLookupSwitch1I(int a) {
+        switch (a) {
+            case 0:
+                return 1;
+            case 1:
+                return 2;
+            case 2:
+                return 3;
+            case 3:
+                return 1;
+            case 4:
+                return 2;
+            case 5:
+                return 3;
+            case 6:
+                return 1;
+            case 7:
+                return 2;
+            case 8:
+                return 3;
+            case 9:
+                return 1;
+            case 10:
+                return 2;
+            case 11:
+                return 3;
+            default:
+                return -1;
+        }
+    }
+
+    @SuppressWarnings("unused") private static Object foo = null;
+
+    public static boolean testStatic(Object o) {
+        foo = o;
+        return true;
+    }
+
+    private static int method(int a, int b) {
+        return a + b;
+    }
+
+    public static int testCall(@SuppressWarnings("unused") Object o, int a, int b) {
+        return method(a, b);
+    }
+
+    public static void main(String[] args) {
+        ControlPTXTest test = new ControlPTXTest();
+        for (Method m : ControlPTXTest.class.getMethods()) {
+            String name = m.getName();
+            if (m.getAnnotation(Test.class) == null && name.startsWith("test")) {
+                // CheckStyle: stop system..print check
+                System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
+                // CheckStyle: resume system..print check
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +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.compiler.ptx.test;
-
-import org.junit.*;
-
-import java.lang.reflect.Method;
-
-public class ControlTest extends PTXTestBase {
-
-    @Ignore
-    @Test
-    public void testControl() {
-        compile("testSwitch1I");
-        compile("testStatic");
-        compile("testCall");
-        compile("testLookupSwitch1I");
-    }
-
-    public static int testSwitch1I(int a) {
-        switch (a) {
-        case 1:
-            return 2;
-        case 2:
-            return 3;
-        default:
-            return 4;
-        }
-    }
-
-    public static int testLookupSwitch1I(int a) {
-        switch (a) {
-        case 0:  return 1;
-        case 1:  return 2;
-        case 2:  return 3;
-        case 3:  return 1;
-        case 4:  return 2;
-        case 5:  return 3;
-        case 6:  return 1;
-        case 7:  return 2;
-        case 8:  return 3;
-        case 9:  return 1;
-        case 10: return 2;
-        case 11: return 3;
-        default: return -1;
-        }
-    }
-
-    @SuppressWarnings("unused")
-    private static Object foo = null;
-
-    public static boolean testStatic(Object o) {
-        foo = o;
-        return true;
-    }
-
-    private static int method(int a, int b) {
-        return a + b;
-    }
-
-    public static int testCall(@SuppressWarnings("unused") Object o, int a, int b) {
-        return method(a, b);
-    }
-
-    public static void main(String[] args) {
-        ControlTest test = new ControlTest();
-        for (Method m : ControlTest.class.getMethods()) {
-            String name = m.getName();
-            if (m.getAnnotation(Test.class) == null && name.startsWith("test")) {
-                // CheckStyle: stop system..print check
-                System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
-                // CheckStyle: resume system..print check
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/FloatPTXTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/FloatPTXTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,14 +29,18 @@
 import com.oracle.graal.api.code.CompilationResult;
 
 /* PTX ISA 3.1 - 8.7.3 Floating-Point Instructions */
+@Ignore
 public class FloatPTXTest extends PTXTestBase {
 
+    @Ignore
     @Test
     public void testAdd() {
         CompilationResult r = compile("testAdd2F");
         if (r.getTargetCode() == null) {
             printReport("Compilation of testAdd2F FAILED");
         }
+
+        /*
         r = compile("testAdd2D");
         if (r.getTargetCode() == null) {
             printReport("Compilation of testAdd2D FAILED");
@@ -58,6 +62,7 @@
         if (r.getTargetCode() == null) {
             printReport("Compilation of testConstD FAILED");
         }
+        */
     }
 
     public static float testAdd2F(float a, float b) {
@@ -84,6 +89,7 @@
         return 32.0 + a;
     }
 
+    @Ignore
     @Test
     public void testSub() {
         CompilationResult r = compile("testSub2F");
@@ -141,6 +147,7 @@
         return 32.0 - a;
     }
 
+    @Ignore
     @Test
     public void testMul() {
         CompilationResult r = compile("testMul2F");
@@ -198,6 +205,7 @@
         return 32.0 * a;
     }
 
+    @Ignore
     @Test
     public void testDiv() {
         CompilationResult r = compile("testDiv2F");
@@ -255,6 +263,7 @@
         return 32.0 / a;
     }
 
+    @Ignore
     @Test
     public void testNeg() {
         CompilationResult r = compile("testNeg2F");
@@ -276,6 +285,7 @@
         return -a;
     }
 
+    @Ignore
     @Test
     public void testRem() {
         // need linkage to PTX remainder()
@@ -360,9 +370,7 @@
         FloatPTXTest test = new FloatPTXTest();
         for (Method m : FloatPTXTest.class.getMethods()) {
             String name = m.getName();
-            if (m.getAnnotation(Test.class) == null &&
-                    name.startsWith("test") &&
-                    name.startsWith("testRem") == false) {
+            if (m.getAnnotation(Test.class) == null && name.startsWith("test") && name.startsWith("testRem") == false) {
                 // CheckStyle: stop system..print check
                 System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
                 // CheckStyle: resume system..print check
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/IntegerPTXTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/IntegerPTXTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,11 +26,19 @@
 
 import java.lang.reflect.Method;
 
-
 public class IntegerPTXTest extends PTXTestBase {
 
     @Test
     public void testAdd() {
+        /*
+        Integer r4 = (Integer) invoke(compile("testAdd2B"), (byte) 6, (byte) 4);
+        if (r4 == null) {
+            printReport("testAdd2B FAILED");
+        } else if (r4.intValue() == testAdd2B((byte) 6, (byte) 4)) {
+            printReport("testAdd2B PASSED");
+        } else {
+            printReport("testAdd2B FAILED");
+        } */
 
         Integer r4 = (Integer) invoke(compile("testAdd2I"), 18, 24);
         if (r4 == null) {
@@ -41,16 +49,14 @@
             printReport("testAdd2I FAILED");
         }
 
-        Long r2 = (Long) invoke(compile("testAdd2L"), (long) 12, (long) 6);
+        /* Long r2 = (Long) invoke(compile("testAdd2L"), (long) 12, (long) 6);
         if (r2 == null) {
             printReport("testAdd2L FAILED");
         } else if (r2.longValue() == testAdd2L(12, 6)) {
             printReport("testAdd2L PASSED");
         } else {
             printReport("testAdd2L FAILED");
-        }
-
-        //invoke(compile("testAdd2B"), (byte) 6, (byte) 4);
+        } 
 
         r4 = (Integer) invoke(compile("testAddIConst"), 5);
         if (r4 == null) {
@@ -68,8 +74,7 @@
             printReport("testAddConstI PASSED");
         } else {
             printReport("testAddConstI FAILED");
-        }
-
+        } */
     }
 
     public static int testAdd2I(int a, int b) {
@@ -92,6 +97,7 @@
         return 32 + a;
     }
 
+    @Ignore
     @Test
     public void testSub() {
 
@@ -149,6 +155,7 @@
         return 32 - a;
     }
 
+    @Ignore
     @Test
     public void testMul() {
 
@@ -260,6 +267,7 @@
         return 32 / a;
     }
 
+    @Ignore
     @Test
     public void testRem() {
         Integer r1 = (Integer) invoke(compile("testRem2I"), 8, 4);
@@ -288,6 +296,7 @@
     public static long testRem2L(long a, long b) {
         return a % b;
     }
+
     @Ignore
     @Test
     public void testIntConversion() {
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/LogicPTXTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/LogicPTXTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,10 +24,11 @@
 
 import java.lang.reflect.Method;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
-
 /* PTX ISA 3.1 - 8.7.5 Logic and Shift Instructions */
+@Ignore
 public class LogicPTXTest extends PTXTestBase {
 
     @Test
@@ -105,7 +106,7 @@
         compile("testShiftRight2I");
         compile("testShiftRight2L");
         compile("testUnsignedShiftRight2I");
-        compile("testUnsignedShiftRight2L");
+        // compile("testUnsignedShiftRight2L");
     }
 
     public static int testShiftRight2I(int a, int b) {
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -30,12 +30,16 @@
 import com.oracle.graal.api.runtime.Graal;
 import com.oracle.graal.compiler.GraalCompiler;
 import com.oracle.graal.compiler.ptx.PTXBackend;
+import com.oracle.graal.compiler.ptx.PTXTargetMethodAssembler;
 import com.oracle.graal.compiler.test.GraalCompilerTest;
 import com.oracle.graal.debug.Debug;
+import com.oracle.graal.hotspot.meta.HotSpotNmethod;
 import com.oracle.graal.hotspot.meta.HotSpotRuntime;
 import com.oracle.graal.hotspot.meta.HotSpotResolvedJavaMethod;
+import com.oracle.graal.hotspot.ptx.PTXHotSpotRuntime;
 import com.oracle.graal.java.GraphBuilderConfiguration;
 import com.oracle.graal.java.GraphBuilderPhase;
+import com.oracle.graal.lir.ptx.ParallelOver;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.spi.GraalCodeCacheProvider;
 import com.oracle.graal.phases.OptimisticOptimizations;
@@ -43,6 +47,8 @@
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.ptx.PTX;
+
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Modifier;
 
 public abstract class PTXTestBase extends GraalCompilerTest {
@@ -50,32 +56,36 @@
     private StructuredGraph sg;
 
     protected CompilationResult compile(String test) {
-        StructuredGraph graph = parse(test);
-        sg = graph;
-        Debug.dump(graph, "Graph");
-        TargetDescription target = new TargetDescription(new PTX(), true, 1, 0, true);
-        PTXBackend ptxBackend = new PTXBackend(Graal.getRequiredCapability(GraalCodeCacheProvider.class), target);
-        PhasePlan phasePlan = new PhasePlan();
-        GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.NONE);
-        phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
-        phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PTXPhase());
-        new PTXPhase().apply(graph);
-        CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false);
-        /*
-         * Use Suites.createDefaultSuites() instead of GraalCompilerTest.suites. The
-         * GraalCompilerTest.suites variable contains the Suites for the HotSpotRuntime. This code
-         * will not run on hotspot, so it should use the plain Graal default suites, without hotspot
-         * specific phases.
-         *
-         * Ultimately we might want to have both the kernel and the code natively compiled for GPU fallback to CPU in cases
-         * of ECC failure on kernel invocation.  
-         */
-        CompilationResult result = GraalCompiler.compileGraph(graph, cc, graph.method(), runtime,
-                                                              graalRuntime().getReplacements(), ptxBackend, target,
-                                                              null, phasePlan,
-                                                              OptimisticOptimizations.NONE, new SpeculationLog(),
-                                                              Suites.createDefaultSuites(), new ExternalCompilationResult());
-        return result;
+        if (runtime instanceof PTXHotSpotRuntime) {
+            StructuredGraph graph = parse(test);
+            sg = graph;
+            Debug.dump(graph, "Graph");
+            TargetDescription target = new TargetDescription(new PTX(), true, 1, 0, true);
+            PTXBackend ptxBackend = new PTXBackend(Graal.getRequiredCapability(GraalCodeCacheProvider.class), target);
+            PhasePlan phasePlan = new PhasePlan();
+            GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.NONE);
+            phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
+            phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PTXPhase());
+            new PTXPhase().apply(graph);
+            CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false);
+            /*
+             * Use Suites.createDefaultSuites() instead of GraalCompilerTest.suites. The
+             * GraalCompilerTest.suites variable contains the Suites for the HotSpotRuntime. This code
+             * will not run on hotspot, so it should use the plain Graal default suites, without hotspot
+             * specific phases.
+             *
+             * Ultimately we might want to have both the kernel and the code natively compiled for GPU fallback to CPU in cases
+             * of ECC failure on kernel invocation.  
+             */
+            CompilationResult result = GraalCompiler.compileGraph(graph, cc, graph.method(), runtime,
+                                                                  graalRuntime().getReplacements(), ptxBackend, target,
+                                                                  null, phasePlan,
+                                                                  OptimisticOptimizations.NONE, new SpeculationLog(),
+                                                                  Suites.createDefaultSuites(), new ExternalCompilationResult());
+            return result;
+        } else {
+            return null;
+        }
     }
 
     protected StructuredGraph getStructuredGraph() {
@@ -83,6 +93,9 @@
     }
 
     protected Object invoke(CompilationResult result, Object... args) {
+        if (result == null) {
+            return null;
+        }
         try {
             if (((ExternalCompilationResult) result).getEntryPoint() == 0) {
                 Debug.dump(result, "[CUDA] *** Null entry point - Not launching kernel");
@@ -94,8 +107,47 @@
             boolean isStatic = Modifier.isStatic(compiledMethod.getModifiers());
             Object[] executeArgs = argsWithReceiver((isStatic ? null : this), args);
             HotSpotRuntime hsr = (HotSpotRuntime) runtime;
-            InstalledCode installedCode = hsr.addExternalMethod(sg.method(), result, sg);
-            Object r = installedCode.executeVarargs(executeArgs);
+            InstalledCode installedCode = hsr.addExternalMethod(compiledMethod, result, sg);
+            Annotation[][] params = compiledMethod.getParameterAnnotations();
+
+            int dimensionX = 1;
+            int dimensionY = 1;
+            int dimensionZ = 1;
+
+            for (int p = 0; p < params.length; p++) {
+                Annotation[] annos = params[p];
+                if (annos != null) {
+                    for (int a = 0; a < annos.length; a++) {
+                        Annotation aa = annos[a];
+                        if (args[p] instanceof int[] && aa.annotationType().equals(ParallelOver.class)) {
+                            int[] iarray = (int[]) args[p];
+                            ParallelOver threadBlockDimension = (ParallelOver) aa;
+                            switch (threadBlockDimension.dimension()) {
+                                case X:
+                                    dimensionX = iarray.length;
+                                    break;
+                                case Y:
+                                    dimensionY = iarray.length;
+                                    break;
+                                case Z:
+                                    dimensionZ = iarray.length;
+                                    break;
+                            }
+                        }
+                    }
+                }
+            }
+            Object r;
+            if (dimensionX != 1 || dimensionY != 1 || dimensionZ != 1) {
+                /*
+                 * for now assert that the warp array block is no larger than the number of physical gpu cores.
+                 */
+                assert dimensionX * dimensionY * dimensionZ < PTXTargetMethodAssembler.getAvailableProcessors();
+
+                r = ((HotSpotNmethod) installedCode).executeParallel(dimensionX, dimensionY, dimensionZ, executeArgs);
+            } else {
+                r = installedCode.executeVarargs(executeArgs);
+            }
             return r;
         } catch (Throwable th) {
             th.printStackTrace();
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.compiler.ptx;
 
-import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
 
 import java.util.*;
 
@@ -40,6 +40,7 @@
 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.lir.StandardOp.LabelOp;
 import com.oracle.graal.graph.GraalInternalError;
 
 /**
@@ -52,6 +53,11 @@
     }
 
     @Override
+    public boolean shouldAllocateRegisters() {
+        return false;
+    }
+
+    @Override
     public FrameMap newFrameMap() {
         return new PTXFrameMap(runtime(), target, runtime().lookupRegisterConfig());
     }
@@ -80,7 +86,7 @@
 
     @Override
     public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) {
-        // Omit the frame if the method:
+        // Omit the frame of the method:
         // - has no spill slots or other slots allocated during register allocation
         // - has no callee-saved registers
         // - has no incoming arguments passed on the stack
@@ -89,14 +95,13 @@
         AbstractAssembler masm = createAssembler(frameMap);
         HotSpotFrameContext frameContext = new HotSpotFrameContext();
         TargetMethodAssembler tasm = new PTXTargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult);
-        tasm.setFrameSize(frameMap.frameSize());
+        tasm.setFrameSize(0);
         return tasm;
     }
 
-    private static void emitKernelEntry(TargetMethodAssembler tasm, LIRGenerator lirGen,
-                                        ResolvedJavaMethod codeCacheOwner) {
+    private static void emitKernelEntry(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod codeCacheOwner) {
         // Emit PTX kernel entry text based on PTXParameterOp
-        // instructions in the start block.  Remove the instructions
+        // instructions in the start block. Remove the instructions
         // once kernel entry text and directives are emitted to
         // facilitate seemless PTX code generation subsequently.
         assert codeCacheOwner != null : lirGen.getGraph() + " is not associated with a method";
@@ -132,8 +137,6 @@
         // Start emiting body of the PTX kernel.
         codeBuffer.emitString0(") {");
         codeBuffer.emitString("");
-
-        codeBuffer.emitString(".reg .u64" + " %rax;");
     }
 
     // Emit .reg space declarations
@@ -144,23 +147,53 @@
 
         final SortedSet<Integer> signed32 = new TreeSet<>();
         final SortedSet<Integer> signed64 = new TreeSet<>();
+        final SortedSet<Integer> unsigned64 = new TreeSet<>();
+        final SortedSet<Integer> float32 = new TreeSet<>();
+        final SortedSet<Integer> float64 = new TreeSet<>();
 
         ValueProcedure trackRegisterKind = new ValueProcedure() {
 
             @Override
             public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-                if (isRegister(value)) {
-                    RegisterValue regVal = (RegisterValue) value;
+                if (isVariable(value)) {
+                    Variable regVal = (Variable) value;
                     Kind regKind = regVal.getKind();
                     switch (regKind) {
-                       case Int:
-                           signed32.add(regVal.getRegister().encoding());
-                           break;
-                       case Long:
-                           signed64.add(regVal.getRegister().encoding());
-                           break;
-                       default :
-                           throw GraalInternalError.shouldNotReachHere("unhandled register type "  + value.toString());
+                        case Int:
+                            // If the register was used as a wider signed type
+                            // do not add it here
+                            if (!signed64.contains(regVal.index)) {
+                                signed32.add(regVal.index);
+                            }
+                            break;
+                        case Long:
+                            // If the register was used as a narrower signed type
+                            // remove it from there and add it to wider type.
+                            if (signed32.contains(regVal.index)) {
+                                signed32.remove(regVal.index);
+                            }
+                            signed64.add(regVal.index);
+                            break;
+                        case Float:
+                            // If the register was used as a wider signed type
+                            // do not add it here
+                            if (!float64.contains(regVal.index)) {
+                                float32.add(regVal.index);
+                            }
+                            break;
+                        case Double:
+                            // If the register was used as a narrower signed type
+                            // remove it from there and add it to wider type.
+                            if (float32.contains(regVal.index)) {
+                                float32.remove(regVal.index);
+                            }
+                            float64.add(regVal.index);
+                            break;
+                        case Object:
+                            unsigned64.add(regVal.index);
+                            break;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere("unhandled register type " + value.toString());
                     }
                 }
                 return value;
@@ -169,7 +202,12 @@
 
         for (Block b : lirGen.lir.codeEmittingOrder()) {
             for (LIRInstruction op : lirGen.lir.lir(b)) {
-                op.forEachOutput(trackRegisterKind);
+                if (op instanceof LabelOp) {
+                    // Don't consider this as a definition
+                } else {
+                    op.forEachTemp(trackRegisterKind);
+                    op.forEachOutput(trackRegisterKind);
+                }
             }
         }
 
@@ -179,6 +217,20 @@
         for (Integer i : signed64) {
             codeBuffer.emitString(".reg .s64 %r" + i.intValue() + ";");
         }
+        for (Integer i : unsigned64) {
+            codeBuffer.emitString(".reg .u64 %r" + i.intValue() + ";");
+        }
+        for (Integer i : float32) {
+            codeBuffer.emitString(".reg .f32 %r" + i.intValue() + ";");
+        }
+        for (Integer i : float64) {
+            codeBuffer.emitString(".reg .f64 %r" + i.intValue() + ";");
+        }
+        // emit predicate register declaration
+        int maxPredRegNum = ((PTXLIRGenerator) lirGen).getNextPredRegNumber();
+        if (maxPredRegNum > 0) {
+            codeBuffer.emitString(".reg .pred %p<" + maxPredRegNum + ">;");
+        }
     }
 
     @Override
@@ -192,6 +244,7 @@
         try {
             emitRegisterDecl(tasm, lirGen, codeCacheOwner);
         } catch (GraalInternalError e) {
+            e.printStackTrace();
             // TODO : Better error handling needs to be done once
             //        all types of parameters are handled.
             codeBuffer.setPosition(0);
@@ -202,6 +255,7 @@
         try {
             lirGen.lir.emitCode(tasm);
         } catch (GraalInternalError e) {
+            e.printStackTrace();
             // TODO : Better error handling needs to be done once
             //        all types of parameters are handled.
             codeBuffer.setPosition(0);
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,6 +24,7 @@
 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.*;
@@ -32,6 +33,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.debug.Debug;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
@@ -44,8 +46,6 @@
 import com.oracle.graal.lir.ptx.PTXArithmetic.Unary2Op;
 import com.oracle.graal.lir.ptx.PTXCompare.CompareOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.BranchOp;
-import com.oracle.graal.lir.ptx.PTXControlFlow.CondMoveOp;
-import com.oracle.graal.lir.ptx.PTXControlFlow.FloatCondMoveOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.ReturnOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.ReturnNoValOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.SequentialSwitchOp;
@@ -59,13 +59,22 @@
 import com.oracle.graal.lir.ptx.PTXMemOp.StoreReturnValOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.calc.ConvertNode.Op;
 import com.oracle.graal.nodes.java.*;
 
+import java.lang.annotation.*;
+
+
 /**
  * This class implements the PTX specific portion of the LIR generator.
  */
 public class PTXLIRGenerator extends LIRGenerator {
 
+    // Number of the predicate register that can be used when needed.
+    // This value will be recorded and incremented in the LIR instruction
+    // that sets a predicate register. (e.g., CompareOp)
+    private int nextPredRegNum;
+
     public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class);
     public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class);
 
@@ -73,13 +82,20 @@
 
         @Override
         public LIRInstruction createMove(AllocatableValue result, Value input) {
-            throw new InternalError("NYI");
+            throw GraalInternalError.unimplemented("PTXSpillMoveFactory.createMove()");
         }
     }
 
     public PTXLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) {
         super(graph, runtime, target, frameMap, cc, lir);
         lir.spillMoveFactory = new PTXSpillMoveFactory();
+        int callVariables = cc.getArgumentCount() + (cc.getReturn() == Value.ILLEGAL ? 0 : 1);
+        lir.setFirstVariableNumber(callVariables);
+        nextPredRegNum = 0;
+    }
+
+    public int getNextPredRegNumber() {
+        return nextPredRegNum;
     }
 
     @Override
@@ -107,7 +123,9 @@
             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());
+                return StackSlot.get(value.getKind().getStackKind(),
+                                     asStackSlot(value).getRawOffset(),
+                                     asStackSlot(value).getRawAddFrameSize());
             } else {
                 throw GraalInternalError.shouldNotReachHere();
             }
@@ -119,23 +137,62 @@
     public void emitPrologue() {
         // Need to emit .param directives based on incoming arguments and return value
         CallingConvention incomingArguments = cc;
-        int argCount = incomingArguments.getArgumentCount();
-        // Additional argument for return value.
-        Value[] params = new Value[argCount + 1];
-        for (int i = 0; i < argCount; i++) {
-            params[i] = toParamKind(incomingArguments.getArgument(i));
+        Object returnObject = incomingArguments.getReturn();
+        AllocatableValue[] params;
+        int argCount;
+
+        if (returnObject == Value.ILLEGAL) {
+            params = incomingArguments.getArguments();
+        } else {
+            argCount = incomingArguments.getArgumentCount();
+            params = new Variable[argCount + 1];
+            for (int i = 0; i < argCount; i++) {
+                params[i] = incomingArguments.getArgument(i);
+            }
+            params[argCount] = (Variable) returnObject;
         }
-        // Add the return value as the last parameter.
-        params[argCount] =  incomingArguments.getReturn();
 
         append(new PTXParameterOp(params));
         for (LocalNode local : graph.getNodes(LocalNode.class)) {
             Value param = params[local.index()];
-            assert param.getKind() == local.kind().getStackKind();
-            setResult(local, emitLoadParam(param.getKind(), param, null));
+            Annotation[] annos = graph.method().getParameterAnnotations()[local.index()];
+            Warp warpAnnotation = null;
+
+            if (annos != null) {
+                for (int a = 0; a < annos.length; a++) {
+                    if (annos[a].annotationType().equals(Warp.class)) {
+                        warpAnnotation = (Warp) annos[a];
+                    }
+                }
+            }
+            if (warpAnnotation != null) {
+                setResult(local, emitWarpParam(param.getKind(), warpAnnotation));
+            } else {
+                setResult(local, emitLoadParam(param.getKind(), param, null));
+            }
         }
     }
 
+    public Variable emitWarpParam(Kind kind, Warp annotation) {
+        Variable result = newVariable(kind);
+        Variable tid = newVariable(Kind.Char);
+
+        switch (annotation.dimension()) {
+            case X:
+                tid.setName("%tid.x");
+                break;
+            case Y:
+                tid.setName("%tid.y");
+                break;
+            case Z:
+                tid.setName("%tid.y");
+                break;
+        }
+        emitMove(result, tid);
+
+        return result;
+    }
+
     @Override
     public Variable emitMove(Value input) {
         Variable result = newVariable(input.getKind());
@@ -156,37 +213,45 @@
     public PTXAddressValue emitAddress(Value base, long displacement, Value index, int scale) {
         AllocatableValue baseRegister;
         long finalDisp = displacement;
+
         if (isConstant(base)) {
             if (asConstant(base).isNull()) {
                 baseRegister = Value.ILLEGAL;
-            } else if (asConstant(base).getKind() != Kind.Object) {
+            } else if (asConstant(base).getKind() != Kind.Object && !runtime.needsDataPatch(asConstant(base))) {
                 finalDisp += asConstant(base).asLong();
                 baseRegister = Value.ILLEGAL;
             } else {
                 baseRegister = load(base);
             }
+        } else if (base.equals(Value.ILLEGAL)) {
+            baseRegister = Value.ILLEGAL;
         } else {
             baseRegister = asAllocatable(base);
         }
 
-        if (index != Value.ILLEGAL && scale != 0) {
+        if (!index.equals(Value.ILLEGAL)) {
             if (isConstant(index)) {
                 finalDisp += asConstant(index).asLong() * scale;
             } else {
+                Value convertedIndex;
                 Value indexRegister;
+
+                convertedIndex = emitConvert(Op.I2L, index);
                 if (scale != 1) {
-                    indexRegister = emitMul(index, Constant.forInt(scale));
+                    if (CodeUtil.isPowerOf2(scale)) {
+                        indexRegister = emitShl(convertedIndex, Constant.forInt(CodeUtil.log2(scale)));
+                    } else {
+                        indexRegister = emitMul(convertedIndex, Constant.forInt(scale));
+                    }
                 } else {
-                    indexRegister = index;
+                    indexRegister = convertedIndex;
                 }
-
-                if (baseRegister == Value.ILLEGAL) {
+                if (baseRegister.equals(Value.ILLEGAL)) {
                     baseRegister = asAllocatable(indexRegister);
                 } else {
-                    Variable newBase = newVariable(Kind.Int);
-                    emitMove(newBase, baseRegister);
-                    baseRegister = newBase;
-                    baseRegister = emitAdd(baseRegister, indexRegister);
+                    Variable longBaseRegister = newVariable(Kind.Long);
+                    emitMove(longBaseRegister, baseRegister);
+                    baseRegister = emitAdd(longBaseRegister, indexRegister);
                 }
             }
         }
@@ -195,6 +260,8 @@
     }
 
     private PTXAddressValue asAddress(Value address) {
+        assert address != null;
+
         if (address instanceof PTXAddressValue) {
             return (PTXAddressValue) address;
         } else {
@@ -219,7 +286,7 @@
 
     @Override
     public Variable emitAddress(StackSlot address) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitAddress()");
     }
 
     @Override
@@ -231,24 +298,24 @@
     public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label) {
         switch (left.getKind().getStackKind()) {
             case Int:
-                append(new CompareOp(ICMP, cond, left, right));
-                append(new BranchOp(cond, label));
+                append(new CompareOp(ICMP, cond, left, right, nextPredRegNum));
+                append(new BranchOp(cond, label, nextPredRegNum++));
                 break;
             case Long:
-                append(new CompareOp(LCMP, cond, left, right));
-                append(new BranchOp(cond, label));
+                append(new CompareOp(LCMP, cond, left, right, nextPredRegNum));
+                append(new BranchOp(cond, label, nextPredRegNum++));
                 break;
             case Float:
-                append(new CompareOp(FCMP, cond, left, right));
-                append(new BranchOp(cond, label));
+                append(new CompareOp(FCMP, cond, left, right, nextPredRegNum));
+                append(new BranchOp(cond, label, nextPredRegNum++));
                 break;
             case Double:
-                append(new CompareOp(DCMP, cond, left, right));
-                append(new BranchOp(cond, label));
+                append(new CompareOp(DCMP, cond, left, right, nextPredRegNum));
+                append(new BranchOp(cond, label, nextPredRegNum++));
                 break;
             case Object:
-                append(new CompareOp(ACMP, cond, left, right));
-                append(new BranchOp(cond, label));
+                append(new CompareOp(ACMP, cond, left, right, nextPredRegNum));
+                append(new BranchOp(cond, label, nextPredRegNum++));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere("" + left.getKind());
@@ -257,79 +324,22 @@
 
     @Override
     public void emitOverflowCheckBranch(LabelRef label, boolean negated) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitOverflowCheckBranch()");
     }
 
     @Override
     public void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef label) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitIntegerTestBranch()");
     }
 
     @Override
     public Variable emitConditionalMove(Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
-        boolean mirrored = emitCompare(cond, left, right);
-        Condition finalCondition = mirrored ? cond.mirror() : cond;
-
-        Variable result = newVariable(trueValue.getKind());
-        switch (left.getKind().getStackKind()) {
-            case Int:
-            case Long:
-            case Object:
-                append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue)));
-                break;
-            case Float:
-            case Double:
-                append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere("missing: " + left.getKind());
-        }
-        return result;
+        // TODO: There is no conventional conditional move instruction in PTX.
+        // So, this method is changed to throw NYI exception.
+        // To be revisited if this needs to be really implemented.
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitConditionalMove()");
     }
 
-    /**
-     * This method emits the compare instruction, and may reorder the operands. It returns true if
-     * it did so.
-     *
-     *
-     * @param a the left operand of the comparison
-     * @param b the right operand of the comparison
-     * @return true if the left and right operands were switched, false otherwise
-     */
-    private boolean emitCompare(Condition cond, Value a, Value b) {
-        Variable left;
-        Value right;
-        boolean mirrored;
-        if (LIRValueUtil.isVariable(b)) {
-            left = load(b);
-            right = loadNonConst(a);
-            mirrored = true;
-        } else {
-            left = load(a);
-            right = loadNonConst(b);
-            mirrored = false;
-        }
-        switch (left.getKind().getStackKind()) {
-            case Int:
-                append(new CompareOp(ICMP, cond, left, right));
-                break;
-            case Long:
-                append(new CompareOp(LCMP, cond, left, right));
-                break;
-            case Object:
-                append(new CompareOp(ACMP, cond, left, right));
-                break;
-            case Float:
-                append(new CompareOp(FCMP, cond, left, right));
-                break;
-            case Double:
-                append(new CompareOp(DCMP, cond, left, right));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-        return mirrored;
-    }
 
     @Override
     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
@@ -483,12 +493,12 @@
 
     @Override
     public Variable emitUDiv(Value a, Value b, DeoptimizingNode deopting) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitUDiv()");
     }
 
     @Override
     public Variable emitURem(Value a, Value b, DeoptimizingNode deopting) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitURem()");
     }
 
     @Override
@@ -548,7 +558,7 @@
                 append(new Op2Stack(ISHL, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op1Stack(LSHL, result, loadNonConst(b)));
+                append(new Op2Stack(LSHL, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -564,7 +574,7 @@
                 append(new Op2Stack(ISHR, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op1Stack(LSHR, result, loadNonConst(b)));
+                append(new Op2Stack(LSHR, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -663,28 +673,28 @@
     }
 
     @Override
-    public void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, DeoptimizingNode deopting) {
         append(new ReturnOp(Value.ILLEGAL));
     }
 
     @Override
     public void emitMembar(int barriers) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitMembar()");
     }
 
     @Override
     protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitDirectCall()");
     }
 
     @Override
     protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitIndirectCall()");
     }
 
     @Override
     protected void emitForeignCall(ForeignCallLinkage callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitForeignCall()");
     }
 
     @Override
@@ -698,47 +708,47 @@
 
     @Override
     public void emitBitScanForward(Variable result, Value value) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitBitScanForward()");
     }
 
     @Override
     public void emitBitScanReverse(Variable result, Value value) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitBitScanReverse()");
     }
 
     @Override
     public Value emitMathAbs(Value input) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitMathAbs()");
     }
 
     @Override
     public Value emitMathSqrt(Value input) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitMathSqrt()");
     }
 
     @Override
     public Value emitMathLog(Value input, boolean base10) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitMathLog()");
     }
 
     @Override
     public Value emitMathCos(Value input) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitMathCos()");
     }
 
     @Override
     public Value emitMathSin(Value input) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitMathSin()");
     }
 
     @Override
     public Value emitMathTan(Value input) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitMathTan()");
     }
 
     @Override
     public void emitByteSwap(Variable result, Value input) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitByteSwap()");
     }
 
     @Override
@@ -755,10 +765,10 @@
         // Making a copy of the switch value is necessary because jump table destroys the input
         // value
         if (key.getKind() == Kind.Int || key.getKind() == Kind.Long) {
-            append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, Value.ILLEGAL));
+            append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, Value.ILLEGAL, nextPredRegNum));
         } else {
             assert key.getKind() == Kind.Object : key.getKind();
-            append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, newVariable(Kind.Object)));
+            append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, newVariable(Kind.Object), nextPredRegNum));
         }
     }
 
@@ -772,39 +782,39 @@
         // 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(target.wordKind), nextPredRegNum++));
     }
 
     @Override
     public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.visitCompareAndSwap()");
     }
 
     @Override
     public void visitBreakpointNode(BreakpointNode node) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.visitBreakpointNode()");
     }
 
     @Override
     public void visitSafepointNode(SafepointNode i) {
-        // LIRFrameState info = state();
+        // LIRFrameState info = state(i);
         // append(new PTXSafepointOp(info, runtime().config, this));
-        throw new InternalError("NYI");
+        Debug.log("visitSafePointNode unimplemented");
     }
 
     @Override
     public void emitUnwind(Value operand) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitUnwind()");
     }
 
     @Override
     public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitNullCheck()");
     }
 
     @Override
     public void visitInfopointNode(InfopointNode i) {
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.visitInfopointNode()");
     }
 
     public Variable emitLoadParam(Kind kind, Value address, DeoptimizingNode deopting) {
@@ -827,6 +837,13 @@
         append(new StoreReturnValOp(kind, storeAddress, input, deopting != null ? state(deopting) : null));
     }
 
+    @Override
+    public AllocatableValue resultOperandFor(Kind kind) {
+        if (kind == Kind.Void) {
+            return ILLEGAL;
+        }
+        return (new Variable(kind, 0));
+    }
 
     @Override
     public void visitReturn(ReturnNode x) {
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXTargetMethodAssembler.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXTargetMethodAssembler.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,6 +36,12 @@
     private static CompilerToGPU toGPU = HotSpotGraalRuntime.graalRuntime().getCompilerToGPU();
     private static boolean validDevice = toGPU.deviceInit();
 
+    private static final int totalProcessors = (validDevice ? toGPU.availableProcessors() : 0);
+
+    public static int getAvailableProcessors() {
+        return totalProcessors;
+    }
+
     // detach ??
 
     public PTXTargetMethodAssembler(TargetDescription target, CodeCacheProvider runtime, FrameMap frameMap,
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Wed Oct 02 13:26:31 2013 +0200
@@ -837,7 +837,7 @@
     }
 
     @Override
-    public void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, DeoptimizingNode deopting) {
         append(new ReturnOp(Value.ILLEGAL));
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -300,16 +300,16 @@
 
     final ValueNode getResult(String snippet) {
         processMethod(snippet);
-        assertEquals(1, graph.getNodes(ReturnNode.class).count());
-        return graph.getNodes(ReturnNode.class).first().result();
+        assertEquals(1, graph.getNodes().filter(ReturnNode.class).count());
+        return graph.getNodes().filter(ReturnNode.class).first().result();
     }
 
     private void processMethod(final String snippet) {
         graph = parse(snippet);
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-        new InliningPhase().apply(graph, context);
-        new PartialEscapePhase(false).apply(graph, context);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new PartialEscapePhase(false, new CanonicalizerPhase(true)).apply(graph, context);
     }
 
     private void compareGraphs(final String snippet, final String referenceSnippet) {
@@ -326,19 +326,19 @@
                 Assumptions assumptions = new Assumptions(false);
                 HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
                 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-                new InliningPhase().apply(graph, context);
+                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
                 if (loopPeeling) {
                     new LoopTransformHighPhase().apply(graph);
                 }
                 new DeadCodeEliminationPhase().apply(graph);
                 canonicalizer.apply(graph, context);
-                new PartialEscapePhase(false).apply(graph, context);
+                new PartialEscapePhase(false, canonicalizer).apply(graph, context);
 
                 new DeadCodeEliminationPhase().apply(graph);
                 canonicalizer.apply(graph, context);
 
                 StructuredGraph referenceGraph = parse(referenceSnippet);
-                new InliningPhase().apply(referenceGraph, context);
+                new InliningPhase(new CanonicalizerPhase(true)).apply(referenceGraph, context);
                 new DeadCodeEliminationPhase().apply(referenceGraph);
                 new CanonicalizerPhase(true).apply(referenceGraph, context);
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -30,12 +30,13 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 public class CompareCanonicalizerTest extends GraalCompilerTest {
 
     private StructuredGraph getCanonicalizedGraph(String name) {
         StructuredGraph graph = parse(name);
-        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
         return graph;
     }
 
@@ -53,7 +54,7 @@
             assertEquals(referenceGraph, graph);
         }
         Assumptions assumptions = new Assumptions(false);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(referenceGraph);
+        new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(runtime(), assumptions, replacements));
         for (int i = 1; i < 4; i++) {
             StructuredGraph graph = getCanonicalizedGraph("canonicalCompare" + i);
             assertEquals(referenceGraph, graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -45,7 +45,7 @@
                         Constant b = Constant.forInt(i < 100 ? a.asInt() : rand.nextInt());
                         boolean result1 = c1.foldCondition(a, b, null, false);
                         boolean result2 = c2.foldCondition(a, b, null, false);
-                        if (result1 && implies) {
+                        if (result1) {
                             assertTrue(result2);
                         }
                     }
@@ -60,7 +60,7 @@
         for (Condition c1 : Condition.values()) {
             for (Condition c2 : Condition.values()) {
                 Condition join = c1.join(c2);
-                assertTrue(join == c2.join(c1));
+                assertEquals(join, c2.join(c1));
                 if (join != null) {
                     for (int i = 0; i < 1000; i++) {
                         Constant a = Constant.forInt(rand.nextInt());
@@ -70,6 +70,8 @@
                         boolean resultJoin = join.foldCondition(a, b, null, false);
                         if (result1 && result2) {
                             assertTrue(resultJoin);
+                        } else {
+                            assertFalse(resultJoin);
                         }
                     }
                 }
@@ -83,7 +85,7 @@
         for (Condition c1 : Condition.values()) {
             for (Condition c2 : Condition.values()) {
                 Condition meet = c1.meet(c2);
-                assertTrue(meet == c2.meet(c1));
+                assertEquals(meet, c2.meet(c1));
                 if (meet != null) {
                     for (int i = 0; i < 1000; i++) {
                         Constant a = Constant.forInt(rand.nextInt());
@@ -93,6 +95,8 @@
                         boolean resultMeet = meet.foldCondition(a, b, null, false);
                         if (result1 || result2) {
                             assertTrue(resultMeet);
+                        } else {
+                            assertFalse(resultMeet);
                         }
                     }
                 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 /**
  * Collection of tests for {@link ConditionalEliminationPhase} including those that triggered bugs
@@ -141,7 +142,7 @@
 
         StructuredGraph graph = parse("testNullnessSnippet");
         new ConditionalEliminationPhase(runtime()).apply(graph);
-        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
         for (ConstantNode constant : graph.getNodes().filter(ConstantNode.class)) {
             assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
         }
@@ -163,7 +164,7 @@
     @Test
     public void testDisjunction() {
         StructuredGraph graph = parse("testDisjunctionSnippet");
-        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
         IfNode ifNode = (IfNode) graph.start().next();
         InstanceOfNode instanceOf = (InstanceOfNode) ifNode.condition();
         IsNullNode x = graph.unique(new IsNullNode(graph.getLocal(0)));
@@ -171,9 +172,9 @@
         ShortCircuitOrNode disjunction = graph.unique(new ShortCircuitOrNode(x, false, y, false, NOT_FREQUENT_PROBABILITY));
         LogicNegationNode negation = graph.unique(new LogicNegationNode(disjunction));
         ifNode.setCondition(negation);
-        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
         new ConditionalEliminationPhase(runtime()).apply(graph);
-        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
         for (ConstantNode constant : graph.getNodes().filter(ConstantNode.class)) {
             assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
         }
@@ -191,10 +192,10 @@
     public void testInvoke() {
         test("testInvokeSnippet", new Integer(16));
         StructuredGraph graph = parse("testInvokeSnippet");
-        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
         new ConditionalEliminationPhase(runtime()).apply(graph);
 
-        InvokeNode invoke = graph.getNodes(InvokeNode.class).first();
+        InvokeNode invoke = graph.getNodes().filter(InvokeNode.class).first();
         assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind());
     }
 
@@ -221,11 +222,43 @@
     @Test
     public void testTypeMerging() {
         StructuredGraph graph = parse("testTypeMergingSnippet");
-        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
         new ConditionalEliminationPhase(runtime()).apply(graph);
-        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
 
         assertEquals(0, graph.getNodes().filter(StoreFieldNode.class).count());
     }
 
+    public static String testInstanceOfCheckCastSnippet(Object e) {
+        if (e instanceof Entry) {
+            return ((Entry) e).name;
+        }
+        return null;
+    }
+
+    @Test
+    public void testInstanceOfCheckCast() {
+        StructuredGraph graph = parse("testInstanceOfCheckCastSnippet");
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
+        new ConditionalEliminationPhase(runtime()).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
+
+        assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
+    }
+
+    @Test
+    @Ignore
+    public void testInstanceOfCheckCastLowered() {
+        StructuredGraph graph = parse("testInstanceOfCheckCastSnippet");
+
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+        PhaseContext context = new PhaseContext(runtime(), null, replacements);
+
+        new LoweringPhase(canonicalizer).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        new ConditionalEliminationPhase(runtime()).apply(graph);
+        canonicalizer.apply(graph, context);
+
+        assertEquals(0, graph.getNodes().filter(GuardNode.class).count());
+    }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -83,7 +83,7 @@
             public void run() {
                 StructuredGraph graph = parse(snippet);
                 HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-                new InliningPhase().apply(graph, context);
+                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
                 new CanonicalizerPhase(true).apply(graph, context);
                 Debug.dump(graph, "Graph");
                 StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 public class EliminateNestedCheckCastsTest extends GraalCompilerTest {
 
@@ -113,8 +114,8 @@
             public StructuredGraph call() throws Exception {
                 Debug.dump(graph, "After parsing: " + snippet);
                 Assert.assertEquals(checkcasts, graph.getNodes().filter(CheckCastNode.class).count());
-                new CanonicalizerPhase.Instance(runtime(), new Assumptions(false), true).apply(graph);
-                Assert.assertEquals(afterCanon, graph.getNodes(CheckCastNode.class).count());
+                new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), new Assumptions(false), replacements));
+                Assert.assertEquals(afterCanon, graph.getNodes().filter(CheckCastNode.class).count());
                 return graph;
             }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -69,7 +69,7 @@
         GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault();
         new GraphBuilderPhase(runtime, conf, OptimisticOptimizations.ALL).apply(graph);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-        new InliningPhase().apply(graph, context);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
         return graph;
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.Lowerable.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -60,7 +59,7 @@
             public void run() {
                 StructuredGraph graph = parse(snippet);
                 PhaseContext context = new PhaseContext(runtime(), new Assumptions(false), replacements);
-                new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context);
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, context);
                 new FloatingReadPhase().apply(graph);
 
                 ReturnNode returnNode = null;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,9 +25,11 @@
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 
+import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
 
 import org.junit.*;
 import org.junit.internal.*;
@@ -87,7 +89,7 @@
     }
 
     @BeforeClass
-    public static void initializeDebgging() {
+    public static void initializeDebugging() {
         DebugEnvironment.initialize(System.out);
     }
 
@@ -114,8 +116,8 @@
 
     protected void assertConstantReturn(StructuredGraph graph, int value) {
         String graphString = getCanonicalGraphString(graph, false);
-        Assert.assertEquals("unexpected number of ReturnNodes: " + graphString, graph.getNodes(ReturnNode.class).count(), 1);
-        ValueNode result = graph.getNodes(ReturnNode.class).first().result();
+        Assert.assertEquals("unexpected number of ReturnNodes: " + graphString, graph.getNodes().filter(ReturnNode.class).count(), 1);
+        ValueNode result = graph.getNodes().filter(ReturnNode.class).first().result();
         Assert.assertTrue("unexpected ReturnNode result node: " + graphString, result.isConstant());
         Assert.assertEquals("unexpected ReturnNode result kind: " + graphString, result.asConstant().getKind(), Kind.Int);
         Assert.assertEquals("unexpected ReturnNode result: " + graphString, result.asConstant().asInt(), value);
@@ -169,7 +171,7 @@
         return parse(getMethod(methodName));
     }
 
-    private static int compilationId = 0;
+    private static AtomicInteger compilationId = new AtomicInteger();
 
     /**
      * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}.
@@ -206,11 +208,45 @@
         }
     }
 
+    @SuppressWarnings("serial")
+    public static class MultiCauseAssertionError extends AssertionError {
+
+        private Throwable[] causes;
+
+        public MultiCauseAssertionError(String message, Throwable... causes) {
+            super(message);
+            this.causes = causes;
+        }
+
+        @Override
+        public void printStackTrace(PrintStream out) {
+            super.printStackTrace(out);
+            int num = 0;
+            for (Throwable cause : causes) {
+                if (cause != null) {
+                    out.print("cause " + (num++));
+                    cause.printStackTrace(out);
+                }
+            }
+        }
+
+        @Override
+        public void printStackTrace(PrintWriter out) {
+            super.printStackTrace(out);
+            int num = 0;
+            for (Throwable cause : causes) {
+                if (cause != null) {
+                    out.print("cause " + (num++) + ": ");
+                    cause.printStackTrace(out);
+                }
+            }
+        }
+    }
+
     protected void testN(int n, final String name, final Object... args) {
-        final Throwable[] errors = new Throwable[n];
+        final List<Throwable> errors = new ArrayList<>(n);
         Thread[] threads = new Thread[n];
         for (int i = 0; i < n; i++) {
-            final int idx = i;
             Thread t = new Thread(i + ":" + name) {
 
                 @Override
@@ -218,26 +254,23 @@
                     try {
                         test(name, args);
                     } catch (Throwable e) {
-                        errors[idx] = e;
+                        errors.add(e);
                     }
                 }
             };
             threads[i] = t;
             t.start();
         }
-        int failed = 0;
         for (int i = 0; i < n; i++) {
             try {
                 threads[i].join();
             } catch (InterruptedException e) {
-                errors[i] = e;
-            }
-            if (errors[i] != null) {
-                errors[i].printStackTrace();
-                failed++;
+                errors.add(e);
             }
         }
-        Assert.assertTrue(failed + " of " + n + " failed", failed == 0);
+        if (!errors.isEmpty()) {
+            throw new MultiCauseAssertionError(errors.size() + " failures", errors.toArray(new Throwable[errors.size()]));
+        }
     }
 
     protected Object referenceInvoke(Method method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
@@ -421,7 +454,7 @@
             }
         }
 
-        final int id = compilationId++;
+        final int id = compilationId.incrementAndGet();
 
         InstalledCode installedCode = Debug.scope("Compiling", new Object[]{runtime, new DebugDumpScope(String.valueOf(id), true)}, new Callable<InstalledCode>() {
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 /**
  * In the following tests, the usages of local variable "a" are replaced with the integer constant
@@ -144,7 +145,7 @@
             n.replaceFirstInput(local, constant);
         }
         Debug.dump(graph, "Graph");
-        new CanonicalizerPhase.Instance(runtime(), new Assumptions(false), true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), new Assumptions(false), replacements));
         for (FrameState fs : local.usages().filter(FrameState.class).snapshot()) {
             fs.replaceFirstInput(local, null);
         }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -74,7 +74,7 @@
         final Method method = getMethod("testMethod");
         final StructuredGraph graph = parseDebug(method);
         int graphLineSPs = 0;
-        for (InfopointNode ipn : graph.getNodes(InfopointNode.class)) {
+        for (InfopointNode ipn : graph.getNodes().filter(InfopointNode.class)) {
             if (ipn.reason == InfopointReason.LINE_NUMBER) {
                 ++graphLineSPs;
             }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -67,7 +67,7 @@
         }
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-        new InliningPhase(hints).apply(graph, context);
+        new InliningPhase(hints, new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -78,7 +78,7 @@
 
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-        new InliningPhase(hints).apply(graph, context);
+        new InliningPhase(hints, new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
         StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -62,7 +61,7 @@
         test("testSynchronizedSnippet", new A(), new A());
 
         StructuredGraph graph = getGraph("testSynchronizedSnippet");
-        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
         new LockEliminationPhase().apply(graph);
         assertEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
         assertEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
@@ -80,7 +79,7 @@
         test("testSynchronizedMethodSnippet", new A());
 
         StructuredGraph graph = getGraph("testSynchronizedMethodSnippet");
-        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), null, replacements));
         new LockEliminationPhase().apply(graph);
         assertEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
         assertEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
@@ -93,10 +92,10 @@
         Assumptions assumptions = new Assumptions(true);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, phasePlan, OptimisticOptimizations.ALL);
         new CanonicalizerPhase(true).apply(graph, context);
-        new InliningPhase().apply(graph, context);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
-        new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context);
+        new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new ValueAnchorCleanupPhase().apply(graph);
         new LockEliminationPhase().apply(graph);
         return graph;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 public class LoopUnswitchTest extends GraalCompilerTest {
 
@@ -133,8 +134,8 @@
         }
 
         Assumptions assumptions = new Assumptions(false);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(graph);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(referenceGraph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), assumptions, replacements));
+        new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(runtime(), assumptions, replacements));
         Debug.scope("Test", new DebugDumpScope("Test:" + snippet), new Runnable() {
 
             @Override
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,7 +36,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
@@ -222,7 +221,7 @@
     public void testArrayCopy() {
         SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES, MemoryScheduling.OPTIMAL);
         StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
-        ReturnNode ret = graph.getNodes(ReturnNode.class).first();
+        ReturnNode ret = graph.getNodes().filter(ReturnNode.class).first();
         assertTrue(ret.result() instanceof FloatingReadNode);
         assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
         assertReadWithinReturnBlock(schedule, true);
@@ -502,9 +501,9 @@
                 HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
                 new CanonicalizerPhase(true).apply(graph, context);
                 if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
-                    new InliningPhase().apply(graph, context);
+                    new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
                 }
-                new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context);
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, context);
                 if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
                     for (Node node : graph.getNodes()) {
                         if (node instanceof StateSplit) {
@@ -523,8 +522,8 @@
 
                 MidTierContext midContext = new MidTierContext(runtime(), assumptions, replacements, runtime().getTarget(), OptimisticOptimizations.ALL);
                 new GuardLoweringPhase().apply(graph, midContext);
-                new LoweringPhase(LoweringType.AFTER_GUARDS).apply(graph, midContext);
-                new LoweringPhase(LoweringType.AFTER_FSA).apply(graph, midContext);
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, midContext);
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, midContext);
 
                 SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, memsched);
                 schedule.apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -95,7 +95,7 @@
         }
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-        new InliningPhase(hints).apply(graph, context);
+        new InliningPhase(hints, new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
         return graph;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -30,7 +30,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -94,7 +93,7 @@
         StructuredGraph graph = parse(snippet);
         PhaseContext context = new PhaseContext(runtime(), new Assumptions(false), replacements);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-        new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context);
+        new LoweringPhase(canonicalizer).apply(graph, context);
         canonicalizer.apply(graph, context);
         new PushThroughPiPhase().apply(graph);
         canonicalizer.apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.Lowerable.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -85,7 +84,7 @@
             public void run() {
                 StructuredGraph graph = parse(snippet);
                 PhaseContext context = new PhaseContext(runtime(), new Assumptions(false), replacements);
-                new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context);
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, context);
                 new FloatingReadPhase().apply(graph);
                 new EliminatePartiallyRedundantGuardsPhase(true, false).apply(graph);
                 new ReadEliminationPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 public class ReassociateAndCanonicalTest extends GraalCompilerTest {
 
@@ -241,12 +242,12 @@
         return (2 - rnd) - 1;
     }
 
-    private <T extends Node & Node.IterableNodeType> void test(String test, String ref) {
+    private <T extends Node & IterableNodeType> void test(String test, String ref) {
         StructuredGraph testGraph = parse(test);
         Assumptions assumptions = new Assumptions(false);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(testGraph);
+        new CanonicalizerPhase(true).apply(testGraph, new PhaseContext(runtime(), assumptions, replacements));
         StructuredGraph refGraph = parse(ref);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(refGraph);
+        new CanonicalizerPhase(true).apply(refGraph, new PhaseContext(runtime(), assumptions, replacements));
         assertEquals(testGraph, refGraph);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 /**
  * In the following tests, the scalar type system of the compiler should be complete enough to see
@@ -166,9 +167,9 @@
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
         Assumptions assumptions = new Assumptions(false);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), assumptions, replacements));
         new ConditionalEliminationPhase(runtime()).apply(graph);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), assumptions, replacements));
         StructuredGraph referenceGraph = parse(referenceSnippet);
         assertEquals(referenceGraph, graph);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 /**
  * This class tests some specific patterns the stamp system should be able to canonicalize away
@@ -109,7 +110,7 @@
 
     private void testZeroReturn(String methodName) {
         StructuredGraph graph = parse(methodName);
-        new CanonicalizerPhase.Instance(runtime(), new Assumptions(false), true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), new Assumptions(false), replacements));
         new DeadCodeEliminationPhase().apply(graph);
         assertConstantReturn(graph, 0);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 public class StraighteningTest extends GraalCompilerTest {
 
@@ -89,7 +90,7 @@
         // No debug scope to reduce console noise for @Test(expected = ...) tests
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
-        new CanonicalizerPhase.Instance(runtime(), new Assumptions(false), true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), new Assumptions(false), replacements));
         StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
         assertEquals(referenceGraph, graph);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -35,6 +35,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.phases.tiers.*;
 
 /**
  * In the following tests, the scalar type system of the compiler should be complete enough to see
@@ -44,7 +45,7 @@
 
     @Test
     public void test1() {
-        test("test1Snippet", CheckCastNode.class);
+        testHelper("test1Snippet", CheckCastNode.class);
     }
 
     public static int test1Snippet(Object a) {
@@ -56,7 +57,7 @@
 
     @Test
     public void test2() {
-        test("test2Snippet", CheckCastNode.class);
+        testHelper("test2Snippet", CheckCastNode.class);
     }
 
     public static int test2Snippet(Object a) {
@@ -161,7 +162,7 @@
 
     @Test
     public void test6() {
-        test("test6Snippet", CheckCastNode.class);
+        testHelper("test6Snippet", CheckCastNode.class);
     }
 
     public static int test6Snippet(int i) throws IOException {
@@ -184,13 +185,13 @@
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
         Assumptions assumptions = new Assumptions(false);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), assumptions, replacements));
         new ConditionalEliminationPhase(runtime()).apply(graph);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), assumptions, replacements));
         // a second canonicalizer is needed to process nested MaterializeNodes
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), assumptions, replacements));
         StructuredGraph referenceGraph = parse(referenceSnippet);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(referenceGraph);
+        new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(runtime(), assumptions, replacements));
         assertEquals(referenceGraph, graph);
     }
 
@@ -236,14 +237,14 @@
         }
     }
 
-    private <T extends Node & Node.IterableNodeType> void test(String snippet, Class<T> clazz) {
+    private <T extends Node> void testHelper(String snippet, Class<T> clazz) {
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
         Assumptions assumptions = new Assumptions(false);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), assumptions, replacements));
         new ConditionalEliminationPhase(runtime()).apply(graph);
-        new CanonicalizerPhase.Instance(runtime(), assumptions, true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), assumptions, replacements));
         Debug.dump(graph, "Graph");
-        Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes(clazz).iterator().hasNext());
+        Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes().filter(clazz).iterator().hasNext());
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.test.*;
 
 /**
@@ -55,7 +56,7 @@
     public void test1() {
         Method method = getMethod("testMethod");
         final StructuredGraph graph = parse(method);
-        new CanonicalizerPhase.Instance(runtime(), new Assumptions(false), true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime(), new Assumptions(false), replacements));
         new DeadCodeEliminationPhase().apply(graph);
 
         for (Node node : graph.getNodes()) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -42,7 +42,7 @@
         graph = parse(snippet);
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-        new InliningPhase().apply(graph, context);
-        new EarlyReadEliminationPhase().apply(graph, context);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new EarlyReadEliminationPhase(new CanonicalizerPhase(true)).apply(graph, context);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -234,17 +234,18 @@
 
                 Assumptions assumptions = new Assumptions(false);
                 HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-                new InliningPhase().apply(graph, context);
+                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
                 new DeadCodeEliminationPhase().apply(graph);
                 new CanonicalizerPhase(true).apply(graph, context);
-                new PartialEscapePhase(iterativeEscapeAnalysis).apply(graph, context);
-                Assert.assertEquals(1, graph.getNodes(ReturnNode.class).count());
-                ReturnNode returnNode = graph.getNodes(ReturnNode.class).first();
+                new PartialEscapePhase(iterativeEscapeAnalysis, new CanonicalizerPhase(true)).apply(graph, context);
+                Assert.assertEquals(1, graph.getNodes().filter(ReturnNode.class).count());
+                ReturnNode returnNode = graph.getNodes().filter(ReturnNode.class).first();
                 if (expectedConstantResult != null) {
                     Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant());
                     Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant());
                 }
-                int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewArrayNode.class).count() + graph.getNodes(CommitAllocationNode.class).count();
+                int newInstanceCount = graph.getNodes().filter(NewInstanceNode.class).count() + graph.getNodes().filter(NewArrayNode.class).count() +
+                                graph.getNodes().filter(CommitAllocationNode.class).count();
                 Assert.assertEquals(0, newInstanceCount);
                 return returnNode;
             }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -82,8 +82,8 @@
 
     final ReturnNode getReturn(String snippet) {
         processMethod(snippet);
-        assertEquals(1, graph.getNodes(ReturnNode.class).count());
-        return graph.getNodes(ReturnNode.class).first();
+        assertEquals(1, graph.getNodes().filter(ReturnNode.class).count());
+        return graph.getNodes().filter(ReturnNode.class).first();
     }
 
     private void processMethod(final String snippet) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -236,15 +236,15 @@
 
     final ReturnNode getReturn(String snippet) {
         processMethod(snippet);
-        assertEquals(1, graph.getNodes(ReturnNode.class).count());
-        return graph.getNodes(ReturnNode.class).first();
+        assertEquals(1, graph.getNodes().filter(ReturnNode.class).count());
+        return graph.getNodes().filter(ReturnNode.class).first();
     }
 
     protected void processMethod(final String snippet) {
         graph = parse(snippet);
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-        new InliningPhase().apply(graph, context);
-        new PartialEscapePhase(false, true).apply(graph, context);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new PartialEscapePhase(false, true, new CanonicalizerPhase(true)).apply(graph, context);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -126,7 +126,7 @@
 
     @Test
     public void testCache() {
-        testMaterialize("testCacheSnippet", 0.5, 1);
+        testMaterialize("testCacheSnippet", 0.75, 1);
     }
 
     public static class CacheKey {
@@ -167,13 +167,13 @@
     final void testMaterialize(final String snippet, double expectedProbability, int expectedCount, Class<? extends Node>... invalidNodeClasses) {
         StructuredGraph result = processMethod(snippet);
         try {
-            Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", result.getNodes(NewInstanceNode.class).isEmpty());
-            Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", result.getNodes(NewArrayNode.class).isEmpty());
+            Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", result.getNodes().filter(NewInstanceNode.class).isEmpty());
+            Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", result.getNodes().filter(NewArrayNode.class).isEmpty());
 
             NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(result).apply();
             double probabilitySum = 0;
             int materializeCount = 0;
-            for (CommitAllocationNode materialize : result.getNodes(CommitAllocationNode.class)) {
+            for (CommitAllocationNode materialize : result.getNodes().filter(CommitAllocationNode.class)) {
                 probabilitySum += nodeProbabilities.get(materialize) * materialize.getVirtualObjects().size();
                 materializeCount += materialize.getVirtualObjects().size();
             }
@@ -199,10 +199,10 @@
 
                 Assumptions assumptions = new Assumptions(false);
                 HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-                new InliningPhase().apply(graph, context);
+                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
                 new DeadCodeEliminationPhase().apply(graph);
                 new CanonicalizerPhase(true).apply(graph, context);
-                new PartialEscapePhase(false).apply(graph, context);
+                new PartialEscapePhase(false, new CanonicalizerPhase(true)).apply(graph, context);
 
                 for (MergeNode merge : graph.getNodes(MergeNode.class)) {
                     merge.setStateAfter(null);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -240,7 +240,7 @@
                 HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, phasePlan, OptimisticOptimizations.ALL);
                 Debug.dump(graph, "Graph");
                 new CanonicalizerPhase(true).apply(graph, context);
-                new InliningPhase().apply(graph, context);
+                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
                 Debug.dump(graph, "Graph");
                 new CanonicalizerPhase(true).apply(graph, context);
                 new DeadCodeEliminationPhase().apply(graph);
@@ -279,7 +279,7 @@
     private static int[] countMethodInfopoints(StructuredGraph graph) {
         int start = 0;
         int end = 0;
-        for (InfopointNode ipn : graph.getNodes(InfopointNode.class)) {
+        for (InfopointNode ipn : graph.getNodes().filter(InfopointNode.class)) {
             if (ipn.reason == InfopointReason.METHOD_START) {
                 ++start;
             } else if (ipn.reason == InfopointReason.METHOD_END) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Oct 02 13:26:31 2013 +0200
@@ -229,7 +229,7 @@
                 List<Block> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock, nodeProbabilities);
                 List<Block> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock, nodeProbabilities);
 
-                LIR lir = new LIR(schedule.getCFG(), schedule.getBlockToNodesMap(), linearScanOrder, codeEmittingOrder, speculationLog);
+                LIR lir = new LIR(schedule.getCFG(), schedule.getBlockToNodesMap(), linearScanOrder, codeEmittingOrder);
                 Debug.dump(lir, "After linear scan order");
                 return lir;
 
@@ -238,7 +238,7 @@
 
     }
 
-    public static LIRGenerator emitLIR(Backend backend, final TargetDescription target, final LIR lir, StructuredGraph graph, CallingConvention cc) {
+    public static LIRGenerator emitLIR(final Backend backend, final TargetDescription target, final LIR lir, StructuredGraph graph, CallingConvention cc) {
         final FrameMap frameMap = backend.newFrameMap();
         final LIRGenerator lirGen = backend.newLIRGenerator(graph, frameMap, cc, lir);
 
@@ -269,7 +269,9 @@
         Debug.scope("Allocator", new Runnable() {
 
             public void run() {
-                new LinearScan(target, lir, lirGen, frameMap).allocate();
+                if (backend.shouldAllocateRegisters()) {
+                    new LinearScan(target, lir, lirGen, frameMap).allocate();
+                }
             }
         });
         return lirGen;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,8 +36,6 @@
 public class GraalDebugConfig implements DebugConfig {
 
     // @formatter:off
-    @Option(help = "Enable scope-based debugging", name = "Debug")
-    public static final OptionValue<Boolean> DebugEnabled = new OptionValue<>(true);
     @Option(help = "Pattern for scope(s) to in which dumping is enabled (see DebugFilter and Debug.dump)")
     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)")
@@ -53,7 +51,7 @@
                    "Partial - aggregate by partially qualified name (e.g., A.B.C.D.Counter and X.Y.Z.D.Counter will be merged to D.Counter)%n" +
                    "Complete - aggregate by qualified name%n" +
                    "Thread - aggregate by qualified name and thread")
-    public static final OptionValue<String> DebugValueSummary = new OptionValue<>("Complete");
+    public static final OptionValue<String> DebugValueSummary = new OptionValue<>("Name");
     @Option(help = "Send Graal IR to dump handlers on error")
     public static final OptionValue<Boolean> DumpOnError = new OptionValue<>(false);
     @Option(help = "Enable expensive assertions")
@@ -68,6 +66,10 @@
     };
     // @formatter:on
 
+    public static boolean areDebugScopePatternsEnabled() {
+        return DumpOnError.getValue() || Dump.getValue() != null || Meter.getValue() != null || Time.getValue() != null || Log.getValue() != null;
+    }
+
     private final DebugFilter logFilter;
     private final DebugFilter meterFilter;
     private final DebugFilter timerFilter;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Wed Oct 02 13:26:31 2013 +0200
@@ -48,7 +48,7 @@
     protected HashMap<VirtualObjectNode, VirtualObject> virtualObjects = new HashMap<>();
     protected IdentityHashMap<VirtualObjectNode, EscapeObjectState> objectStates = new IdentityHashMap<>();
 
-    public LIRFrameState build(FrameState topState, short reason, LabelRef exceptionEdge) {
+    public LIRFrameState build(FrameState topState, LabelRef exceptionEdge) {
         assert virtualObjects.size() == 0;
         assert objectStates.size() == 0;
 
@@ -101,11 +101,11 @@
         }
         objectStates.clear();
 
-        return newLIRFrameState(reason, exceptionEdge, frame, virtualObjectsArray);
+        return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray);
     }
 
-    protected LIRFrameState newLIRFrameState(short reason, LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) {
-        return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge, reason);
+    protected LIRFrameState newLIRFrameState(LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) {
+        return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge);
     }
 
     protected BytecodeFrame computeFrameForState(FrameState state) {
@@ -122,7 +122,7 @@
         if (state.outerFrameState() != null) {
             caller = computeFrameForState(state.outerFrameState());
         }
-        assert state.bci != FrameState.UNKNOWN_BCI : "bci == " + state.bci;
+        assert state.bci >= FrameState.BEFORE_BCI : "bci == " + state.bci;
         return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks);
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Wed Oct 02 13:26:31 2013 +0200
@@ -228,26 +228,26 @@
         if (!deopt.canDeoptimize()) {
             return null;
         }
-        return stateFor(deopt.getDeoptimizationState(), deopt.getDeoptimizationReason());
+        return stateFor(deopt.getDeoptimizationState());
     }
 
     public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) {
         if (!deopt.canDeoptimize()) {
             return null;
         }
-        return stateForWithExceptionEdge(deopt.getDeoptimizationState(), deopt.getDeoptimizationReason(), exceptionEdge);
+        return stateForWithExceptionEdge(deopt.getDeoptimizationState(), exceptionEdge);
     }
 
-    public LIRFrameState stateFor(FrameState state, DeoptimizationReason reason) {
-        return stateForWithExceptionEdge(state, reason, null);
+    public LIRFrameState stateFor(FrameState state) {
+        return stateForWithExceptionEdge(state, null);
     }
 
-    public LIRFrameState stateForWithExceptionEdge(FrameState state, DeoptimizationReason reason, LabelRef exceptionEdge) {
+    public LIRFrameState stateForWithExceptionEdge(FrameState state, LabelRef exceptionEdge) {
         if (needOnlyOopMaps()) {
-            return new LIRFrameState(null, null, null, (short) -1);
+            return new LIRFrameState(null, null, null);
         }
         assert state != null;
-        return debugInfoBuilder.build(state, lir.getDeoptimizationReasons().addSpeculation(reason), exceptionEdge);
+        return debugInfoBuilder.build(state, exceptionEdge);
     }
 
     /**
@@ -616,7 +616,15 @@
 
     @Override
     public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
-        LIRFrameState state = !linkage.canDeoptimize() ? null : stateFor(info.getDeoptimizationState(), info.getDeoptimizationReason());
+        LIRFrameState state = null;
+        if (linkage.canDeoptimize()) {
+            if (info != null) {
+                state = stateFor(info.getDeoptimizationState());
+            } else {
+                assert needOnlyOopMaps();
+                state = new LIRFrameState(null, null, null);
+            }
+        }
 
         // move the arguments into the correct location
         CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,12 +22,12 @@
  */
 package com.oracle.graal.compiler.phases;
 
+import static com.oracle.graal.compiler.phases.HighTier.Options.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.loop.phases.*;
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
@@ -37,12 +37,15 @@
 
 public class HighTier extends PhaseSuite<HighTierContext> {
 
-    // @formatter:off
-    @Option(help = "")
-    public static final OptionValue<Boolean> VerifyUsageWithEquals = new OptionValue<>(true);
-    @Option(help = "Enable inlining")
-    public static final OptionValue<Boolean> Inline = new OptionValue<>(true);
-    // @formatter:on
+    static class Options {
+
+        // @formatter:off
+        @Option(help = "")
+        public static final OptionValue<Boolean> VerifyUsageWithEquals = new OptionValue<>(true);
+        @Option(help = "Enable inlining")
+        public static final OptionValue<Boolean> Inline = new OptionValue<>(true);
+        // @formatter:on
+    }
 
     public HighTier() {
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!AOTCompilation.getValue());
@@ -60,12 +63,12 @@
             if (IterativeInlining.getValue()) {
                 appendPhase(new IterativeInliningPhase(canonicalizer));
             } else {
-                appendPhase(new InliningPhase());
+                appendPhase(new InliningPhase(canonicalizer));
                 appendPhase(new DeadCodeEliminationPhase());
 
                 if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
                     appendPhase(canonicalizer);
-                    appendPhase(new IterativeConditionalEliminationPhase());
+                    appendPhase(new IterativeConditionalEliminationPhase(canonicalizer));
                 }
             }
         }
@@ -73,15 +76,15 @@
         appendPhase(new CleanTypeProfileProxyPhase());
 
         if (FullUnroll.getValue()) {
-            appendPhase(new LoopFullUnrollPhase(!AOTCompilation.getValue()));
+            appendPhase(new LoopFullUnrollPhase(canonicalizer));
         }
 
         if (OptTailDuplication.getValue()) {
-            appendPhase(new TailDuplicationPhase());
+            appendPhase(new TailDuplicationPhase(canonicalizer));
         }
 
         if (PartialEscapeAnalysis.getValue()) {
-            appendPhase(new PartialEscapePhase(true));
+            appendPhase(new PartialEscapePhase(true, canonicalizer));
         }
 
         if (OptConvertDeoptsToGuards.getValue()) {
@@ -98,6 +101,6 @@
             appendPhase(canonicalizer);
         }
 
-        appendPhase(new LoweringPhase(LoweringType.BEFORE_GUARDS));
+        appendPhase(new LoweringPhase(canonicalizer));
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,8 @@
  */
 package com.oracle.graal.compiler.phases;
 
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
+import static com.oracle.graal.phases.GraalOptions.*;
+
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -30,7 +31,9 @@
 public class LowTier extends PhaseSuite<LowTierContext> {
 
     public LowTier() {
-        appendPhase(new LoweringPhase(LoweringType.AFTER_FSA));
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!AOTCompilation.getValue());
+
+        appendPhase(new LoweringPhase(canonicalizer));
 
         appendPhase(new ExpandLogicPhase());
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,7 +25,6 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import com.oracle.graal.loop.phases.*;
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -47,11 +46,11 @@
         appendPhase(new LockEliminationPhase());
 
         if (OptReadElimination.getValue()) {
-            appendPhase(new EarlyReadEliminationPhase());
+            appendPhase(new EarlyReadEliminationPhase(canonicalizer));
         }
 
         if (OptFloatingReads.getValue()) {
-            IncrementalCanonicalizerPhase<MidTierContext> incCanonicalizer = new IncrementalCanonicalizerPhase<>();
+            IncrementalCanonicalizerPhase<MidTierContext> incCanonicalizer = new IncrementalCanonicalizerPhase<>(canonicalizer);
             incCanonicalizer.appendPhase(new FloatingReadPhase());
             appendPhase(incCanonicalizer);
             if (OptReadElimination.getValue()) {
@@ -69,7 +68,7 @@
         }
 
         if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
-            appendPhase(new IterativeConditionalEliminationPhase());
+            appendPhase(new IterativeConditionalEliminationPhase(canonicalizer));
         }
 
         if (OptEliminatePartiallyRedundantGuards.getValue()) {
@@ -82,14 +81,16 @@
 
         appendPhase(new LoopSafepointEliminationPhase());
 
-        appendPhase(new SafepointInsertionPhase());
+        appendPhase(new LoopSafepointInsertionPhase());
 
         appendPhase(new GuardLoweringPhase());
 
-        appendPhase(new LoweringPhase(LoweringType.AFTER_GUARDS));
+        appendPhase(new LoweringPhase(canonicalizer));
 
         appendPhase(new FrameStateAssignmentPhase());
 
+        appendPhase(new DeoptimizationGroupingPhase());
+
         if (OptCanonicalizer.getValue()) {
             appendPhase(canonicalizer);
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Wed Oct 02 13:26:31 2013 +0200
@@ -55,6 +55,8 @@
 
     public abstract TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult);
 
+    public abstract boolean shouldAllocateRegisters();
+
     /**
      * Emits the code for a given graph.
      * 
--- a/graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugHistogramTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugHistogramTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -27,6 +27,7 @@
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.internal.*;
 
 public class DebugHistogramTest {
 
@@ -34,8 +35,13 @@
     public void testEmptyHistogram() {
         DebugHistogram histogram = Debug.createHistogram("TestHistogram");
         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        histogram.print(new PrintStream(outputStream));
+
+        new DebugHistogramAsciiPrinter(new PrintStream(outputStream)).print(histogram);
         Assert.assertEquals("TestHistogram is empty.\n", outputStream.toString());
+
+        outputStream.reset();
+        new DebugHistogramRPrinter(new PrintStream(outputStream)).print(histogram);
+        Assert.assertEquals("", outputStream.toString());
     }
 
     @Test
@@ -44,19 +50,28 @@
         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
         histogram.add(new Integer(1));
         histogram.add(new Integer(1));
-        histogram.print(new PrintStream(outputStream));
+        new DebugHistogramAsciiPrinter(new PrintStream(outputStream)).print(histogram);
         String[] lines = outputStream.toString().split("\n");
-        Assert.assertEquals(4, lines.length);
-        Assert.assertEquals("TestHistogram has 1 unique elements and 2 total elements:", lines[0]);
-        Assert.assertEquals(
-                        "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------",
-                        lines[1]);
-        Assert.assertEquals(
-                        "| 1                                                  | 2          | ==================================================================================================== |",
-                        lines[2]);
-        Assert.assertEquals(
-                        "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------",
-                        lines[3]);
+        // @formatter:off
+        String[] expected = {
+            "TestHistogram has 1 unique elements and 2 total elements:",
+            "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------",
+            "| 1                                                  | 2          | ==================================================================================================== |",
+            "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
+        };
+        // @formatter:on
+        Assert.assertArrayEquals(expected, lines);
+
+        outputStream.reset();
+        new DebugHistogramRPrinter(new PrintStream(outputStream)).print(histogram);
+        lines = outputStream.toString().split("\n");
+        // @formatter:off
+        expected = new String[] {
+            "TestHistogram <- c(2);",
+            "names(TestHistogram) <- c(\"1\");"
+        };
+        // @formatter:on
+        Assert.assertArrayEquals(expected, lines);
     }
 
     @Test
@@ -66,22 +81,29 @@
         histogram.add(new Integer(1));
         histogram.add(new Integer(2));
         histogram.add(new Integer(2));
-        histogram.print(new PrintStream(outputStream));
+        new DebugHistogramAsciiPrinter(new PrintStream(outputStream)).print(histogram);
         String[] lines = outputStream.toString().split("\n");
-        Assert.assertEquals(5, lines.length);
-        Assert.assertEquals("TestHistogram has 2 unique elements and 3 total elements:", lines[0]);
-        Assert.assertEquals(
-                        "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------",
-                        lines[1]);
-        Assert.assertEquals(
-                        "| 2                                                  | 2          | ==================================================================================================== |",
-                        lines[2]);
-        Assert.assertEquals(
-                        "| 1                                                  | 1          | ==================================================                                                   |",
-                        lines[3]);
-        Assert.assertEquals(
-                        "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------",
-                        lines[4]);
+        // @formatter:off
+        String[] expected = new String[] {
+            "TestHistogram has 2 unique elements and 3 total elements:",
+            "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------",
+            "| 2                                                  | 2          | ==================================================================================================== |",
+            "| 1                                                  | 1          | ==================================================                                                   |",
+            "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
+        };
+        // @formatter:on
+        Assert.assertArrayEquals(expected, lines);
+
+        outputStream.reset();
+        new DebugHistogramRPrinter(new PrintStream(outputStream)).print(histogram);
+        lines = outputStream.toString().split("\n");
+        // @formatter:off
+        expected = new String[] {
+            "TestHistogram <- c(2, 1);",
+            "names(TestHistogram) <- c(\"2\", \"1\");"
+        };
+        // @formatter:on
+        Assert.assertArrayEquals(expected, lines);
     }
 
     @Test
@@ -89,7 +111,7 @@
         DebugHistogram histogram = Debug.createHistogram("TestHistogram");
         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
         histogram.add("MyCustomValue");
-        histogram.print(new PrintStream(outputStream), Integer.MAX_VALUE, 10, 10);
+        new DebugHistogramAsciiPrinter(new PrintStream(outputStream), Integer.MAX_VALUE, 10, 10).print(histogram);
         String[] lines = outputStream.toString().split("\n");
         Assert.assertEquals(4, lines.length);
         Assert.assertEquals("TestHistogram has 1 unique elements and 1 total elements:", lines[0]);
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,24 +22,49 @@
  */
 package com.oracle.graal.debug;
 
-import com.oracle.graal.debug.internal.*;
+import static com.oracle.graal.debug.Debug.Initialization.*;
 
 import java.io.*;
 import java.util.*;
 import java.util.concurrent.*;
 
+import com.oracle.graal.debug.internal.*;
+
+/**
+ * Scope based debugging facility. This facility is {@link #isEnabled()} if assertions are enabled
+ * for the {@link Debug} class or the {@value Initialization#INITIALIZER_PROPERTY_NAME} system
+ * property is {@code "true"} when {@link Debug} is initialized.
+ */
 public class Debug {
 
-    private static boolean ENABLED = false;
+    /**
+     * Class to assist with initialization of {@link Debug}.
+     */
+    public static class Initialization {
+
+        public static final String INITIALIZER_PROPERTY_NAME = "graal.debug.enable";
 
-    public static void enable() {
-        ENABLED = true;
+        private static boolean initialized;
+
+        /**
+         * Determines if {@link Debug} has been initialized.
+         */
+        public static boolean isDebugInitialized() {
+            return initialized;
+        }
+
     }
 
-    public static void disable() {
-        ENABLED = false;
+    @SuppressWarnings("all")
+    private static boolean initialize() {
+        boolean assertionsEnabled = false;
+        assert assertionsEnabled = true;
+        Initialization.initialized = true;
+        return assertionsEnabled || Boolean.getBoolean(INITIALIZER_PROPERTY_NAME);
     }
 
+    private static final boolean ENABLED = initialize();
+
     public static boolean isEnabled() {
         return ENABLED;
     }
@@ -330,7 +355,7 @@
 
     public static DebugMetric metric(String name) {
         if (ENABLED) {
-            return new MetricImpl(name);
+            return new MetricImpl(name, true);
         } else {
             return VOID_METRIC;
         }
@@ -342,6 +367,9 @@
         }
     }
 
+    /**
+     * Creates an object for counting value frequencies.
+     */
     public static DebugHistogram createHistogram(String name) {
         return new DebugHistogramImpl(name);
     }
@@ -402,11 +430,19 @@
 
         public void add(long value) {
         }
+
+        public void setConditional(boolean flag) {
+            throw new InternalError("Cannot make void metric conditional");
+        }
+
+        public boolean isConditional() {
+            return false;
+        }
     };
 
     public static DebugTimer timer(String name) {
         if (ENABLED) {
-            return new TimerImpl(name);
+            return new TimerImpl(name, true);
         } else {
             return VOID_TIMER;
         }
@@ -417,5 +453,13 @@
         public TimerCloseable start() {
             return TimerImpl.VOID_CLOSEABLE;
         }
+
+        public void setConditional(boolean flag) {
+            throw new InternalError("Cannot make void timer conditional");
+        }
+
+        public boolean isConditional() {
+            return false;
+        }
     };
 }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugHistogram.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugHistogram.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,15 +22,75 @@
  */
 package com.oracle.graal.debug;
 
-import java.io.*;
+import java.util.*;
 
+/**
+ * Facility for recording value frequencies.
+ */
 public interface DebugHistogram {
 
+    /**
+     * Gets the name specified when this objected was {@linkplain Debug#createHistogram(String)
+     * created}.
+     */
     String getName();
 
+    /**
+     * Increments the count for a given value.
+     */
     void add(Object value);
 
-    void print(PrintStream os);
+    /**
+     * A value and a frequency. The ordering imposed by {@link #compareTo(CountedValue)} places
+     * values with higher frequencies first.
+     */
+    public class CountedValue implements Comparable<CountedValue> {
+
+        private int count;
+        private final Object value;
+
+        public CountedValue(int count, Object value) {
+            this.count = count;
+            this.value = value;
+        }
+
+        public int compareTo(CountedValue o) {
+            if (count < o.count) {
+                return 1;
+            } else if (count > o.count) {
+                return -1;
+            }
+            return 0;
+        }
 
-    void print(PrintStream os, int limit, int nameSize, int barSize);
+        @Override
+        public String toString() {
+            return count + " -> " + value;
+        }
+
+        public void inc() {
+            count++;
+        }
+
+        public int getCount() {
+            return count;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+    }
+
+    /**
+     * Gets a list of the counted values, sorted in descending order of frequency.
+     */
+    List<CountedValue> getValues();
+
+    /**
+     * Interface for a service that can render a visualization of a histogram.
+     */
+    public interface Printer {
+
+        void print(DebugHistogram histogram);
+    }
 }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugMetric.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugMetric.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,9 +22,32 @@
  */
 package com.oracle.graal.debug;
 
+/**
+ * A counter for some value of interest.
+ */
 public interface DebugMetric {
 
+    /**
+     * Adds 1 to this counter if metering is {@link Debug#isMeterEnabled() enabled} or this is an
+     * {@linkplain #isConditional() unconditional} metric.
+     */
     void increment();
 
+    /**
+     * Adds {@code value} to this counter if metering is {@link Debug#isMeterEnabled() enabled} or
+     * this is an {@linkplain #isConditional() unconditional} metric.
+     */
     void add(long value);
+
+    /**
+     * Sets a flag determining if this counter is only enabled if metering is
+     * {@link Debug#isMeterEnabled() enabled}.
+     */
+    void setConditional(boolean flag);
+
+    /**
+     * Determines if this counter is only enabled if metering is {@link Debug#isMeterEnabled()
+     * enabled}.
+     */
+    boolean isConditional();
 }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugTimer.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugTimer.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,7 +24,36 @@
 
 import com.oracle.graal.debug.internal.*;
 
+/**
+ * A timer for some activity of interest. A timer should be deployed using the try-with-resources
+ * pattern:
+ * 
+ * <pre>
+ * try (TimerCloseable a = timer.start()) {
+ *     // the code to time
+ * }
+ * </pre>
+ */
 public interface DebugTimer {
 
+    /**
+     * Starts this timer if timing is {@linkplain Debug#isTimeEnabled() enabled} or this is an
+     * {@linkplain #isConditional() unconditional} timer.
+     * 
+     * @return an object that must be closed once the activity has completed to add the elapsed time
+     *         since this call to the total for this timer
+     */
     TimerCloseable start();
+
+    /**
+     * Sets a flag determining if this timer is only enabled if metering is
+     * {@link Debug#isMeterEnabled() enabled}.
+     */
+    void setConditional(boolean flag);
+
+    /**
+     * Determines if this timer is only enabled if metering is {@link Debug#isMeterEnabled()
+     * enabled}.
+     */
+    boolean isConditional();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramAsciiPrinter.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,101 @@
+/*
+ * 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.debug.internal;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.DebugHistogram.*;
+
+/**
+ * Renders a textual representation of a histogram to a given print stream.
+ */
+public class DebugHistogramAsciiPrinter implements Printer {
+
+    public static final int NumberSize = 10;
+    public static final int DefaultNameSize = 50;
+    public static final int DefaultBarSize = 100;
+
+    private PrintStream os;
+    private int limit;
+    private int nameSize;
+    private int barSize;
+
+    public DebugHistogramAsciiPrinter(PrintStream os) {
+        this(os, Integer.MAX_VALUE, DefaultNameSize, DefaultBarSize);
+    }
+
+    /**
+     * @param os where to print
+     * @param limit limits printing to the {@code limit} most frequent values
+     * @param nameSize the width of the value names column
+     * @param barSize the width of the value frequency column
+     */
+    public DebugHistogramAsciiPrinter(PrintStream os, int limit, int nameSize, int barSize) {
+        this.os = os;
+        this.limit = limit;
+        this.nameSize = nameSize;
+        this.barSize = barSize;
+    }
+
+    public void print(DebugHistogram histogram) {
+        List<CountedValue> list = histogram.getValues();
+        if (list.isEmpty()) {
+            os.printf("%s is empty.\n", histogram.getName());
+            return;
+        }
+
+        // Sum up the total number of elements.
+        int total = 0;
+        for (CountedValue cv : list) {
+            total += cv.getCount();
+        }
+
+        // Print header.
+        os.printf("%s has %d unique elements and %d total elements:\n", histogram.getName(), list.size(), total);
+
+        int max = list.get(0).getCount();
+        final int lineSize = nameSize + NumberSize + barSize + 10;
+        printLine(os, '-', lineSize);
+        String formatString = "| %-" + nameSize + "s | %-" + NumberSize + "d | %-" + barSize + "s |\n";
+        for (int i = 0; i < list.size() && i < limit; ++i) {
+            CountedValue cv = list.get(i);
+            int value = cv.getCount();
+            char[] bar = new char[(int) (((double) value / (double) max) * barSize)];
+            Arrays.fill(bar, '=');
+            String objectString = String.valueOf(cv.getValue());
+            if (objectString.length() > nameSize) {
+                objectString = objectString.substring(0, nameSize - 3) + "...";
+            }
+            os.printf(formatString, objectString, value, new String(bar));
+        }
+        printLine(os, '-', lineSize);
+    }
+
+    private static void printLine(PrintStream printStream, char c, int lineSize) {
+        char[] charArr = new char[lineSize];
+        Arrays.fill(charArr, c);
+        printStream.printf("%s\n", new String(charArr));
+    }
+}
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramImpl.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramImpl.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,28 +22,25 @@
  */
 package com.oracle.graal.debug.internal;
 
-import java.io.*;
 import java.util.*;
 
 import com.oracle.graal.debug.*;
 
 public class DebugHistogramImpl implements DebugHistogram {
 
-    public static final int NumberSize = 10;
-    public static final int DefaultNameSize = 50;
-    public static final int DefaultBarSize = 100;
     private final String name;
-    private HashMap<Object, Integer> map = new HashMap<>();
+    private HashMap<Object, CountedValue> map = new HashMap<>();
 
     public DebugHistogramImpl(String name) {
         this.name = name;
     }
 
     public void add(Object value) {
-        if (!map.containsKey(value)) {
-            map.put(value, 1);
+        CountedValue cv = map.get(value);
+        if (cv == null) {
+            map.put(value, new CountedValue(1, value));
         } else {
-            map.put(value, map.get(value) + 1);
+            cv.inc();
         }
     }
 
@@ -52,59 +49,9 @@
         return name;
     }
 
-    @Override
-    public void print(PrintStream os) {
-        print(os, Integer.MAX_VALUE, DefaultNameSize, DefaultBarSize);
-    }
-
-    public void print(PrintStream os, int limit, int nameSize, int barSize) {
-
-        List<Object> list = new ArrayList<>(map.keySet());
-        if (list.size() == 0) {
-            // No elements in the histogram.
-            os.printf("%s is empty.\n", name);
-            return;
-        }
-
-        // Sort from highest to smallest.
-        Collections.sort(list, new Comparator<Object>() {
-
-            @Override
-            public int compare(Object o1, Object o2) {
-                return map.get(o2) - map.get(o1);
-            }
-        });
-
-        // Sum up the total number of elements.
-        int total = 0;
-        for (Object o : list) {
-            total += map.get(o);
-        }
-
-        // Print header.
-        os.printf("%s has %d unique elements and %d total elements:\n", name, list.size(), total);
-
-        int max = map.get(list.get(0));
-        final int lineSize = nameSize + NumberSize + barSize + 10;
-        printLine(os, '-', lineSize);
-        String formatString = "| %-" + nameSize + "s | %-" + NumberSize + "d | %-" + barSize + "s |\n";
-        for (int i = 0; i < list.size() && i < limit; ++i) {
-            Object o = list.get(i);
-            int value = map.get(o);
-            char[] bar = new char[(int) (((double) value / (double) max) * barSize)];
-            Arrays.fill(bar, '=');
-            String objectString = o.toString();
-            if (objectString.length() > nameSize) {
-                objectString = objectString.substring(0, nameSize - 3) + "...";
-            }
-            os.printf(formatString, objectString, value, new String(bar));
-        }
-        printLine(os, '-', lineSize);
-    }
-
-    private static void printLine(PrintStream printStream, char c, int lineSize) {
-        char[] charArr = new char[lineSize];
-        Arrays.fill(charArr, c);
-        printStream.printf("%s\n", new String(charArr));
+    public List<CountedValue> getValues() {
+        ArrayList<CountedValue> res = new ArrayList<>(map.values());
+        Collections.sort(res);
+        return res;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramRPrinter.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,81 @@
+/*
+ * 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.debug.internal;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.DebugHistogram.CountedValue;
+import com.oracle.graal.debug.DebugHistogram.Printer;
+
+/**
+ * Renders a histogram as an R script to a given print stream. The R script emitted for a histogram
+ * is a simple set of statements for defining a vector of named objects.
+ */
+public class DebugHistogramRPrinter implements Printer {
+
+    private PrintStream os;
+    private int limit;
+
+    public DebugHistogramRPrinter(PrintStream os) {
+        this(os, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @param os where to print
+     * @param limit limits printing to the {@code limit} most frequent values
+     */
+    public DebugHistogramRPrinter(PrintStream os, int limit) {
+        this.os = os;
+        this.limit = limit;
+    }
+
+    public void print(DebugHistogram histogram) {
+        List<CountedValue> list = histogram.getValues();
+        if (list.isEmpty()) {
+            return;
+        }
+
+        String var = histogram.getName().replace('-', '.').replace(' ', '_');
+        os.print(var + " <- c(");
+        for (int i = 0; i < list.size() && i < limit; ++i) {
+            CountedValue cv = list.get(i);
+            if (i != 0) {
+                os.print(", ");
+            }
+            os.print(cv.getCount());
+        }
+        os.println(");");
+
+        os.print("names(" + var + ") <- c(");
+        for (int i = 0; i < list.size() && i < limit; ++i) {
+            CountedValue cv = list.get(i);
+            if (i != 0) {
+                os.print(", ");
+            }
+            os.print("\"" + cv.getValue() + "\"");
+        }
+        os.println(");");
+    }
+}
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Wed Oct 02 13:26:31 2013 +0200
@@ -92,7 +92,6 @@
     private static ThreadLocal<DebugScope> instanceTL = new ThreadLocal<>();
     private static ThreadLocal<DebugConfig> configTL = new ThreadLocal<>();
     private static ThreadLocal<Throwable> lastExceptionThrownTL = new ThreadLocal<>();
-    private static DebugTimer scopeTime = Debug.timer("ScopeTime");
 
     private final DebugScope parent;
     private IndentImpl lastUsedIndent;
@@ -210,6 +209,9 @@
             for (DebugDumpHandler dumpHandler : config.dumpHandlers()) {
                 dumpHandler.dump(object, message);
             }
+        } else {
+            PrintStream out = System.out;
+            out.println("Forced dump ignored because debugging is disabled - use -G:Dump=xxx option");
         }
     }
 
@@ -239,7 +241,7 @@
         }
         instanceTL.set(newChild);
         newChild.updateFlags();
-        try (TimerCloseable a = scopeTime.start()) {
+        try {
             return executeScope(runnable, callable);
         } finally {
             newChild.context = null;
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugValue.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugValue.java	Wed Oct 02 13:26:31 2013 +0200
@@ -30,10 +30,12 @@
 
     private final String name;
     private int index;
+    private boolean conditional;
 
-    protected DebugValue(String name) {
+    protected DebugValue(String name, boolean conditional) {
         this.name = name;
         this.index = -1;
+        this.conditional = conditional;
     }
 
     protected long getCurrentValue() {
@@ -46,6 +48,14 @@
         DebugScope.getInstance().setCurrentValue(index, l);
     }
 
+    public void setConditional(boolean flag) {
+        conditional = flag;
+    }
+
+    public boolean isConditional() {
+        return conditional;
+    }
+
     private void ensureInitialized() {
         if (index == -1) {
             index = KeyRegistry.register(this);
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/MetricImpl.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/MetricImpl.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,8 +26,8 @@
 
 public final class MetricImpl extends DebugValue implements DebugMetric {
 
-    public MetricImpl(String name) {
-        super(name);
+    public MetricImpl(String name, boolean conditional) {
+        super(name, conditional);
     }
 
     public void increment() {
@@ -35,7 +35,7 @@
     }
 
     public void add(long value) {
-        if (Debug.isMeterEnabled()) {
+        if (!isConditional() || Debug.isMeterEnabled()) {
             super.addToCurrentValue(value);
         }
     }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/TimerCloseable.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/TimerCloseable.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,6 +22,12 @@
  */
 package com.oracle.graal.debug.internal;
 
+import com.oracle.graal.debug.*;
+
+/**
+ * An object returned by {@link DebugTimer#start()} that when closed, stops the associated timer and
+ * adds the elapsed time since {@code start()} to the total for the timer.
+ */
 public interface TimerCloseable extends AutoCloseable {
 
     void close();
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/TimerImpl.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/TimerImpl.java	Wed Oct 02 13:26:31 2013 +0200
@@ -37,59 +37,78 @@
         }
     };
 
-    private ThreadLocal<Long> valueToSubstract = new ThreadLocal<>();
+    /**
+     * Records the most recent active timer.
+     */
+    private static ThreadLocal<AbstractTimer> currentTimer = new ThreadLocal<>();
+
+    private final DebugValue flat;
 
-    public TimerImpl(String name) {
-        super(name);
+    public TimerImpl(String name, boolean conditional) {
+        super(name + "_Accm", conditional);
+        this.flat = new DebugValue(name + "_Flat", conditional) {
+
+            @Override
+            public String toString(long value) {
+                return valueToString(value);
+            }
+        };
     }
 
     @Override
     public TimerCloseable start() {
-        if (Debug.isTimeEnabled()) {
+        if (!isConditional() || Debug.isTimeEnabled()) {
             long startTime;
             if (threadMXBean.isCurrentThreadCpuTimeSupported()) {
                 startTime = threadMXBean.getCurrentThreadCpuTime();
             } else {
                 startTime = System.nanoTime();
             }
-            if (valueToSubstract.get() == null) {
-                valueToSubstract.set(0L);
-            }
-            long previousValueToSubstract = valueToSubstract.get();
+
             AbstractTimer result;
             if (threadMXBean.isCurrentThreadCpuTimeSupported()) {
-                result = new CpuTimeTimer(startTime, previousValueToSubstract);
+                result = new CpuTimeTimer(startTime);
             } else {
-                result = new SystemNanosTimer(startTime, previousValueToSubstract);
+                result = new SystemNanosTimer(startTime);
             }
-            valueToSubstract.set(0L);
+            currentTimer.set(result);
             return result;
         } else {
             return VOID_CLOSEABLE;
         }
     }
 
+    public static String valueToString(long value) {
+        return String.format("%d.%d ms", value / 1000000, (value / 100000) % 10);
+    }
+
     @Override
     public String toString(long value) {
-        return String.format("%d.%d ms", value / 1000000, (value / 100000) % 10);
+        return valueToString(value);
     }
 
     private abstract class AbstractTimer implements TimerCloseable {
 
+        private final AbstractTimer parent;
         private final long startTime;
-        private final long previousValueToSubstract;
+        private long nestedTimeToSubtract;
 
-        private AbstractTimer(long startTime, long previousValueToSubstract) {
+        private AbstractTimer(long startTime) {
+            this.parent = currentTimer.get();
             this.startTime = startTime;
-            this.previousValueToSubstract = previousValueToSubstract;
         }
 
         @Override
         public void close() {
-            long timeSpan = currentTime() - startTime;
-            long oldValueToSubstract = valueToSubstract.get();
-            valueToSubstract.set(timeSpan + previousValueToSubstract);
-            TimerImpl.this.addToCurrentValue(timeSpan - oldValueToSubstract);
+            long endTime = currentTime();
+            long timeSpan = endTime - startTime;
+            if (parent != null) {
+                parent.nestedTimeToSubtract += timeSpan;
+            }
+            currentTimer.set(parent);
+            long flatTime = timeSpan - nestedTimeToSubtract;
+            TimerImpl.this.addToCurrentValue(timeSpan);
+            flat.addToCurrentValue(flatTime);
         }
 
         protected abstract long currentTime();
@@ -97,8 +116,8 @@
 
     private final class SystemNanosTimer extends AbstractTimer {
 
-        public SystemNanosTimer(long startTime, long previousValueToSubstract) {
-            super(startTime, previousValueToSubstract);
+        public SystemNanosTimer(long startTime) {
+            super(startTime);
         }
 
         @Override
@@ -109,8 +128,8 @@
 
     private final class CpuTimeTimer extends AbstractTimer {
 
-        public CpuTimeTimer(long startTime, long previousValueToSubstract) {
-            super(startTime, previousValueToSubstract);
+        public CpuTimeTimer(long startTime) {
+            super(startTime);
         }
 
         @Override
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -32,7 +32,7 @@
 
 public class TypedNodeIteratorTest {
 
-    private static class TestNode extends Node implements Node.IterableNodeType, TestNodeInterface {
+    private static class TestNode extends Node implements IterableNodeType, TestNodeInterface {
 
         private final String name;
 
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest2.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest2.java	Wed Oct 02 13:26:31 2013 +0200
@@ -43,7 +43,7 @@
         }
     }
 
-    private static class NodeB extends NodeA implements Node.IterableNodeType {
+    private static class NodeB extends NodeA implements IterableNodeType {
 
         public NodeB(String name) {
             super(name);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,7 +25,6 @@
 import java.util.*;
 
 import com.oracle.graal.graph.GraphEvent.NodeEvent;
-import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.graph.iterators.*;
 
@@ -57,8 +56,8 @@
     private int deletedNodeCount;
     private GraphEventLog eventLog;
 
-    NodeChangedListener inputChanged;
-    NodeChangedListener usagesDroppedZero;
+    NodeChangedListener inputChangedListener;
+    NodeChangedListener usagesDroppedToZeroListener;
     private final HashMap<CacheEntry, Node> cachedNodes = new HashMap<>();
 
     private static final class CacheEntry {
@@ -66,6 +65,8 @@
         private final Node node;
 
         public CacheEntry(Node node) {
+            assert node.getNodeClass().valueNumberable();
+            assert node.getNodeClass().isLeafNode();
             this.node = node;
         }
 
@@ -82,8 +83,8 @@
             if (obj instanceof CacheEntry) {
                 CacheEntry other = (CacheEntry) obj;
                 NodeClass nodeClass = node.getNodeClass();
-                if (other.node.getNodeClass() == nodeClass) {
-                    return nodeClass.valueNumberable() && nodeClass.valueEqual(node, other.node) && nodeClass.edgesEqual(node, other.node);
+                if (other.node.getClass() == node.getClass()) {
+                    return nodeClass.valueEqual(node, other.node);
                 }
             }
             return false;
@@ -156,7 +157,7 @@
     int usageModCount(Node node) {
         int id = extractOriginalNodeId(node);
         if (id >= 0 && id < nodeUsageModCounts.length) {
-            return nodeUsageModCounts[node.id];
+            return nodeUsageModCounts[id];
         }
         return 0;
     }
@@ -187,8 +188,7 @@
      */
     public Graph copy(String newName) {
         Graph copy = new Graph(newName);
-        Map<Node, Node> emptyMap = Collections.emptyMap();
-        copy.addDuplicates(getNodes(), emptyMap);
+        copy.addDuplicates(getNodes(), this, this.getNodeCount(), (Map<Node, Node>) null);
         return copy;
     }
 
@@ -223,6 +223,24 @@
      * @return the node which was added to the graph
      */
     public <T extends Node> T add(T node) {
+        if (node.getNodeClass().valueNumberable()) {
+            throw new IllegalStateException("Using add for value numberable node. Consider using either unique or addWithoutUnique.");
+        }
+        return addHelper(node);
+    }
+
+    public <T extends Node> T addWithoutUnique(T node) {
+        return addHelper(node);
+    }
+
+    public <T extends Node> T addOrUnique(T node) {
+        if (node.getNodeClass().valueNumberable()) {
+            return uniqueHelper(node);
+        }
+        return add(node);
+    }
+
+    private <T extends Node> T addHelper(T node) {
         node.initialize(this);
         return node;
     }
@@ -232,24 +250,54 @@
         void nodeChanged(Node node);
     }
 
-    public void trackInputChange(NodeChangedListener inputChangedListener) {
-        assert this.inputChanged == null;
-        this.inputChanged = inputChangedListener;
+    private static class ChainedNodeChangedListener implements NodeChangedListener {
+
+        NodeChangedListener head;
+        NodeChangedListener next;
+
+        ChainedNodeChangedListener(NodeChangedListener head, NodeChangedListener next) {
+            this.head = head;
+            this.next = next;
+        }
+
+        public void nodeChanged(Node node) {
+            head.nodeChanged(node);
+            next.nodeChanged(node);
+        }
+    }
+
+    public void trackInputChange(NodeChangedListener listener) {
+        if (inputChangedListener == null) {
+            inputChangedListener = listener;
+        } else {
+            inputChangedListener = new ChainedNodeChangedListener(listener, inputChangedListener);
+        }
     }
 
     public void stopTrackingInputChange() {
-        assert inputChanged != null;
-        inputChanged = null;
+        assert inputChangedListener != null;
+        if (inputChangedListener instanceof ChainedNodeChangedListener) {
+            inputChangedListener = ((ChainedNodeChangedListener) inputChangedListener).next;
+        } else {
+            inputChangedListener = null;
+        }
     }
 
-    public void trackUsagesDroppedZero(NodeChangedListener usagesDroppedZeroListener) {
-        assert this.usagesDroppedZero == null;
-        this.usagesDroppedZero = usagesDroppedZeroListener;
+    public void trackUsagesDroppedZero(NodeChangedListener listener) {
+        if (usagesDroppedToZeroListener == null) {
+            usagesDroppedToZeroListener = listener;
+        } else {
+            usagesDroppedToZeroListener = new ChainedNodeChangedListener(listener, usagesDroppedToZeroListener);
+        }
     }
 
     public void stopTrackingUsagesDroppedZero() {
-        assert usagesDroppedZero != null;
-        usagesDroppedZero = null;
+        assert usagesDroppedToZeroListener != null;
+        if (usagesDroppedToZeroListener instanceof ChainedNodeChangedListener) {
+            usagesDroppedToZeroListener = ((ChainedNodeChangedListener) usagesDroppedToZeroListener).next;
+        } else {
+            usagesDroppedToZeroListener = null;
+        }
     }
 
     /**
@@ -261,53 +309,76 @@
      * @return the node which was added to the graph or a <i>similar</i> which was already in the
      *         graph.
      */
-    @SuppressWarnings("unchecked")
     public <T extends Node & ValueNumberable> T unique(T node) {
         assert checkValueNumberable(node);
+        return uniqueHelper(node);
+    }
 
-        for (Node input : node.inputs()) {
-            if (input != null) {
-                for (Node usage : input.usages()) {
-                    if (usage != node && node.getNodeClass().valueEqual(node, usage) && node.getNodeClass().edgesEqual(node, usage)) {
-                        return (T) usage;
-                    }
-                }
-                return add(node);
+    @SuppressWarnings("unchecked")
+    <T extends Node> T uniqueHelper(T node) {
+        assert node.getNodeClass().valueNumberable();
+        Node other = this.findDuplicate(node);
+        if (other != null) {
+            return (T) other;
+        } else {
+            Node result = addHelper(node);
+            if (node.getNodeClass().isLeafNode()) {
+                putNodeIntoCache(result);
             }
-        }
-        Node cachedNode = cachedNodes.get(new CacheEntry(node));
-        if (cachedNode != null && cachedNode.isAlive()) {
-            return (T) cachedNode;
-        } else {
-            Node result = add(node);
-            cachedNodes.put(new CacheEntry(node), result);
             return (T) result;
         }
     }
 
+    void putNodeIntoCache(Node node) {
+        assert node.graph() == this || node.graph() == null;
+        assert node.getNodeClass().valueNumberable();
+        assert node.getNodeClass().isLeafNode() : node.getClass();
+        cachedNodes.put(new CacheEntry(node), node);
+    }
+
+    Node findNodeInCache(Node node) {
+        CacheEntry key = new CacheEntry(node);
+        Node result = cachedNodes.get(key);
+        if (result != null && result.isDeleted()) {
+            cachedNodes.remove(key);
+            return null;
+        }
+        return result;
+    }
+
     public Node findDuplicate(Node node) {
-        if (node.getNodeClass().valueNumberable()) {
+        NodeClass nodeClass = node.getNodeClass();
+        assert nodeClass.valueNumberable();
+        if (nodeClass.isLeafNode()) {
+            Node cachedNode = findNodeInCache(node);
+            if (cachedNode != null) {
+                return cachedNode;
+            } else {
+                return null;
+            }
+        } else {
+
+            int minCount = Integer.MAX_VALUE;
+            Node minCountNode = null;
             for (Node input : node.inputs()) {
                 if (input != null) {
-                    for (Node usage : input.usages()) {
-                        if (usage != node && node.getNodeClass().valueEqual(node, usage) && node.getNodeClass().edgesEqual(node, usage)) {
-                            return usage;
-                        }
+                    int estimate = input.getUsageCountUpperBound();
+                    if (estimate == 0) {
+                        return null;
+                    } else if (estimate < minCount) {
+                        minCount = estimate;
+                        minCountNode = input;
                     }
-                    return null;
                 }
             }
-        }
-        CacheEntry key = new CacheEntry(node);
-        Node cachedNode = cachedNodes.get(key);
-        if (cachedNode != null) {
-            if (!cachedNode.isAlive()) {
-                cachedNodes.remove(key);
+            if (minCountNode != null) {
+                for (Node usage : minCountNode.usages()) {
+                    if (usage != node && nodeClass == usage.getNodeClass() && nodeClass.valueEqual(node, usage) && nodeClass.edgesEqual(node, usage)) {
+                        return usage;
+                    }
+                }
                 return null;
             }
-            return cachedNode != node ? cachedNode : null;
-        } else {
-            cachedNodes.put(key, node);
             return null;
         }
     }
@@ -319,6 +390,10 @@
         return true;
     }
 
+    public boolean isNew(int mark, Node node) {
+        return node.id >= mark;
+    }
+
     /**
      * Gets a mark that can be used with {@link #getNewNodes(int)}.
      */
@@ -518,7 +593,7 @@
      * {@code type}.
      * 
      * @param type the type of node to return
-     * @return an {@link Iterable} providing all the matching nodes.
+     * @return an {@link Iterable} providing all the matching nodes
      */
     public <T extends Node & IterableNodeType> NodeIterable<T> getNodes(final Class<T> type) {
         final NodeClass nodeClass = NodeClass.get(type);
@@ -671,14 +746,14 @@
      * @param replacementsMap the replacement map (can be null if no replacement is to be performed)
      * @return a map which associates the original nodes from {@code nodes} to their duplicates
      */
-    public Map<Node, Node> addDuplicates(Iterable<Node> newNodes, Map<Node, Node> replacementsMap) {
+    public Map<Node, Node> addDuplicates(Iterable<Node> newNodes, final Graph oldGraph, int estimatedNodeCount, Map<Node, Node> replacementsMap) {
         DuplicationReplacement replacements;
         if (replacementsMap == null) {
             replacements = null;
         } else {
             replacements = new MapReplacement(replacementsMap);
         }
-        return addDuplicates(newNodes, replacements);
+        return addDuplicates(newNodes, oldGraph, estimatedNodeCount, replacements);
     }
 
     public interface DuplicationReplacement {
@@ -702,19 +777,8 @@
 
     }
 
-    private static final DuplicationReplacement NO_REPLACEMENT = new DuplicationReplacement() {
-
-        @Override
-        public Node replacement(Node original) {
-            return original;
-        }
-    };
-
     @SuppressWarnings("all")
-    public Map<Node, Node> addDuplicates(Iterable<Node> newNodes, DuplicationReplacement replacements) {
-        if (replacements == null) {
-            replacements = NO_REPLACEMENT;
-        }
-        return NodeClass.addGraphDuplicate(this, newNodes, replacements);
+    public Map<Node, Node> addDuplicates(Iterable<Node> newNodes, final Graph oldGraph, int estimatedNodeCount, DuplicationReplacement replacements) {
+        return NodeClass.addGraphDuplicate(this, oldGraph, estimatedNodeCount, newNodes, replacements);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/IterableNodeType.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,32 @@
+/*
+ * 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.graph;
+
+/**
+ * A marker for a node type supporting {@linkplain Graph#getNodes(Class) fast iteration} of its
+ * instances in a graph. The support for fast iteration comes with a memory cost (e.g., extra data
+ * structures {@link Graph}) so only node types for which fast iteration provides a compilation
+ * performance benefit should implement this interface.
+ */
+public interface IterableNodeType {
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Wed Oct 02 13:26:31 2013 +0200
@@ -104,6 +104,9 @@
         /**
          * Determines if the stamp of the instantiated intrinsic node has its stamp set from the
          * return type of the annotated method.
+         * <p>
+         * When it is set to true, the stamp that is passed in to the constructor of ValueNode is
+         * ignored and can therefore safely be {@code null}.
          */
         boolean setStampFromReturnType() default false;
     }
@@ -111,9 +114,6 @@
     public interface ValueNumberable {
     }
 
-    public interface IterableNodeType {
-    }
-
     private Graph graph;
     int id;
 
@@ -240,6 +240,16 @@
         }
     }
 
+    int getUsageCountUpperBound() {
+        if (usage0 == null) {
+            return 0;
+        }
+        if (usage1 == null) {
+            return 1;
+        }
+        return 2 + extraUsages.length;
+    }
+
     /**
      * Gets the list of nodes that use this node (e.g., as an input).
      */
@@ -423,15 +433,15 @@
                 assert assertTrue(result, "not found in usages, old input: %s", oldInput);
             }
             if (newInput != null) {
-                NodeChangedListener inputChanged = graph.inputChanged;
-                if (inputChanged != null) {
-                    inputChanged.nodeChanged(this);
+                NodeChangedListener listener = graph.inputChangedListener;
+                if (listener != null) {
+                    listener.nodeChanged(this);
                 }
                 newInput.addUsage(this);
             } else if (oldInput != null && oldInput.usages().isEmpty()) {
-                NodeChangedListener nodeChangedListener = graph.usagesDroppedZero;
-                if (nodeChangedListener != null) {
-                    nodeChangedListener.nodeChanged(oldInput);
+                NodeChangedListener listener = graph.usagesDroppedToZeroListener;
+                if (listener != null) {
+                    listener.nodeChanged(oldInput);
                 }
             }
         }
@@ -449,7 +459,7 @@
                 oldSuccessor.predecessor = null;
             }
             if (newSuccessor != null) {
-                assert assertTrue(newSuccessor.predecessor == null, "unexpected non-null predecessor in new successor (%s): %s", newSuccessor, newSuccessor.predecessor);
+                assert assertTrue(newSuccessor.predecessor == null, "unexpected non-null predecessor in new successor (%s): %s, this=%s", newSuccessor, newSuccessor.predecessor, this);
                 newSuccessor.predecessor = this;
             }
         }
@@ -485,9 +495,9 @@
             boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
             assert assertTrue(result, "not found in inputs, usage: %s", usage);
             if (other != null) {
-                NodeChangedListener inputChanged = graph.inputChanged;
-                if (inputChanged != null) {
-                    inputChanged.nodeChanged(usage);
+                NodeChangedListener listener = graph.inputChangedListener;
+                if (listener != null) {
+                    listener.nodeChanged(usage);
                 }
                 other.addUsage(usage);
             }
@@ -532,9 +542,9 @@
         for (Node input : inputs()) {
             removeThisFromUsages(input);
             if (input.usages().isEmpty()) {
-                NodeChangedListener nodeChangedListener = graph.usagesDroppedZero;
-                if (nodeChangedListener != null) {
-                    nodeChangedListener.nodeChanged(input);
+                NodeChangedListener listener = graph.usagesDroppedToZeroListener;
+                if (listener != null) {
+                    listener.nodeChanged(input);
                 }
             }
         }
@@ -584,15 +594,31 @@
         return newNode;
     }
 
-    public Node clone(Graph into) {
+    static int count = 0;
+
+    public final Node clone(Graph into) {
+        return clone(into, true);
+    }
+
+    final Node clone(Graph into, boolean clearInputsAndSuccessors) {
+        NodeClass nodeClass = getNodeClass();
+        if (nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
+            Node otherNode = into.findNodeInCache(this);
+            if (otherNode != null) {
+                return otherNode;
+            }
+        }
+
         Node newNode = null;
         try {
             newNode = (Node) this.clone();
         } catch (CloneNotSupportedException e) {
             throw new GraalInternalError(e).addContext(this);
         }
-        getNodeClass().clearInputs(newNode);
-        getNodeClass().clearSuccessors(newNode);
+        if (clearInputsAndSuccessors) {
+            nodeClass.clearInputs(newNode);
+            nodeClass.clearSuccessors(newNode);
+        }
         newNode.graph = into;
         newNode.typeCacheNext = null;
         newNode.id = INITIAL_ID;
@@ -601,9 +627,17 @@
         newNode.usage1 = null;
         newNode.extraUsages = NO_NODES;
         newNode.predecessor = null;
+
+        if (nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
+            into.putNodeIntoCache(newNode);
+        }
+        newNode.afterClone(this);
         return newNode;
     }
 
+    protected void afterClone(@SuppressWarnings("unused") Node other) {
+    }
+
     public boolean verify() {
         assertTrue(isAlive(), "cannot verify inactive nodes (id=%d)", id);
         assertTrue(graph() != null, "null graph");
@@ -779,6 +813,7 @@
 
         boolean neighborsAlternate = ((flags & FormattableFlags.LEFT_JUSTIFY) == FormattableFlags.LEFT_JUSTIFY);
         int neighborsFlags = (neighborsAlternate ? FormattableFlags.ALTERNATE | FormattableFlags.LEFT_JUSTIFY : 0);
+        NodeClass nodeClass = getNodeClass();
         if (width > 0) {
             if (this.predecessor != null) {
                 formatter.format(" pred={");
@@ -789,10 +824,10 @@
             NodeClassIterator inputIter = inputs().iterator();
             while (inputIter.hasNext()) {
                 Position position = inputIter.nextPosition();
-                Node input = getNodeClass().get(this, position);
+                Node input = nodeClass.get(this, position);
                 if (input != null) {
                     formatter.format(" ");
-                    formatter.format(getNodeClass().getName(position));
+                    formatter.format(nodeClass.getName(position));
                     formatter.format("={");
                     input.formatTo(formatter, neighborsFlags, width - 1, 0);
                     formatter.format("}");
@@ -817,10 +852,10 @@
             NodeClassIterator succIter = successors().iterator();
             while (succIter.hasNext()) {
                 Position position = succIter.nextPosition();
-                Node successor = getNodeClass().get(this, position);
+                Node successor = nodeClass.get(this, position);
                 if (successor != null) {
                     formatter.format(" ");
-                    formatter.format(getNodeClass().getName(position));
+                    formatter.format(nodeClass.getName(position));
                     formatter.format("={");
                     successor.formatTo(formatter, neighborsFlags, 0, precision - 1);
                     formatter.format("}");
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,12 +26,11 @@
 
 import java.lang.reflect.*;
 import java.util.*;
-import java.util.Map.Entry;
 import java.util.concurrent.*;
 
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
 import com.oracle.graal.graph.Node.Input;
-import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.graph.Node.Successor;
 import com.oracle.graal.graph.Node.Verbosity;
 
@@ -139,12 +138,16 @@
     private final long[] successorOffsets;
     private final Class<?>[] dataTypes;
     private final boolean canGVN;
+    private final boolean isLeafNode;
     private final int startGVNNumber;
     private final String shortName;
     private final String nameTemplate;
     private final int iterableId;
     private int[] iterableIds;
 
+    private static final DebugMetric ITERABLE_NODE_TYPES = Debug.metric("IterableNodeTypes");
+    private final DebugMetric nodeIterableCount;
+
     private NodeClass(Class<?> clazz) {
         super(clazz);
         assert NODE_CLASS.isAssignableFrom(clazz);
@@ -185,14 +188,15 @@
         }
         this.nameTemplate = newNameTemplate == null ? newShortName : newNameTemplate;
         this.shortName = newShortName;
-        if (Node.IterableNodeType.class.isAssignableFrom(clazz)) {
+        if (IterableNodeType.class.isAssignableFrom(clazz)) {
+            ITERABLE_NODE_TYPES.increment();
             this.iterableId = nextIterableId++;
             List<NodeClass> existingClasses = new LinkedList<>();
             for (FieldIntrospection nodeClass : allClasses.values()) {
                 if (clazz.isAssignableFrom(nodeClass.clazz)) {
                     existingClasses.add((NodeClass) nodeClass);
                 }
-                if (nodeClass.clazz.isAssignableFrom(clazz) && Node.IterableNodeType.class.isAssignableFrom(nodeClass.clazz)) {
+                if (nodeClass.clazz.isAssignableFrom(clazz) && IterableNodeType.class.isAssignableFrom(nodeClass.clazz)) {
                     NodeClass superNodeClass = (NodeClass) nodeClass;
                     superNodeClass.iterableIds = Arrays.copyOf(superNodeClass.iterableIds, superNodeClass.iterableIds.length + 1);
                     superNodeClass.iterableIds[superNodeClass.iterableIds.length - 1] = this.iterableId;
@@ -209,6 +213,9 @@
             this.iterableId = NOT_ITERABLE;
             this.iterableIds = null;
         }
+
+        isLeafNode = (this.inputOffsets.length == 0 && this.successorOffsets.length == 0);
+        nodeIterableCount = Debug.metric("NodeIterable_" + shortName);
     }
 
     @Override
@@ -236,6 +243,7 @@
     }
 
     public int[] iterableIds() {
+        nodeIterableCount.increment();
         return iterableIds;
     }
 
@@ -247,6 +255,10 @@
         return canGVN;
     }
 
+    public boolean isLeafNode() {
+        return isLeafNode;
+    }
+
     public static int cacheSize() {
         return nextIterableId;
     }
@@ -417,6 +429,7 @@
      */
     public static final class NodeClassIterator implements Iterator<Node> {
 
+        private final NodeClass nodeClass;
         private final Node node;
         private final int modCount;
         private final int directCount;
@@ -434,6 +447,7 @@
          */
         private NodeClassIterator(Node node, long[] offsets, int directCount) {
             this.node = node;
+            this.nodeClass = node.getNodeClass();
             this.modCount = MODIFICATION_COUNTS_ENABLED ? node.modCount() : 0;
             this.offsets = offsets;
             this.directCount = directCount;
@@ -500,9 +514,9 @@
         public Position nextPosition() {
             try {
                 if (index < directCount) {
-                    return new Position(offsets == node.getNodeClass().inputOffsets, index, NOT_ITERABLE);
+                    return new Position(offsets == nodeClass.inputOffsets, index, NOT_ITERABLE);
                 } else {
-                    return new Position(offsets == node.getNodeClass().inputOffsets, index, subIndex);
+                    return new Position(offsets == nodeClass.inputOffsets, index, subIndex);
                 }
             } finally {
                 forward();
@@ -581,7 +595,7 @@
     }
 
     public boolean valueEqual(Node a, Node b) {
-        if (!canGVN || a.getNodeClass() != b.getNodeClass()) {
+        if (!canGVN || a.getClass() != b.getClass()) {
             return a == b;
         }
         for (int i = 0; i < dataOffsets.length; ++i) {
@@ -659,6 +673,84 @@
         return fieldNames.get(pos.input ? inputOffsets[pos.index] : successorOffsets[pos.index]);
     }
 
+    void updateInputSuccInPlace(Node node, InplaceUpdateClosure duplicationReplacement) {
+        int index = 0;
+        while (index < directInputCount) {
+            Node input = getNode(node, inputOffsets[index]);
+            if (input != null) {
+                Node newInput = duplicationReplacement.replacement(input, true);
+                node.updateUsages(null, newInput);
+                putNode(node, inputOffsets[index], newInput);
+            }
+            index++;
+        }
+
+        if (index < inputOffsets.length) {
+            updateInputLists(node, duplicationReplacement, index);
+        }
+
+        index = 0;
+        while (index < directSuccessorCount) {
+            Node successor = getNode(node, successorOffsets[index]);
+            if (successor != null) {
+                Node newSucc = duplicationReplacement.replacement(successor, false);
+                node.updatePredecessor(null, newSucc);
+                putNode(node, successorOffsets[index], newSucc);
+            }
+            index++;
+        }
+
+        if (index < successorOffsets.length) {
+            updateSuccLists(node, duplicationReplacement, index);
+        }
+    }
+
+    private void updateInputLists(Node node, InplaceUpdateClosure duplicationReplacement, int startIndex) {
+        int index = startIndex;
+        while (index < inputOffsets.length) {
+            NodeList<Node> list = getNodeList(node, inputOffsets[index]);
+            putNodeList(node, inputOffsets[index], updateInputListCopy(list, node, duplicationReplacement));
+            assert list != null : clazz;
+            index++;
+        }
+    }
+
+    private void updateSuccLists(Node node, InplaceUpdateClosure duplicationReplacement, int startIndex) {
+        int index = startIndex;
+        while (index < successorOffsets.length) {
+            NodeList<Node> list = getNodeList(node, successorOffsets[index]);
+            putNodeList(node, successorOffsets[index], updateSuccListCopy(list, node, duplicationReplacement));
+            assert list != null : clazz;
+            index++;
+        }
+    }
+
+    private static NodeInputList<Node> updateInputListCopy(NodeList<Node> list, Node node, InplaceUpdateClosure duplicationReplacement) {
+        int size = list.size();
+        NodeInputList<Node> result = new NodeInputList<>(node, size);
+        for (int i = 0; i < list.count(); ++i) {
+            Node oldNode = list.get(i);
+            if (oldNode != null) {
+                Node newNode = duplicationReplacement.replacement(oldNode, true);
+                result.set(i, newNode);
+            }
+        }
+        return result;
+    }
+
+    private static NodeSuccessorList<Node> updateSuccListCopy(NodeList<Node> list, Node node, InplaceUpdateClosure duplicationReplacement) {
+        int size = list.size();
+        NodeSuccessorList<Node> result = new NodeSuccessorList<>(node, size);
+        for (int i = 0; i < list.count(); ++i) {
+            Node oldNode = list.get(i);
+            if (oldNode != null) {
+                Node newNode = duplicationReplacement.replacement(oldNode, false);
+                result.set(i, newNode);
+            }
+        }
+        return result;
+    }
+
     public void set(Node node, Position pos, Node x) {
         long offset = pos.input ? inputOffsets[pos.index] : successorOffsets[pos.index];
         if (pos.subIndex == NOT_ITERABLE) {
@@ -955,78 +1047,113 @@
         return nameTemplate;
     }
 
-    static Map<Node, Node> addGraphDuplicate(Graph graph, Iterable<Node> nodes, DuplicationReplacement replacements) {
-        Map<Node, Node> newNodes = new IdentityHashMap<>();
-        Map<Node, Node> replacementsMap = new IdentityHashMap<>();
-        // create node duplicates
+    interface InplaceUpdateClosure {
+
+        Node replacement(Node node, boolean isInput);
+    }
+
+    static Map<Node, Node> addGraphDuplicate(final Graph graph, final Graph oldGraph, int estimatedNodeCount, Iterable<Node> nodes, final DuplicationReplacement replacements) {
+        final Map<Node, Node> newNodes = (estimatedNodeCount > (oldGraph.getNodeCount() + oldGraph.getDeletedNodeCount() >> 4)) ? new NodeNodeMap(oldGraph) : new IdentityHashMap<Node, Node>();
+        createNodeDuplicates(graph, nodes, replacements, newNodes);
+
+        InplaceUpdateClosure replacementClosure = new InplaceUpdateClosure() {
+
+            public Node replacement(Node node, boolean isInput) {
+                Node target = newNodes.get(node);
+                if (target == null) {
+                    Node replacement = node;
+                    if (replacements != null) {
+                        replacement = replacements.replacement(node);
+                    }
+                    if (replacement != node) {
+                        target = replacement;
+                    } else if (node.graph() == graph && isInput) {
+                        // patch to the outer world
+                        target = node;
+                    }
+
+                }
+                return target;
+            }
+
+        };
+
+        // re-wire inputs
+        for (Node oldNode : nodes) {
+            Node node = newNodes.get(oldNode);
+            NodeClass oldNodeClass = oldNode.getNodeClass();
+            NodeClass nodeClass = node.getNodeClass();
+            if (replacements == null || replacements.replacement(oldNode) == oldNode) {
+                nodeClass.updateInputSuccInPlace(node, replacementClosure);
+            } else {
+                transferValuesDifferentNodeClass(graph, replacements, newNodes, oldNode, node, oldNodeClass, nodeClass);
+            }
+        }
+
+        return newNodes;
+    }
+
+    private static void createNodeDuplicates(final Graph graph, Iterable<Node> nodes, final DuplicationReplacement replacements, final Map<Node, Node> newNodes) {
         for (Node node : nodes) {
             if (node != null) {
                 assert !node.isDeleted() : "trying to duplicate deleted node: " + node;
-                Node replacement = replacements.replacement(node);
+                Node replacement = node;
+                if (replacements != null) {
+                    replacement = replacements.replacement(node);
+                }
                 if (replacement != node) {
                     assert replacement != null;
                     newNodes.put(node, replacement);
                 } else {
-                    Node newNode = node.clone(graph);
+                    Node newNode = node.clone(graph, false);
+                    assert newNode.usages().count() == 0 || newNode.inputs().count() == 0;
                     assert newNode.getClass() == node.getClass();
                     newNodes.put(node, newNode);
                 }
             }
         }
-        // re-wire inputs
-        for (Entry<Node, Node> entry : newNodes.entrySet()) {
-            Node oldNode = entry.getKey();
-            Node node = entry.getValue();
-            for (NodeClassIterator iter = oldNode.inputs().iterator(); iter.hasNext();) {
-                Position pos = iter.nextPosition();
-                if (!pos.isValidFor(node, oldNode)) {
-                    continue;
+    }
+
+    private static void transferValuesDifferentNodeClass(final Graph graph, final DuplicationReplacement replacements, final Map<Node, Node> newNodes, Node oldNode, Node node, NodeClass oldNodeClass,
+                    NodeClass nodeClass) {
+        for (NodeClassIterator iter = oldNode.inputs().iterator(); iter.hasNext();) {
+            Position pos = iter.nextPosition();
+            if (!nodeClass.isValid(pos, oldNodeClass)) {
+                continue;
+            }
+            Node input = oldNodeClass.get(oldNode, pos);
+            Node target = newNodes.get(input);
+            if (target == null) {
+                Node replacement = input;
+                if (replacements != null) {
+                    replacement = replacements.replacement(input);
                 }
-                Node input = oldNode.getNodeClass().get(oldNode, pos);
-                Node target = newNodes.get(input);
-                if (target == null) {
-                    target = replacementsMap.get(input);
-                    if (target == null) {
-                        Node replacement = replacements.replacement(input);
-                        if (replacement != input) {
-                            replacementsMap.put(input, replacement);
-                            assert isAssignable(node.getNodeClass().fieldTypes.get(node.getNodeClass().inputOffsets[pos.index]), replacement);
-                            target = replacement;
-                        } else if (input.graph() == graph) { // patch to the outer world
-                            target = input;
-                        }
-                    }
+                if (replacement != input) {
+                    assert isAssignable(nodeClass.fieldTypes.get(nodeClass.inputOffsets[pos.index]), replacement);
+                    target = replacement;
+                } else if (input.graph() == graph) { // patch to the outer world
+                    target = input;
                 }
-                node.getNodeClass().set(node, pos, target);
             }
+            nodeClass.set(node, pos, target);
         }
 
-        // re-wire successors
-        for (Entry<Node, Node> entry : newNodes.entrySet()) {
-            Node oldNode = entry.getKey();
-            Node node = entry.getValue();
-            for (NodeClassIterator iter = oldNode.successors().iterator(); iter.hasNext();) {
-                Position pos = iter.nextPosition();
-                if (!pos.isValidFor(node, oldNode)) {
-                    continue;
+        for (NodeClassIterator iter = oldNode.successors().iterator(); iter.hasNext();) {
+            Position pos = iter.nextPosition();
+            if (!nodeClass.isValid(pos, oldNodeClass)) {
+                continue;
+            }
+            Node succ = oldNodeClass.get(oldNode, pos);
+            Node target = newNodes.get(succ);
+            if (target == null) {
+                Node replacement = replacements.replacement(succ);
+                if (replacement != succ) {
+                    assert isAssignable(nodeClass.fieldTypes.get(node.getNodeClass().successorOffsets[pos.index]), replacement);
+                    target = replacement;
                 }
-                Node succ = oldNode.getNodeClass().get(oldNode, pos);
-                Node target = newNodes.get(succ);
-                if (target == null) {
-                    target = replacementsMap.get(succ);
-                    if (target == null) {
-                        Node replacement = replacements.replacement(succ);
-                        if (replacement != succ) {
-                            replacementsMap.put(succ, replacement);
-                            assert isAssignable(node.getNodeClass().fieldTypes.get(node.getNodeClass().successorOffsets[pos.index]), replacement);
-                            target = replacement;
-                        }
-                    }
-                }
-                node.getNodeClass().set(node, pos, target);
             }
+            nodeClass.set(node, pos, target);
         }
-        return newNodes;
     }
 
     private static boolean isAssignable(Class<?> fieldType, Node replacement) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,11 +26,11 @@
 import java.util.*;
 import java.util.Map.Entry;
 
-public final class NodeMap<T> {
+public class NodeMap<T> {
 
     private final Graph graph;
     private final boolean autogrow;
-    private Object[] values;
+    protected Object[] values;
 
     public NodeMap(Graph graph) {
         this(graph, false);
@@ -54,6 +54,29 @@
         return (T) values[node.id()];
     }
 
+    public boolean isEmpty() {
+        return !entries().iterator().hasNext();
+    }
+
+    public boolean containsKey(Object key) {
+        if (key instanceof Node) {
+            Node node = (Node) key;
+            if (node.graph() == graph()) {
+                return get(node) != null;
+            }
+        }
+        return false;
+    }
+
+    public boolean containsValue(Object value) {
+        for (Object o : values) {
+            if (o == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public Graph graph() {
         return graph;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeNodeMap.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011, 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.graph;
+
+import java.util.*;
+
+public final class NodeNodeMap extends NodeMap<Node> implements Map<Node, Node> {
+
+    public NodeNodeMap(Graph graph) {
+        super(graph, true);
+    }
+
+    public NodeNodeMap(NodeNodeMap copyFrom) {
+        super(copyFrom);
+    }
+
+    public Node get(Object key) {
+        return super.get((Node) key);
+    }
+
+    public Node put(Node key, Node value) {
+        Node oldValue = super.get(key);
+        super.set(key, value);
+        return oldValue;
+    }
+
+    public Node remove(Object key) {
+        throw new UnsupportedOperationException("Cannot remove keys from this map");
+    }
+
+    public void putAll(Map<? extends Node, ? extends Node> m) {
+        for (Entry<? extends Node, ? extends Node> entry : m.entrySet()) {
+            put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    public Set<Node> keySet() {
+        throw new UnsupportedOperationException("Cannot get key set from this map");
+    }
+
+    public Collection<Node> values() {
+        ArrayList<Node> result = new ArrayList<>(this.size());
+        for (int i = 0; i < values.length; ++i) {
+            Object v = values[i];
+            if (v != null) {
+                result.add((Node) v);
+            }
+        }
+        return result;
+    }
+
+    public Set<java.util.Map.Entry<Node, Node>> entrySet() {
+        throw new UnsupportedOperationException("Cannot get entry set for this map");
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,12 +23,8 @@
 package com.oracle.graal.hotspot.amd64;
 
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
@@ -36,21 +32,14 @@
 @Opcode("DEOPT")
 final class AMD64DeoptimizeOp extends AMD64LIRInstruction {
 
-    private DeoptimizationAction action;
-    private DeoptimizationReason reason;
     @State private LIRFrameState info;
 
-    AMD64DeoptimizeOp(DeoptimizationAction action, DeoptimizationReason reason, LIRFrameState info) {
-        this.action = action;
-        this.reason = reason;
+    AMD64DeoptimizeOp(LIRFrameState info) {
         this.info = info;
     }
 
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-        HotSpotGraalRuntime runtime = graalRuntime();
-        Register thread = runtime.getRuntime().threadRegister();
-        masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason));
         AMD64Call.directCall(tasm, masm, tasm.runtime.lookupForeignCall(UNCOMMON_TRAP), null, false, info);
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Wed Oct 02 13:26:31 2013 +0200
@@ -63,6 +63,11 @@
     }
 
     @Override
+    public boolean shouldAllocateRegisters() {
+        return true;
+    }
+
+    @Override
     public FrameMap newFrameMap() {
         return new AMD64FrameMap(runtime(), target, runtime().lookupRegisterConfig());
     }
@@ -231,11 +236,10 @@
         FrameMap frameMap = tasm.frameMap;
         RegisterConfig regConfig = frameMap.registerConfig;
         HotSpotVMConfig config = runtime().config;
-        Label unverifiedStub = installedCodeOwner == null || isStatic(installedCodeOwner.getModifiers()) ? null : new Label();
+        Label verifiedStub = new Label();
 
         // Emit the prefix
-
-        if (unverifiedStub != null) {
+        if (installedCodeOwner != null && !isStatic(installedCodeOwner.getModifiers())) {
             tasm.recordMark(Marks.MARK_UNVERIFIED_ENTRY);
             CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, new JavaType[]{runtime().lookupJavaType(Object.class)}, target, false);
             Register inlineCacheKlass = rax; // see definition of IC_Klass in
@@ -252,11 +256,12 @@
             } else {
                 asm.cmpq(inlineCacheKlass, src);
             }
-            asm.jcc(ConditionFlag.NotEqual, unverifiedStub);
+            AMD64Call.directConditionalJmp(tasm, asm, runtime().lookupForeignCall(IC_MISS_HANDLER), ConditionFlag.NotEqual);
         }
 
         asm.align(config.codeEntryAlignment);
         tasm.recordMark(Marks.MARK_OSR_ENTRY);
+        asm.bind(verifiedStub);
         tasm.recordMark(Marks.MARK_VERIFIED_ENTRY);
 
         // Emit code for the LIR
@@ -273,10 +278,5 @@
             // it has no calls that can cause such "return" entries
             assert !frameMap.accessesCallerFrame() : lirGen.getGraph();
         }
-
-        if (unverifiedStub != null) {
-            asm.bind(unverifiedStub);
-            AMD64Call.directJmp(tasm, asm, runtime().lookupForeignCall(IC_MISS_HANDLER));
-        }
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,12 +23,8 @@
 package com.oracle.graal.hotspot.amd64;
 
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
@@ -39,21 +35,9 @@
 @Opcode("DEOPT_CALLER")
 final class AMD64HotSpotDeoptimizeCallerOp extends AMD64HotSpotEpilogueOp {
 
-    private final DeoptimizationAction action;
-    private final DeoptimizationReason reason;
-
-    AMD64HotSpotDeoptimizeCallerOp(DeoptimizationAction action, DeoptimizationReason reason) {
-        this.action = action;
-        this.reason = reason;
-    }
-
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
         leaveFrameAndRestoreRbp(tasm, masm);
-
-        HotSpotGraalRuntime runtime = graalRuntime();
-        Register thread = runtime.getRuntime().threadRegister();
-        masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason));
         AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupForeignCall(UNCOMMON_TRAP));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,6 +25,7 @@
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -36,6 +37,7 @@
 import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.CompareAndSwapCompressedOp;
@@ -176,7 +178,7 @@
 
     @Override
     protected void emitReturn(Value input) {
-        append(new AMD64HotSpotReturnOp(input));
+        append(new AMD64HotSpotReturnOp(input, getStub() != null));
     }
 
     @Override
@@ -242,7 +244,7 @@
         Variable result;
 
         if (linkage.canDeoptimize()) {
-            assert info != null;
+            assert info != null || stub != null;
             append(new AMD64HotSpotCRuntimeCallPrologueOp());
             result = super.emitForeignCall(linkage, info, args);
             append(new AMD64HotSpotCRuntimeCallEpilogueOp());
@@ -287,7 +289,7 @@
     @Override
     public void visitSafepointNode(SafepointNode i) {
         LIRFrameState info = state(i);
-        append(new AMD64SafepointOp(info, runtime().config, this));
+        append(new AMD64HotSpotSafepointOp(info, runtime().config, this));
     }
 
     @SuppressWarnings("hiding")
@@ -361,14 +363,29 @@
         append(new AMD64HotSpotUnwindOp(exceptionParameter));
     }
 
+    private void moveDeoptimizationActionAndReasonToThread(Value actionAndReason) {
+        int pendingDeoptimizationOffset = graalRuntime().getConfig().pendingDeoptimizationOffset;
+        RegisterValue thread = runtime().threadRegister().asValue(HotSpotGraalRuntime.wordKind());
+        AMD64AddressValue pendingDeoptAddress = new AMD64AddressValue(actionAndReason.getKind(), thread, pendingDeoptimizationOffset);
+        if (actionAndReason instanceof Constant && !runtime.needsDataPatch((Constant) actionAndReason)) {
+            Constant constantActionAndReason = (Constant) actionAndReason;
+            assert !runtime.needsDataPatch(constantActionAndReason);
+            append(new StoreConstantOp(constantActionAndReason.getKind(), pendingDeoptAddress, constantActionAndReason, null));
+        } else {
+            append(new StoreOp(actionAndReason.getKind(), pendingDeoptAddress, load(actionAndReason), null));
+        }
+    }
+
     @Override
-    public void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting) {
-        append(new AMD64DeoptimizeOp(action, deopting.getDeoptimizationReason(), state(deopting)));
+    public void emitDeoptimize(Value actionAndReason, DeoptimizingNode deopting) {
+        moveDeoptimizationActionAndReasonToThread(actionAndReason);
+        append(new AMD64DeoptimizeOp(state(deopting)));
     }
 
     @Override
     public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
-        append(new AMD64HotSpotDeoptimizeCallerOp(action, reason));
+        moveDeoptimizationActionAndReasonToThread(runtime.encodeDeoptActionAndReason(action, reason));
+        append(new AMD64HotSpotDeoptimizeCallerOp());
     }
 
     @Override
@@ -522,4 +539,13 @@
         append(new CondMoveOp(result, Condition.EQ, load(Constant.TRUE), Constant.FALSE));
         setResult(node, result);
     }
+
+    @Override
+    public void visitInfopointNode(InfopointNode i) {
+        if (i.getState() != null && i.getState().bci == FrameState.AFTER_BCI) {
+            Debug.log("Ignoring InfopointNode for AFTER_BCI");
+        } else {
+            super.visitInfopointNode(i);
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,10 +22,16 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+import static com.oracle.graal.phases.GraalOptions.*;
 
+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.graph.*;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
@@ -36,14 +42,31 @@
 final class AMD64HotSpotReturnOp extends AMD64HotSpotEpilogueOp {
 
     @Use({REG, ILLEGAL}) protected Value value;
+    private final boolean isStub;
 
-    AMD64HotSpotReturnOp(Value value) {
+    AMD64HotSpotReturnOp(Value value, boolean isStub) {
         this.value = value;
+        this.isStub = isStub;
     }
 
+    private static Register findPollOnReturnScratchRegister() {
+        RegisterConfig config = HotSpotGraalRuntime.graalRuntime().getRuntime().lookupRegisterConfig();
+        for (Register r : config.getAllocatableRegisters(Kind.Long)) {
+            if (r != config.getReturnRegister(Kind.Long) && r != AMD64.rbp) {
+                return r;
+            }
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    private static final Register scratchForSafepointOnReturn = findPollOnReturnScratchRegister();
+
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
         leaveFrameAndRestoreRbp(tasm, masm);
+        if (!isStub && (tasm.frameContext != null || !OptEliminateSafepoints.getValue())) {
+            AMD64HotSpotSafepointOp.emitCode(tasm, masm, graalRuntime().getConfig(), true, null, scratchForSafepointOnReturn);
+        }
         masm.ret(0);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,79 @@
+/*
+ * 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.hotspot.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+import static com.oracle.graal.hotspot.bridge.Marks.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Emits a safepoint poll.
+ */
+@Opcode("SAFEPOINT")
+public class AMD64HotSpotSafepointOp extends AMD64LIRInstruction {
+
+    @State protected LIRFrameState state;
+    @Temp({OperandFlag.REG}) private AllocatableValue temp;
+
+    private final HotSpotVMConfig config;
+
+    public AMD64HotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, LIRGeneratorTool tool) {
+        this.state = state;
+        this.config = config;
+        temp = tool.newVariable(tool.target().wordKind);
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler asm) {
+        RegisterValue scratch = (RegisterValue) temp;
+        emitCode(tasm, asm, config, false, state, scratch.getRegister());
+    }
+
+    public static void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler asm, HotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) {
+        final int pos = asm.codeBuffer.position();
+        if (config.isPollingPageFar) {
+            asm.movq(scratch, config.safepointPollingAddress);
+            tasm.recordMark(atReturn ? MARK_POLL_RETURN_FAR : MARK_POLL_FAR);
+            if (state != null) {
+                tasm.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+            }
+            asm.movq(scratch, new AMD64Address(scratch));
+        } else {
+            tasm.recordMark(atReturn ? MARK_POLL_RETURN_NEAR : MARK_POLL_NEAR);
+            if (state != null) {
+                tasm.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+            }
+            // The C++ code transforms the polling page offset into an RIP displacement
+            // to the real address at that offset in the polling page.
+            asm.movq(scratch, new AMD64Address(rip, 0));
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * 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.hotspot.amd64;
-
-import static com.oracle.graal.amd64.AMD64.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.bridge.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * Emits a safepoint poll.
- */
-@Opcode("SAFEPOINT")
-public class AMD64SafepointOp extends AMD64LIRInstruction {
-
-    @State protected LIRFrameState state;
-    @Temp({OperandFlag.REG}) private AllocatableValue temp;
-
-    private final HotSpotVMConfig config;
-
-    public AMD64SafepointOp(LIRFrameState state, HotSpotVMConfig config, LIRGeneratorTool tool) {
-        this.state = state;
-        this.config = config;
-        temp = tool.newVariable(tool.target().wordKind);
-    }
-
-    @Override
-    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler asm) {
-        final int pos = asm.codeBuffer.position();
-        RegisterValue scratch = (RegisterValue) temp;
-        if (config.isPollingPageFar) {
-            asm.movq(scratch.getRegister(), config.safepointPollingAddress);
-            tasm.recordMark(Marks.MARK_POLL_FAR);
-            tasm.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
-            asm.movq(scratch.getRegister(), new AMD64Address(scratch.getRegister()));
-        } else {
-            tasm.recordMark(Marks.MARK_POLL_NEAR);
-            tasm.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
-            // The C++ code transforms the polling page offset into an RIP displacement
-            // to the real address at that offset in the polling page.
-            asm.movq(scratch.getRegister(), new AMD64Address(rip, 0));
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,73 @@
+/*
+ * 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.hotspot.ptx;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * HotSpot PTX specific backend.
+ */
+public class PTXHotSpotBackend extends HotSpotBackend {
+
+    public PTXHotSpotBackend(HotSpotRuntime runtime, TargetDescription target) {
+        super(runtime, target);
+    }
+
+    @Override
+    public boolean shouldAllocateRegisters() {
+        throw new InternalError("NYI");
+    }
+
+    @Override
+    public FrameMap newFrameMap() {
+        throw new InternalError("NYI");
+    }
+
+    @Override
+    public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) {
+        throw new InternalError("NYI");
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod installedCodeOwner) {
+        throw new InternalError("NYI");
+    }
+
+    @Override
+    protected AbstractAssembler createAssembler(FrameMap frameMap) {
+        throw new InternalError("NYI");
+    }
+
+    @Override
+    public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir) {
+        throw new InternalError("NYI");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotGraalRuntime.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,82 @@
+/*
+ * 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.hotspot.ptx;
+
+import com.oracle.graal.ptx.*;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+
+/**
+ * PTX specific implementation of {@link HotSpotGraalRuntime}.
+ */
+public class PTXHotSpotGraalRuntime extends HotSpotGraalRuntime {
+
+    protected PTXHotSpotGraalRuntime() {
+    }
+
+    /**
+     * Called from C++ code to retrieve the singleton instance, creating it first if necessary.
+     */
+    public static HotSpotGraalRuntime makeInstance() {
+        HotSpotGraalRuntime graalRuntime = graalRuntime();
+        if (graalRuntime == null) {
+            HotSpotGraalRuntimeFactory factory = findFactory("PTX");
+            if (factory != null) {
+                graalRuntime = factory.createRuntime();
+            } else {
+                graalRuntime = new PTXHotSpotGraalRuntime();
+            }
+            graalRuntime.completeInitialization();
+        }
+        return graalRuntime;
+    }
+
+    protected Architecture createArchitecture() {
+        return new PTX();
+    }
+
+    @Override
+    protected TargetDescription createTarget() {
+        final int stackFrameAlignment = 16;
+        final int implicitNullCheckLimit = 4096;
+        final boolean inlineObjects = true;
+        return new TargetDescription(createArchitecture(), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
+    }
+
+    @Override
+    protected HotSpotBackend createBackend() {
+        return new PTXHotSpotBackend(getRuntime(), getTarget());
+    }
+
+    @Override
+    protected HotSpotRuntime createRuntime() {
+        return new PTXHotSpotRuntime(config, this);
+    }
+
+    @Override
+    protected Value[] getNativeABICallerSaveRegisters() {
+        throw new InternalError("NYI");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotRegisterConfig.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,159 @@
+/*
+ * 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.hotspot.ptx;
+
+import static com.oracle.graal.ptx.PTX.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.graph.*;
+
+public class PTXHotSpotRegisterConfig implements RegisterConfig {
+
+    private final Register[] allocatable;
+
+    @Override
+    public Register[] getAllocatableRegisters() {
+        return allocatable.clone();
+    }
+
+    @Override
+    public Register[] getAllocatableRegisters(PlatformKind kind) {
+        throw GraalInternalError.unimplemented("PTXHotSpotRegisterConfig.getAllocatableRegisters()");
+    }
+
+    @Override
+    public RegisterAttributes[] getAttributesMap() {
+        throw GraalInternalError.unimplemented("PTXHotSpotRegisterConfig.getAttributesMap()");
+    }
+
+    private final Register[] javaGeneralParameterRegisters;
+    private final Register[] nativeGeneralParameterRegisters;
+
+    private static Register[] initAllocatable() {
+        Register[] registers = new Register[] {
+            r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
+            r8,  r9,  r10, r11, r12, r13, r14, r15,
+        };
+
+        return registers;
+    }
+
+    public PTXHotSpotRegisterConfig() {
+        javaGeneralParameterRegisters = paramRegisters;
+        nativeGeneralParameterRegisters = gprRegisters;
+
+        allocatable = initAllocatable();
+    }
+
+    @Override
+    public Register[] getCallerSaveRegisters() {
+        // No caller save registers; return empty array
+        return new Register[]{};
+    }
+
+    @Override
+    public Register getRegisterForRole(int index) {
+        throw GraalInternalError.unimplemented("PTXHotSpotRegisterConfig.getRegisterForRole()");
+    }
+
+    @Override
+    public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) {
+        if (type == Type.NativeCall) {
+            return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly);
+        }
+        return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly);
+    }
+
+    @Override
+    public Register[] getCallingConventionRegisters(Type type, Kind kind) {
+        throw GraalInternalError.unimplemented("PTXHotSpotRegisterConfig.getRegisterForRole()");
+    }
+
+    private static CallingConvention callingConvention(@SuppressWarnings("unused") Register[] generalParameterRegisters,
+                                                JavaType returnType, JavaType[] parameterTypes,
+                                                Type type, TargetDescription target, boolean stackOnly) {
+
+        assert stackOnly == false;
+
+        int currentGeneral = 0;
+        int currentStackOffset = 0;
+
+        Kind returnKind = returnType == null ? Kind.Void : returnType.getKind();
+        AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : new Variable(returnKind, currentGeneral++);
+        AllocatableValue[] locations = new AllocatableValue[parameterTypes.length];
+
+        for (int i = 0; i < parameterTypes.length; i++) {
+            final Kind kind = parameterTypes[i].getKind();
+
+            switch (kind) {
+                case Byte:
+                case Boolean:
+                case Short:
+                case Char:
+                case Int:
+                case Long:
+                case Float:
+                case Double:
+                case Object:
+                    if (!stackOnly) {
+                        locations[i] = new Variable(kind, currentGeneral++);
+                    }
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+
+            if (locations[i] == null) {
+                locations[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, !type.out);
+                currentStackOffset += Math.max(target.arch.getSizeInBytes(kind), target.wordSize);
+            }
+        }
+
+        return new CallingConvention(currentStackOffset, returnLocation, locations);
+    }
+
+    @Override
+    public Register getReturnRegister(Kind kind) {
+        throw GraalInternalError.unimplemented("PTXHotSpotRegisterConfig.getRegisterForRole()");
+    }
+
+    @Override
+    public Register getFrameRegister() {
+        // No frame register
+        return null;
+    }
+
+    public CalleeSaveLayout getCalleeSaveLayout() {
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave:  " + Arrays.toString(getCallerSaveRegisters()) + "%n");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotRuntime.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,83 @@
+/*
+ * 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.hotspot.ptx;
+
+import static com.oracle.graal.ptx.PTX.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.calc.ConvertNode;
+
+public class PTXHotSpotRuntime extends HotSpotRuntime {
+
+    public PTXHotSpotRuntime(HotSpotVMConfig config, HotSpotGraalRuntime graalRuntime) {
+        super(config, graalRuntime);
+
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        if (n instanceof ConvertNode) {
+            // PTX has a cvt instruction that "takes a variety of
+            // operand types and sizes, as its job is to convert from
+            // nearly any data type to any other data type (and
+            // size)." [Section 6.2 of PTX ISA manual]
+            // So, there is no need to lower the operation.
+            return;
+        } else {
+            super.lower(n, tool);
+        }
+    }
+
+    @Override
+    public void registerReplacements(Replacements replacements) {
+        Debug.log("PTXHotSpotRuntime.registerReplacements unimplemented");
+    }
+
+    // PTX code does not use stack or stack pointer
+    @Override
+    public Register stackPointerRegister() {
+        return Register.None;
+    }
+
+    // PTX code does not have heap register
+    @Override
+    public Register heapBaseRegister() {
+        return Register.None;
+    }
+
+    // Thread register is %tid.
+    @Override
+    public Register threadRegister() {
+        return tid;
+    }
+
+    @Override
+    protected RegisterConfig createRegisterConfig() {
+        return new PTXHotSpotRegisterConfig();
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,39 +22,24 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
-import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.sparc.SPARC.*;
 
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.lir.asm.*;
 
 @Opcode("DEOPT")
 final class SPARCDeoptimizeOp extends SPARCLIRInstruction {
 
-    private DeoptimizationAction action;
-    private DeoptimizationReason reason;
     @State private LIRFrameState info;
 
-    SPARCDeoptimizeOp(DeoptimizationAction action, DeoptimizationReason reason, LIRFrameState info) {
-        this.action = action;
-        this.reason = reason;
+    SPARCDeoptimizeOp(LIRFrameState info) {
         this.info = info;
     }
 
     @Override
     public void emitCode(TargetMethodAssembler tasm, SPARCMacroAssembler masm) {
-        HotSpotGraalRuntime runtime = graalRuntime();
-        Register thread = runtime.getRuntime().threadRegister();
-        Register scratch = g3;
-        new Mov(tasm.runtime.encodeDeoptActionAndReason(action, reason), scratch).emit(masm);
-        new Stw(scratch, new SPARCAddress(thread, runtime.getConfig().pendingDeoptimizationOffset)).emit(masm);
         // TODO the patched call address looks odd (and is invalid) compared to other runtime calls:
 // 0xffffffff749bb5fc: call 0xffffffff415a720c ; {runtime_call}
 // [Exception Handler]
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Wed Oct 02 13:26:31 2013 +0200
@@ -60,6 +60,11 @@
     }
 
     @Override
+    public boolean shouldAllocateRegisters() {
+        return true;
+    }
+
+    @Override
     public FrameMap newFrameMap() {
         return new SPARCFrameMap(runtime(), target, runtime().lookupRegisterConfig());
     }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,18 +22,14 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.sparc.SPARC.*;
-import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.lir.asm.*;
 
 /**
  * Removes the current frame and tail calls the uncommon trap routine.
@@ -41,14 +37,6 @@
 @Opcode("DEOPT_CALLER")
 final class SPARCHotSpotDeoptimizeCallerOp extends SPARCHotSpotEpilogueOp {
 
-    private final DeoptimizationAction action;
-    private final DeoptimizationReason reason;
-
-    SPARCHotSpotDeoptimizeCallerOp(DeoptimizationAction action, DeoptimizationReason reason) {
-        this.action = action;
-        this.reason = reason;
-    }
-
     @Override
     public void emitCode(TargetMethodAssembler tasm, SPARCMacroAssembler masm) {
         leaveFrame(tasm);
@@ -58,14 +46,7 @@
 // final boolean isStub = true;
 // HotSpotFrameContext frameContext = backend.new HotSpotFrameContext(isStub);
 // frameContext.enter(tasm);
-
-        HotSpotGraalRuntime runtime = graalRuntime();
-        Register thread = runtime.getRuntime().threadRegister();
-
-        Register scratch = g5;
-        new Mov(tasm.runtime.encodeDeoptActionAndReason(action, reason), scratch).emit(masm);
-        new Stw(scratch, new SPARCAddress(thread, runtime.getConfig().pendingDeoptimizationOffset)).emit(masm);
-
+        Register scratch = g3;
         SPARCCall.indirectJmp(tasm, masm, scratch, tasm.runtime.lookupForeignCall(UNCOMMON_TRAP));
 
 // frameContext.leave(tasm);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,6 +24,7 @@
 
 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.sparc.SPARC.*;
 
 import java.lang.reflect.*;
@@ -39,7 +40,10 @@
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.lir.sparc.SPARCMove.*;
+import com.oracle.graal.lir.sparc.SPARCMove.CompareAndSwapOp;
+import com.oracle.graal.lir.sparc.SPARCMove.LoadOp;
+import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp;
+import com.oracle.graal.lir.sparc.SPARCMove.StoreOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
@@ -103,9 +107,14 @@
     }
 
     @Override
+    protected void emitReturn(Value input) {
+        append(new SPARCHotSpotReturnOp(input, getStub() != null));
+    }
+
+    @Override
     public void visitSafepointNode(SafepointNode i) {
         LIRFrameState info = state(i);
-        append(new SPARCSafepointOp(info, runtime().config, this));
+        append(new SPARCHotSpotSafepointOp(info, runtime().config, this));
     }
 
     @Override
@@ -175,14 +184,23 @@
         append(new SPARCHotSpotUnwindOp(exceptionParameter));
     }
 
+    private void moveDeoptimizationActionAndReasonToThread(Value actionAndReason) {
+        int pendingDeoptimizationOffset = graalRuntime().getConfig().pendingDeoptimizationOffset;
+        RegisterValue thread = runtime().threadRegister().asValue(HotSpotGraalRuntime.wordKind());
+        SPARCAddressValue pendingDeoptAddress = new SPARCAddressValue(actionAndReason.getKind(), thread, pendingDeoptimizationOffset);
+        append(new StoreOp(actionAndReason.getKind(), pendingDeoptAddress, emitMove(actionAndReason), null));
+    }
+
     @Override
-    public void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting) {
-        append(new SPARCDeoptimizeOp(action, deopting.getDeoptimizationReason(), state(deopting)));
+    public void emitDeoptimize(Value actionAndReason, DeoptimizingNode deopting) {
+        moveDeoptimizationActionAndReasonToThread(actionAndReason);
+        append(new SPARCDeoptimizeOp(state(deopting)));
     }
 
     @Override
     public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
-        append(new SPARCHotSpotDeoptimizeCallerOp(action, reason));
+        moveDeoptimizationActionAndReasonToThread(runtime.encodeDeoptActionAndReason(action, reason));
+        append(new SPARCHotSpotDeoptimizeCallerOp());
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotReturnOp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.hotspot.sparc;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+import static com.oracle.graal.phases.GraalOptions.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp;
+import com.oracle.graal.sparc.*;
+
+/**
+ * Returns from a function.
+ */
+@Opcode("RETURN")
+final class SPARCHotSpotReturnOp extends SPARCHotSpotEpilogueOp {
+
+    @Use({REG, ILLEGAL}) protected Value value;
+    private final boolean isStub;
+
+    SPARCHotSpotReturnOp(Value value, boolean isStub) {
+        this.value = value;
+        this.isStub = isStub;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, SPARCMacroAssembler masm) {
+        if (!isStub && (tasm.frameContext != null || !OptEliminateSafepoints.getValue())) {
+            // Using the same scratch register as LIR_Assembler::return_op
+            // in c1_LIRAssembler_sparc.cpp
+            SPARCHotSpotSafepointOp.emitCode(tasm, masm, graalRuntime().getConfig(), true, null, SPARC.l0);
+        }
+        ReturnOp.emitCodeHelper(tasm, masm);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2011, 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.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.hotspot.bridge.Marks.*;
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Emits a safepoint poll.
+ */
+@Opcode("SAFEPOINT")
+public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction {
+
+    @State protected LIRFrameState state;
+    @Temp({OperandFlag.REG}) private AllocatableValue temp;
+
+    private final HotSpotVMConfig config;
+
+    public SPARCHotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, LIRGeneratorTool tool) {
+        this.state = state;
+        this.config = config;
+        temp = tool.newVariable(tool.target().wordKind);
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, SPARCMacroAssembler masm) {
+        Register scratch = ((RegisterValue) temp).getRegister();
+        emitCode(tasm, masm, config, false, state, scratch);
+    }
+
+    public static void emitCode(TargetMethodAssembler tasm, SPARCMacroAssembler masm, HotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) {
+        final int pos = masm.codeBuffer.position();
+        new Setx(config.safepointPollingAddress, scratch).emit(masm);
+        assert !config.isPollingPageFar;
+        tasm.recordMark(atReturn ? MARK_POLL_RETURN_NEAR : MARK_POLL_NEAR);
+        if (state != null) {
+            tasm.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+        }
+        new Ldx(new SPARCAddress(scratch, 0), g0).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCSafepointOp.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2011, 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.sparc;
-
-import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
-import static com.oracle.graal.sparc.SPARC.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * Emits a safepoint poll.
- */
-@Opcode("SAFEPOINT")
-public class SPARCSafepointOp extends SPARCLIRInstruction {
-
-    @State protected LIRFrameState state;
-    @Temp({OperandFlag.REG}) private AllocatableValue temp;
-
-    private final HotSpotVMConfig config;
-
-    public SPARCSafepointOp(LIRFrameState state, HotSpotVMConfig config, LIRGeneratorTool tool) {
-        this.state = state;
-        this.config = config;
-        temp = tool.newVariable(tool.target().wordKind);
-    }
-
-    @Override
-    public void emitCode(TargetMethodAssembler tasm, SPARCMacroAssembler masm) {
-        final int pos = masm.codeBuffer.position();
-        Register scratch = ((RegisterValue) temp).getRegister();
-        new Setx(config.safepointPollingAddress, scratch).emit(masm);
-        tasm.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
-        new Ldx(new SPARCAddress(scratch, 0), g0).emit(masm);
-    }
-}
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -66,7 +66,7 @@
         assertEquals(1, result.getNodes().filter(ConstantNode.class).count());
         assertEquals(runtime.getTarget().wordKind, result.getNodes().filter(ConstantNode.class).first().kind());
         assertEquals(2, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes(ReadNode.class).count());
+        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     @Test
@@ -75,7 +75,7 @@
         assertEquals(1, result.getNodes().filter(ConstantNode.class).count());
         assertEquals(Kind.Object, result.getNodes().filter(ConstantNode.class).first().kind());
         assertEquals(0, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes(ReadNode.class).count());
+        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     public static Class getClassObject() {
@@ -92,7 +92,7 @@
         assertEquals(type.klass(), filter.first().asConstant());
 
         assertEquals(1, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes(ReadNode.class).count());
+        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     @Test
@@ -106,7 +106,7 @@
         assertEquals(AheadOfTimeCompilationTest.class, mirror);
 
         assertEquals(0, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes(ReadNode.class).count());
+        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     public static Class getPrimitiveClassObject() {
@@ -121,7 +121,7 @@
         assertEquals(runtime.getTarget().wordKind, filter.first().kind());
 
         assertEquals(2, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes(ReadNode.class).count());
+        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     @Test
@@ -134,7 +134,7 @@
         assertEquals(Integer.TYPE, mirror);
 
         assertEquals(0, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes(ReadNode.class).count());
+        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     public static String getStringObject() {
@@ -162,7 +162,7 @@
         assertEquals("test string", mirror);
 
         assertEquals(0, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes(ReadNode.class).count());
+        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     public static Boolean getBoxedBoolean() {
@@ -175,7 +175,7 @@
         StructuredGraph result = compile("getBoxedBoolean", true);
 
         assertEquals(2, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(1, result.getNodes(UnsafeCastNode.class).count());
+        assertEquals(1, result.getNodes(PiNode.class).count());
         assertEquals(1, result.getNodes().filter(ConstantNode.class).count());
         ConstantNode constant = result.getNodes().filter(ConstantNode.class).first();
         assertEquals(Kind.Long, constant.kind());
@@ -186,7 +186,7 @@
     public void testBoxedBoolean() {
         StructuredGraph result = compile("getBoxedBoolean", false);
         assertEquals(0, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes(UnsafeCastNode.class).count());
+        assertEquals(0, result.getNodes(PiNode.class).count());
         assertEquals(1, result.getNodes().filter(ConstantNode.class).count());
         ConstantNode constant = result.getNodes().filter(ConstantNode.class).first();
         assertEquals(Kind.Object, constant.kind());
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -60,30 +60,42 @@
     }
 
     @Test
-    public void testAESEncryptSubstitution() throws Exception {
+    public void testEncryptSubstitution() throws Exception {
         byte[] seed = {0x4, 0x7, 0x1, 0x1};
         SecureRandom random = new SecureRandom(seed);
         KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
+        KeyGenerator desKeyGen = KeyGenerator.getInstance("DESede");
         aesKeyGen.init(128, random);
+        desKeyGen.init(168, random);
         SecretKey aesKey = aesKeyGen.generateKey();
+        SecretKey desKey = desKeyGen.generateKey();
         byte[] input = readClassfile16(getClass());
 
-        ByteArrayOutputStream expected = new ByteArrayOutputStream();
-        expected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input));
-        expected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input));
+        ByteArrayOutputStream aesExpected = new ByteArrayOutputStream();
+        aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input));
+        aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input));
 
         if (compiledAndInstall("com.sun.crypto.provider.AESCrypt", "encryptBlock", "decryptBlock")) {
             ByteArrayOutputStream actual = new ByteArrayOutputStream();
             actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input));
             actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input));
-            Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+            Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray());
         }
 
+        ByteArrayOutputStream desExpected = new ByteArrayOutputStream();
+        desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding", input));
+        desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding", input));
+
         if (compiledAndInstall("com.sun.crypto.provider.CipherBlockChaining", "encrypt", "decrypt")) {
             ByteArrayOutputStream actual = new ByteArrayOutputStream();
             actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input));
             actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input));
-            Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+            Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray());
+
+            actual.reset();
+            actual.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding", input));
+            actual.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding", input));
+            Assert.assertArrayEquals(desExpected.toByteArray(), actual.toByteArray());
         }
     }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -35,11 +35,11 @@
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.phases.*;
-import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -249,10 +249,10 @@
                 StructuredGraph graph = parse(snippet);
                 HighTierContext highContext = new HighTierContext(runtime(), new Assumptions(false), replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
                 MidTierContext midContext = new MidTierContext(runtime(), new Assumptions(false), replacements, runtime().getTarget(), OptimisticOptimizations.ALL);
-                new InliningPhase(new InliningPhase.InlineEverythingPolicy()).apply(graph, highContext);
-                new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, highContext);
+                new InliningPhase(new InliningPhase.InlineEverythingPolicy(), new CanonicalizerPhase(true)).apply(graph, highContext);
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, highContext);
                 new GuardLoweringPhase().apply(graph, midContext);
-                new LoweringPhase(LoweringType.AFTER_GUARDS).apply(graph, midContext);
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, midContext);
                 new WriteBarrierAdditionPhase().apply(graph);
                 Debug.dump(graph, "After Write Barrier Addition");
 
@@ -263,7 +263,7 @@
                     barriers = graph.getNodes(SerialWriteBarrier.class).count();
                 }
                 Assert.assertEquals(expectedBarriers, barriers);
-                for (WriteNode write : graph.getNodes(WriteNode.class)) {
+                for (WriteNode write : graph.getNodes().filter(WriteNode.class)) {
                     if (useG1GC()) {
                         if (write.getBarrierType() != BarrierType.NONE) {
                             Assert.assertEquals(1, write.successors().count());
@@ -278,7 +278,7 @@
                     }
                 }
 
-                for (ReadNode read : graph.getNodes(ReadNode.class)) {
+                for (ReadNode read : graph.getNodes().filter(ReadNode.class)) {
                     if (read.getBarrierType() != BarrierType.NONE) {
                         if (read.location() instanceof ConstantLocationNode) {
                             Assert.assertEquals(referentOffset(), ((ConstantLocationNode) (read.location())).getDisplacement());
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -33,10 +33,10 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.graph.*;
@@ -633,14 +633,14 @@
             public AssertionError call() {
                 final StructuredGraph graph = parse(snippet);
                 HighTierContext highTierContext = new HighTierContext(runtime(), new Assumptions(false), replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-                new InliningPhase().apply(graph, highTierContext);
+                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
 
                 MidTierContext midTierContext = new MidTierContext(runtime(), new Assumptions(false), replacements, runtime().getTarget(), OptimisticOptimizations.ALL);
 
-                new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, highTierContext);
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
                 new GuardLoweringPhase().apply(graph, midTierContext);
-                new SafepointInsertionPhase().apply(graph);
-                new LoweringPhase(LoweringType.AFTER_GUARDS).apply(graph, highTierContext);
+                new LoopSafepointInsertionPhase().apply(graph);
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
 
                 new WriteBarrierAdditionPhase().apply(graph);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Oct 02 13:26:31 2013 +0200
@@ -128,8 +128,7 @@
             CompilationStatistics stats = CompilationStatistics.create(method, entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI);
             final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed();
             if (printCompilation) {
-                TTY.println(String.format("%-6d Graal %-70s %-45s %-50s %s...", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature(),
-                                entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") "));
+                TTY.println(getMethodDescription() + "...");
             }
             if (HotSpotPrintCompilation.getValue()) {
                 printCompilation();
@@ -161,7 +160,10 @@
                 });
             } finally {
                 filter.remove();
-                if (printCompilation) {
+                final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed();
+                if (printAfterCompilation) {
+                    TTY.println(getMethodDescription() + String.format(" | %4dms %5dB", System.currentTimeMillis() - start, (result != null ? result.getTargetCodeSize() : -1)));
+                } else if (printCompilation) {
                     TTY.println(String.format("%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, (result != null ? result.getTargetCodeSize() : -1)));
                 }
             }
@@ -193,6 +195,11 @@
         }
     }
 
+    private String getMethodDescription() {
+        return String.format("%-6d Graal %-70s %-45s %-50s %s", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature().getMethodDescriptor(),
+                        entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") ");
+    }
+
     /**
      * Print a HotSpot-style compilation message to the console.
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerThread.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerThread.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.compiler.GraalDebugConfig.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.io.*;
@@ -52,7 +51,7 @@
     @Override
     public void run() {
         GraalDebugConfig hotspotDebugConfig = null;
-        if (DebugEnabled.getValue()) {
+        if (Debug.isEnabled()) {
             PrintStream log = graalRuntime().getVMToCompiler().log();
             DebugEnvironment.initialize(log);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Wed Oct 02 13:26:31 2013 +0200
@@ -61,7 +61,7 @@
     }
 
     @Override
-    protected LIRFrameState newLIRFrameState(short reason, LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) {
-        return new HotSpotLIRFrameState(frame, virtualObjectsArray, exceptionEdge, reason);
+    protected LIRFrameState newLIRFrameState(LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) {
+        return new HotSpotLIRFrameState(frame, virtualObjectsArray, exceptionEdge);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRFrameState.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRFrameState.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,8 +34,8 @@
  */
 class HotSpotLIRFrameState extends LIRFrameState {
 
-    public HotSpotLIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge, short deoptimizationReason) {
-        super(topFrame, virtualObjects, exceptionEdge, deoptimizationReason);
+    public HotSpotLIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge) {
+        super(topFrame, virtualObjects, exceptionEdge);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,6 +23,7 @@
 
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
 import static java.nio.file.Files.*;
 
 import java.io.*;
@@ -30,6 +31,7 @@
 import java.nio.file.*;
 import java.util.*;
 
+import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.logging.*;
 import com.oracle.graal.options.*;
 
@@ -174,6 +176,19 @@
     }
 
     /**
+     * Called from VM code once all Graal command line options have been processed by
+     * {@link #setOption(String)}.
+     * 
+     * @param ciTime the value of the CITime HotSpot VM option
+     */
+    public static void finalizeOptions(boolean ciTime) {
+        if (areDebugScopePatternsEnabled() || ciTime) {
+            assert !Debug.Initialization.isDebugInitialized();
+            System.setProperty(Debug.Initialization.INITIALIZER_PROPERTY_NAME, "true");
+        }
+    }
+
+    /**
      * Wraps some given text to one or more lines of a given maximum width.
      * 
      * @param text text to wrap
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed Oct 02 13:26:31 2013 +0200
@@ -38,7 +38,7 @@
 
     private static final long serialVersionUID = -4744897993263044184L;
 
-    private final HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean();
+    private static final HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean();
 
     HotSpotVMConfig(CompilerToVM c2vm) {
         c2vm.initializeConfiguration(this);
@@ -52,9 +52,9 @@
      * @return value of option
      * @throws IllegalArgumentException if option doesn't exist
      */
-    private int getVMOptionInt(String name) {
+    public static int getVMOptionInt(String name) {
         String value = diagnostic.getVMOption(name).getValue();
-        return new Integer(value).intValue();
+        return Integer.valueOf(value).intValue();
     }
 
     /**
@@ -64,7 +64,7 @@
      * @param defaultValue default value if option is not exists (e.g. development options)
      * @return value of option or defaultValue if option doesn't exist
      */
-    private int getVMOption(String name, int defaultValue) {
+    public static int getVMOption(String name, int defaultValue) {
         try {
             return getVMOptionInt(name);
         } catch (IllegalArgumentException e) {
@@ -79,9 +79,9 @@
      * @return value of option
      * @throws IllegalArgumentException if option doesn't exist
      */
-    private boolean getVMOption(String name) {
+    public static boolean getVMOption(String name) {
         String value = diagnostic.getVMOption(name).getValue();
-        return new Boolean(value).booleanValue();
+        return Boolean.valueOf(value).booleanValue();
     }
 
     /**
@@ -91,7 +91,7 @@
      * @param defaultValue default value if option is not exists (e.g. development options)
      * @return value of option or defaultValue if option doesn't exist
      */
-    private boolean getVMOption(String name, boolean defaultValue) {
+    public static boolean getVMOption(String name, boolean defaultValue) {
         try {
             return getVMOption(name);
         } catch (IllegalArgumentException e) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPU.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPU.java	Wed Oct 02 13:26:31 2013 +0200
@@ -45,6 +45,8 @@
      */
     boolean deviceDetach();
 
+    int availableProcessors();
+
     /**
      * Attempts to generate and return a bound function to the
      * loaded method kernel on the GPU.
@@ -55,4 +57,8 @@
     long generateKernel(byte[] code, String name) throws InvalidInstalledCodeException;
 
     Object executeExternalMethodVarargs(Object[] args, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
+
+
+    Object executeParallelMethodVarargs(int dimX, int dimY, int dimZ,
+                                        Object[] args, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPUImpl.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPUImpl.java	Wed Oct 02 13:26:31 2013 +0200
@@ -38,5 +38,12 @@
 
     public native boolean deviceDetach();
 
-    public native Object executeExternalMethodVarargs(Object[] args, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
+    public native int availableProcessors();
+
+    public native Object executeExternalMethodVarargs(Object[] args,
+                                                      HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
+
+    public native Object executeParallelMethodVarargs(int dimX, int dimY, int dimZ,
+                                                      Object[] args,
+                                                      HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,6 +29,7 @@
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.java.GraphBuilderPhase.*;
 import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.phases.common.InliningUtil.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -51,7 +52,6 @@
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
-import com.oracle.graal.phases.common.*;
 import com.oracle.graal.printer.*;
 import com.oracle.graal.replacements.*;
 
@@ -105,8 +105,6 @@
 
     private PrintStream log = System.out;
 
-    private boolean quietMeterAndTime;
-
     private long compilerStartTime;
 
     public VMToCompilerImpl(HotSpotGraalRuntime compiler) {
@@ -165,13 +163,12 @@
         }
 
         if (config.ciTime) {
-            quietMeterAndTime = (Meter.getValue() == null && Time.getValue() == null);
-            DebugEnabled.setValue(true);
-            Meter.setValue("");
-            Time.setValue("");
+            BytecodesParsed.setConditional(false);
+            InlinedBytecodes.setConditional(false);
+            CompilationTime.setConditional(false);
         }
 
-        if (DebugEnabled.getValue()) {
+        if (Debug.isEnabled()) {
             DebugEnvironment.initialize(log);
 
             String summary = DebugValueSummary.getValue();
@@ -374,7 +371,7 @@
         CompilationStatistics.clear(phase);
         if (graalRuntime.getConfig().ciTime) {
             parsedBytecodesPerSecond = MetricRateInPhase.snapshot(phase, parsedBytecodesPerSecond, BytecodesParsed, CompilationTime, TimeUnit.SECONDS);
-            inlinedBytecodesPerSecond = MetricRateInPhase.snapshot(phase, inlinedBytecodesPerSecond, InliningUtil.InlinedBytecodes, CompilationTime, TimeUnit.SECONDS);
+            inlinedBytecodesPerSecond = MetricRateInPhase.snapshot(phase, inlinedBytecodesPerSecond, InlinedBytecodes, CompilationTime, TimeUnit.SECONDS);
         }
     }
 
@@ -435,7 +432,7 @@
 
         bootstrapRunning = false;
 
-        TTY.println(" in %d ms", System.currentTimeMillis() - startTime);
+        TTY.println(" in %d ms (compiled %d methods)", System.currentTimeMillis() - startTime, compileQueue.getCompletedTaskCount());
         if (graalRuntime.getCache() != null) {
             graalRuntime.getCache().clear();
         }
@@ -476,7 +473,7 @@
             CompilationTask.withinEnqueue.set(Boolean.FALSE);
         }
 
-        if (Debug.isEnabled() && !quietMeterAndTime) {
+        if (Debug.isEnabled() && areDebugScopePatternsEnabled()) {
             List<DebugValueMap> topLevelMaps = DebugValueMap.getTopLevelMaps();
             List<DebugValue> debugValues = KeyRegistry.getDebugValues();
             if (debugValues.size() > 0) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java	Wed Oct 02 13:26:31 2013 +0200
@@ -123,6 +123,15 @@
         return true;
     }
 
+    public Object executeParallel(int dimX, int dimY, int dimZ, Object... args) throws InvalidInstalledCodeException {
+        assert checkArgs(args);
+
+        assert isExternal(); // for now
+
+        return graalRuntime().getCompilerToGPU().executeParallelMethodVarargs(dimX, dimY, dimZ, args, this);
+
+    }
+
     @Override
     public Object executeVarargs(Object... args) throws InvalidInstalledCodeException {
         assert checkArgs(args);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Wed Oct 02 13:26:31 2013 +0200
@@ -167,8 +167,14 @@
         return true;
     }
 
-    private static final String SystemClassName = MetaUtil.toInternalName(System.class.getName());
+    private static final String SystemClassName = "Ljava/lang/System;";
 
+    /**
+     * {@inheritDoc}
+     * <p>
+     * The {@code value} field in {@link OptionValue} is considered constant if the type of
+     * {@code receiver} is (assignable to) {@link StableOptionValue}.
+     */
     @Override
     public Constant readConstantValue(Constant receiver) {
         assert !AOTCompilation.getValue() || isCalledForSnippets() : receiver;
@@ -198,6 +204,7 @@
             } else {
                 Class<?> clazz = object.getClass();
                 if (StableOptionValue.class.isAssignableFrom(clazz)) {
+                    assert getName().equals("value") : "Unexpected field in " + StableOptionValue.class.getName() + " hierarchy:" + this;
                     StableOptionValue<?> option = (StableOptionValue<?>) object;
                     return Constant.forObject(option.getValue());
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Wed Oct 02 13:26:31 2013 +0200
@@ -218,6 +218,10 @@
 
     @Override
     public int getMaxLocals() {
+        int modifiers = getModifiers();
+        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+            return 0;
+        }
         HotSpotVMConfig config = graalRuntime().getConfig();
         long metaspaceConstMethod = unsafe.getLong(metaspaceMethod + config.methodConstMethodOffset);
         return unsafe.getShort(metaspaceConstMethod + config.methodMaxLocalsOffset) & 0xFFFF;
@@ -225,6 +229,10 @@
 
     @Override
     public int getMaxStackSize() {
+        int modifiers = getModifiers();
+        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+            return 0;
+        }
         HotSpotVMConfig config = graalRuntime().getConfig();
         long metaspaceConstMethod = unsafe.getLong(metaspaceMethod + config.methodConstMethodOffset);
         return config.extraStackEntries + (unsafe.getShort(metaspaceConstMethod + config.constMethodMaxStackOffset) & 0xFFFF);
@@ -407,6 +415,9 @@
     @Override
     public LineNumberTable getLineNumberTable() {
         long[] values = graalRuntime().getCompilerToVM().getLineNumberTable(this);
+        if (values == null) {
+            return null;
+        }
         assert values.length % 2 == 0;
         int[] bci = new int[values.length / 2];
         int[] line = new int[values.length / 2];
@@ -422,6 +433,9 @@
     @Override
     public LocalVariableTable getLocalVariableTable() {
         Local[] locals = graalRuntime().getCompilerToVM().getLocalVariableTable(this);
+        if (locals == null) {
+            return null;
+        }
         return new LocalVariableTableImpl(locals);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Wed Oct 02 13:26:31 2013 +0200
@@ -345,7 +345,11 @@
     @Override
     public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method) {
         assert method instanceof HotSpotMethod;
-        return (ResolvedJavaMethod) graalRuntime().getCompilerToVM().resolveMethod(this, method.getName(), ((HotSpotSignature) method.getSignature()).getMethodDescriptor());
+        ResolvedJavaMethod res = (ResolvedJavaMethod) graalRuntime().getCompilerToVM().resolveMethod(this, method.getName(), ((HotSpotSignature) method.getSignature()).getMethodDescriptor());
+        if (res == null || isAbstract(res.getModifiers())) {
+            return null;
+        }
+        return res;
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,8 +23,8 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
-import static com.oracle.graal.api.code.DeoptimizationAction.*;
 import static com.oracle.graal.api.code.MemoryBarriers.*;
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.graph.UnsafeAccess.*;
@@ -49,6 +49,7 @@
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*;
 import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*;
+import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 import static com.oracle.graal.replacements.Log.*;
@@ -85,7 +86,6 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.tiers.*;
@@ -290,7 +290,7 @@
         registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
 
         link(new NewInstanceStub(this, r, target, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
-        link(new NewArrayStub(this, r, target, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
+        link(new NewArrayStub(this, r, target, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, INIT_LOCATION)));
         link(new ExceptionHandlerStub(this, r, target, foreignCalls.get(EXCEPTION_HANDLER)));
         link(new UnwindExceptionToCallerStub(this, r, target, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
         link(new VerifyOopStub(this, r, target, registerStubCall(VERIFY_OOP, REEXECUTABLE, LEAF, NO_LOCATIONS)));
@@ -301,8 +301,8 @@
         linkForeignCall(r, CREATE_OUT_OF_BOUNDS_EXCEPTION, c.createOutOfBoundsExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
         linkForeignCall(r, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
         linkForeignCall(r, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
-        linkForeignCall(r, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
-        linkForeignCall(r, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
+        linkForeignCall(r, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION);
+        linkForeignCall(r, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION);
         linkForeignCall(r, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(r, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(r, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
@@ -477,9 +477,9 @@
     }
 
     @Override
-    public int lookupArrayLength(Constant array) {
+    public Integer lookupArrayLength(Constant array) {
         if (array.getKind() != Kind.Object || array.isNull() || !array.asObject().getClass().isArray()) {
-            throw new IllegalArgumentException(array + " is not an array");
+            return null;
         }
         return Array.getLength(array.asObject());
     }
@@ -555,10 +555,9 @@
             assert loadField.kind() != Kind.Illegal;
             BarrierType barrierType = getFieldLoadBarrierType(field);
             ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object)));
+            graph.replaceFixedWithFixed(loadField, memoryRead);
             tool.createNullCheckGuard(memoryRead, object);
 
-            graph.replaceFixedWithFixed(loadField, memoryRead);
-
             if (loadField.isVolatile()) {
                 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
                 graph.addBeforeFixed(memoryRead, preMembar);
@@ -606,18 +605,21 @@
             LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index());
             ValueNode value = storeIndexed.value();
             ValueNode array = storeIndexed.array();
+
+            CheckCastNode checkcastNode = null;
+            CheckCastDynamicNode checkcastDynamicNode = null;
             if (elementKind == Kind.Object && !ObjectStamp.isObjectAlwaysNull(value)) {
                 // Store check!
                 ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array);
                 if (arrayType != null && ObjectStamp.isExactType(array)) {
                     ResolvedJavaType elementType = arrayType.getComponentType();
                     if (!MetaUtil.isJavaLangObject(elementType)) {
-                        CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null, true));
-                        graph.addBeforeFixed(storeIndexed, checkcast);
-                        value = checkcast;
+                        checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true));
+                        graph.addBeforeFixed(storeIndexed, checkcastNode);
+                        value = checkcastNode;
                     }
                 } else {
-                    LoadHubNode arrayClass = graph.add(new LoadHubNode(array, wordKind, boundsCheck.asNode()));
+                    FloatingReadNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck);
                     LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
                     /*
                      * Anchor the read of the element klass to the cfg, because it is only valid
@@ -625,9 +627,9 @@
                      * parts of the compiled method.
                      */
                     FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind()), BeginNode.prevBegin(storeIndexed)));
-                    CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
-                    graph.addBeforeFixed(storeIndexed, checkcast);
-                    value = checkcast;
+                    checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
+                    graph.addBeforeFixed(storeIndexed, checkcastDynamicNode);
+                    value = checkcastDynamicNode;
                 }
             }
             BarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
@@ -636,12 +638,18 @@
             memoryWrite.setStateAfter(storeIndexed.stateAfter());
             graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
 
+            // Lower the associated checkcast node.
+            if (checkcastNode != null) {
+                checkcastNode.lower(tool);
+            } else if (checkcastDynamicNode != null) {
+                checkcastDynamicSnippets.lower(checkcastDynamicNode);
+            }
         } else if (n instanceof UnsafeLoadNode) {
-            if (tool.getLoweringType().ordinal() > LoweringType.BEFORE_GUARDS.ordinal()) {
+            if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
                 UnsafeLoadNode load = (UnsafeLoadNode) n;
                 assert load.kind() != Kind.Illegal;
                 boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
-                if (addReadBarrier(load, tool)) {
+                if (addReadBarrier(load)) {
                     unsafeLoadSnippets.lower(load, tool);
                 } else {
                     IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, load.accessKind(), load.displacement(), load.offset(), graph, 1);
@@ -676,14 +684,8 @@
             StoreHubNode storeHub = (StoreHubNode) n;
             WriteNode hub = createWriteHub(graph, wordKind, storeHub.getObject(), storeHub.getValue());
             graph.replaceFixed(storeHub, hub);
-        } else if (n instanceof FixedGuardNode) {
-            FixedGuardNode node = (FixedGuardNode) n;
-            GuardingNode guard = tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated());
-            ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(guard.asNode()));
-            node.replaceAtUsages(guard.asNode());
-            graph.replaceFixedWithFixed(node, newAnchor);
         } else if (n instanceof CommitAllocationNode) {
-            if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
                 CommitAllocationNode commit = (CommitAllocationNode) n;
 
                 ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
@@ -749,6 +751,7 @@
                     for (int lockDepth : commit.getLocks().get(objIndex)) {
                         MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], lockDepth));
                         graph.addBeforeFixed(commit, enter);
+                        enter.lower(tool);
                     }
                 }
                 for (Node usage : commit.usages().snapshot()) {
@@ -759,7 +762,7 @@
                 graph.removeFixed(commit);
             }
         } else if (n instanceof OSRStartNode) {
-            if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
                 OSRStartNode osrStart = (OSRStartNode) n;
                 StartNode newStart = graph.add(new StartNode());
                 LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind())));
@@ -788,31 +791,31 @@
         } else if (n instanceof CheckCastDynamicNode) {
             checkcastDynamicSnippets.lower((CheckCastDynamicNode) n);
         } else if (n instanceof InstanceOfNode) {
-            if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
                 instanceofSnippets.lower((InstanceOfNode) n, tool);
             }
         } else if (n instanceof InstanceOfDynamicNode) {
-            if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
                 instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
             }
         } else if (n instanceof NewInstanceNode) {
-            if (tool.getLoweringType() == LoweringType.AFTER_FSA) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
                 newObjectSnippets.lower((NewInstanceNode) n);
             }
         } else if (n instanceof NewArrayNode) {
-            if (tool.getLoweringType() == LoweringType.AFTER_FSA) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
                 newObjectSnippets.lower((NewArrayNode) n);
             }
         } else if (n instanceof DynamicNewArrayNode) {
-            if (tool.getLoweringType() == LoweringType.AFTER_FSA) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
                 newObjectSnippets.lower((DynamicNewArrayNode) n);
             }
         } else if (n instanceof MonitorEnterNode) {
-            if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
                 monitorSnippets.lower((MonitorEnterNode) n, tool);
             }
         } else if (n instanceof MonitorExitNode) {
-            if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
                 monitorSnippets.lower((MonitorExitNode) n, tool);
             }
         } else if (n instanceof G1PreWriteBarrier) {
@@ -830,7 +833,7 @@
         } else if (n instanceof G1ArrayRangePostWriteBarrier) {
             writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, tool);
         } else if (n instanceof NewMultiArrayNode) {
-            if (tool.getLoweringType() == LoweringType.AFTER_FSA) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
                 newObjectSnippets.lower((NewMultiArrayNode) n);
             }
         } else if (n instanceof LoadExceptionObjectNode) {
@@ -838,8 +841,6 @@
         } 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.
-        } else if (n instanceof UnwindNode || n instanceof DeoptimizeNode) {
-            // Nothing to do, using direct LIR lowering for these nodes.
         } else if (n instanceof BoxNode) {
             boxingSnippets.lower((BoxNode) n, tool);
         } else if (n instanceof UnboxNode) {
@@ -850,8 +851,8 @@
         }
     }
 
-    private static boolean addReadBarrier(UnsafeLoadNode load, LoweringTool tool) {
-        if (useG1GC() && tool.getLoweringType() == LoweringType.AFTER_GUARDS && load.object().kind() == Kind.Object && load.accessKind() == Kind.Object &&
+    private static boolean addReadBarrier(UnsafeLoadNode load) {
+        if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().kind() == Kind.Object && load.accessKind() == Kind.Object &&
                         !ObjectStamp.isObjectAlwaysNull(load.object())) {
             ResolvedJavaType type = ObjectStamp.typeOrNull(load.object());
             if (type != null && !type.isArray()) {
@@ -877,11 +878,11 @@
     private FloatingReadNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object, GuardingNode guard) {
         LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph);
         assert !object.isConstant() || object.asConstant().isNull();
-        return graph.add(new FloatingReadNode(object, location, null, StampFactory.forKind(wordKind()), guard, BarrierType.NONE, useCompressedKlassPointers()));
+        return graph.unique(new FloatingReadNode(object, location, null, StampFactory.forKind(wordKind()), guard, BarrierType.NONE, useCompressedKlassPointers()));
     }
 
     private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) {
-        LocationNode location = ConstantLocationNode.create(ANY_LOCATION, wordKind, config.hubOffset, graph);
+        LocationNode location = ConstantLocationNode.create(HUB_LOCATION, wordKind, config.hubOffset, graph);
         assert !object.isConstant() || object.asConstant().isNull();
         return graph.add(new WriteNode(object, value, location, BarrierType.NONE, useCompressedKlassPointers()));
     }
@@ -991,13 +992,19 @@
         }
     }
 
-    private static GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
-        StructuredGraph graph = n.graph();
-        ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array()));
-        GuardingNode guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
+    private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
+        StructuredGraph g = n.graph();
+        ValueNode array = n.array();
+        ValueNode arrayLength = readArrayLength(array, tool.getRuntime());
+        if (arrayLength == null) {
+            Stamp stamp = StampFactory.positiveInt();
+            ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, g), stamp, BarrierType.NONE, false));
+            g.addBeforeFixed(n, readArrayLength);
+            tool.createNullCheckGuard(readArrayLength, array);
+            arrayLength = readArrayLength;
+        }
 
-        graph.addBeforeFixed(n, arrayLength);
-        return guard;
+        return tool.createGuard(g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
     }
 
     public ResolvedJavaType lookupJavaType(Class<?> clazz) {
@@ -1069,13 +1076,13 @@
     }
 
     @Override
-    public int encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason) {
+    public Constant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason) {
         final int actionShift = 0;
         final int reasonShift = 3;
 
         int actionValue = convertDeoptAction(action);
         int reasonValue = convertDeoptReason(reason);
-        return (~(((reasonValue) << reasonShift) + ((actionValue) << actionShift)));
+        return Constant.forInt(~(((reasonValue) << reasonShift) + ((actionValue) << actionShift)));
     }
 
     public int convertDeoptAction(DeoptimizationAction action) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayRangeWriteBarrier.java	Wed Oct 02 13:26:31 2013 +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.hotspot.nodes;
+
+import com.oracle.graal.nodes.*;
+
+public abstract class ArrayRangeWriteBarrier extends WriteBarrier {
+
+    @Input private ValueNode startIndex;
+    @Input private ValueNode length;
+
+    public ArrayRangeWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
+        super(object, null, null, true);
+        this.startIndex = startIndex;
+        this.length = length;
+    }
+
+    public ValueNode getStartIndex() {
+        return startIndex;
+    }
+
+    public ValueNode getLength() {
+        return length;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -42,8 +41,8 @@
 
     private int lockDepth;
 
-    public BeginLockScopeNode(int lockDepth) {
-        super(StampFactory.forWord());
+    private BeginLockScopeNode(int lockDepth) {
+        super(null);
         this.lockDepth = lockDepth;
     }
 
@@ -66,6 +65,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static native Word beginLockScope(@ConstantNodeParameter int lockDepth);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -27,7 +27,6 @@
 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.word.*;
 
 /**
@@ -38,13 +37,13 @@
 
     private final String string;
 
-    public CStringNode(String string) {
-        super(StampFactory.forWord());
+    private CStringNode(String string) {
+        super(null);
         this.string = string;
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         byte[] formatBytes = string.getBytes();
         long cstring = unsafe.allocateMemory(formatBytes.length + 1);
         for (int i = 0; i < formatBytes.length; i++) {
@@ -55,6 +54,6 @@
         graph().replaceFloating(this, replacement);
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static native Word cstring(@ConstantNodeParameter String string);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.nodes.*;
+
+/**
+ * {@link MacroNode Macro node} for {@link Class#cast(Object)}.
+ * 
+ * @see ClassSubstitutions#isInstance(Class, Object)
+ */
+public class ClassCastNode extends MacroNode implements Canonicalizable {
+
+    public ClassCastNode(Invoke invoke) {
+        super(invoke);
+    }
+
+    private ValueNode getJavaClass() {
+        return arguments.get(0);
+    }
+
+    private ValueNode getObject() {
+        return arguments.get(1);
+    }
+
+    public ValueNode canonical(CanonicalizerTool tool) {
+        ValueNode javaClass = getJavaClass();
+        if (javaClass.isConstant()) {
+            ValueNode object = getObject();
+            Class c = (Class) javaClass.asConstant().asObject();
+            if (c != null && !c.isPrimitive()) {
+                HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(c);
+                CheckCastNode checkcast = graph().add(new CheckCastNode(type, object, null, false));
+                return checkcast;
+            }
+        }
+        return this;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,16 +28,15 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
  * Gets the address of the C++ JavaThread object for the current thread.
  */
-public class CurrentJavaThreadNode extends FloatingNode implements LIRLowerable {
+public final class CurrentJavaThreadNode extends FloatingNode implements LIRLowerable {
 
-    public CurrentJavaThreadNode() {
-        super(StampFactory.forWord());
+    private CurrentJavaThreadNode() {
+        super(null);
     }
 
     @Override
@@ -54,7 +53,7 @@
         }
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static Word get() {
         return Word.unsigned(unsafeReadWord(Thread.currentThread(), eetopOffset()));
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -38,8 +37,8 @@
 
     private int lockDepth;
 
-    public CurrentLockNode(int lockDepth) {
-        super(StampFactory.forWord());
+    private CurrentLockNode(int lockDepth) {
+        super(null);
         this.lockDepth = lockDepth;
     }
 
@@ -53,6 +52,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static native Word currentLock(@ConstantNodeParameter int lockDepth);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizingStubCall.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizingStubCall.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -36,9 +35,4 @@
     public boolean canDeoptimize() {
         return true;
     }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return null;
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -27,7 +27,6 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -38,8 +37,8 @@
 
     private final int rank;
 
-    public DimensionsNode(int rank) {
-        super(StampFactory.forWord());
+    private DimensionsNode(int rank) {
+        super(null);
         this.rank = rank;
     }
 
@@ -51,6 +50,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static native Word allocaDimsArray(@ConstantNodeParameter int rank);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ArrayRangePostWriteBarrier.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,32 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.nodes.*;
+
+public final class G1ArrayRangePostWriteBarrier extends ArrayRangeWriteBarrier {
+
+    public G1ArrayRangePostWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
+        super(object, startIndex, length);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ArrayRangePreWriteBarrier.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,32 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.nodes.*;
+
+public final class G1ArrayRangePreWriteBarrier extends ArrayRangeWriteBarrier {
+
+    public G1ArrayRangePreWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
+        super(object, startIndex, length);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrier.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,33 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+public class G1PostWriteBarrier extends WriteBarrier {
+
+    public G1PostWriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
+        super(object, value, location, precise);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrier.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,71 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+public class G1PreWriteBarrier extends WriteBarrier implements DeoptimizingNode {
+
+    @Input private FrameState deoptimizationState;
+    private final boolean nullCheck;
+    private final boolean doLoad;
+
+    public G1PreWriteBarrier(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad, boolean nullCheck) {
+        super(object, expectedObject, location, true);
+        this.doLoad = doLoad;
+        this.nullCheck = nullCheck;
+    }
+
+    public ValueNode getExpectedObject() {
+        return getValue();
+    }
+
+    public boolean doLoad() {
+        return doLoad;
+    }
+
+    public boolean getNullCheck() {
+        return nullCheck;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return nullCheck;
+    }
+
+    @Override
+    public FrameState getDeoptimizationState() {
+        return deoptimizationState;
+    }
+
+    @Override
+    public void setDeoptimizationState(FrameState state) {
+        updateUsages(deoptimizationState, state);
+        deoptimizationState = state;
+    }
+
+    public FrameState getState() {
+        return deoptimizationState;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ReferentFieldReadBarrier.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,50 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * The {@code G1ReferentFieldReadBarrier} is added when a read access is performed to the referent
+ * field of a {@link java.lang.ref.Reference} object (through a {@code LoadFieldNode} or an
+ * {@code UnsafeLoadNode}). The return value of the read is passed to the snippet implementing the
+ * read barrier and consequently is added to the SATB queue if the concurrent marker is enabled.
+ */
+public class G1ReferentFieldReadBarrier extends WriteBarrier {
+
+    private final boolean doLoad;
+
+    public G1ReferentFieldReadBarrier(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad) {
+        super(object, expectedObject, location, true);
+        this.doLoad = doLoad;
+    }
+
+    public ValueNode getExpectedObject() {
+        return getValue();
+    }
+
+    public boolean doLoad() {
+        return doLoad;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -27,7 +27,6 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -35,8 +34,8 @@
  */
 public final class MonitorCounterNode extends FloatingNode implements LIRGenLowerable {
 
-    public MonitorCounterNode() {
-        super(StampFactory.forWord());
+    private MonitorCounterNode() {
+        super(null);
     }
 
     @Override
@@ -47,6 +46,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static native Word counter();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialArrayRangeWriteBarrier.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,32 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.nodes.*;
+
+public final class SerialArrayRangeWriteBarrier extends ArrayRangeWriteBarrier {
+
+    public SerialArrayRangeWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
+        super(object, startIndex, length);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrier.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,33 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+public class SerialWriteBarrier extends WriteBarrier {
+
+    public SerialWriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
+        super(object, value, location, precise);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.code.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -35,11 +34,10 @@
  * Node for a {@linkplain ForeignCallDescriptor foreign} call from within a stub.
  */
 @NodeInfo(nameTemplate = "StubForeignCall#{p#descriptor/s}")
-public class StubForeignCallNode extends FixedWithNextNode implements DeoptimizingNode, LIRLowerable, MemoryCheckpoint.Multi {
+public class StubForeignCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
 
     @Input private final NodeInputList<ValueNode> arguments;
     private final MetaAccessProvider runtime;
-    @Input private FrameState deoptState;
 
     private final ForeignCallDescriptor descriptor;
 
@@ -72,7 +70,7 @@
         assert graph().start() instanceof StubStartNode;
         ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(descriptor);
         Value[] operands = operands(gen);
-        Value result = gen.emitForeignCall(linkage, this, operands);
+        Value result = gen.emitForeignCall(linkage, null, operands);
         if (result != null) {
             gen.setResult(this, result);
         }
@@ -85,23 +83,4 @@
         }
         return super.toString(verbosity);
     }
-
-    @Override
-    public boolean canDeoptimize() {
-        return false;
-    }
-
-    @Override
-    public FrameState getDeoptimizationState() {
-        return null;
-    }
-
-    @Override
-    public void setDeoptimizationState(FrameState state) {
-    }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return null;
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,67 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+public abstract class WriteBarrier extends FixedWithNextNode implements Lowerable, IterableNodeType {
+
+    @Input private ValueNode object;
+    @Input private ValueNode value;
+    @Input private LocationNode location;
+    private final boolean precise;
+
+    public WriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
+        super(StampFactory.forVoid());
+        this.object = object;
+        this.value = value;
+        this.location = location;
+        this.precise = precise;
+    }
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    public ValueNode getObject() {
+        return object;
+    }
+
+    public LocationNode getLocation() {
+        return location;
+    }
+
+    public boolean usePrecise() {
+        return precise;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        assert graph().getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA;
+        tool.getRuntime().lower(this, tool);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -61,7 +61,7 @@
 
                 Stamp stamp = StampFactory.exactNonNull(runtime.lookupJavaType(Class.class));
                 LocationNode location = graph.unique(ConstantLocationNode.create(FINAL_LOCATION, stamp.kind(), runtime.config.classMirrorOffset, graph));
-                FloatingReadNode freadNode = graph.add(new FloatingReadNode(klassNode, location, null, stamp));
+                FloatingReadNode freadNode = graph.unique(new FloatingReadNode(klassNode, location, null, stamp));
 
                 graph.replaceFloating(node, freadNode);
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/VerifyHotSpotOptionsPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/VerifyHotSpotOptionsPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -57,31 +57,41 @@
             for (OptionDescriptor desc : opts) {
                 if (HotSpotOptions.isHotSpotOption(desc)) {
                     HotSpotResolvedObjectType holder = (HotSpotResolvedObjectType) runtime.lookupJavaType(desc.getDeclaringClass());
-                    if (!checked.contains(holder)) {
-                        checked.add(holder);
-                        for (ResolvedJavaMethod method : holder.getMethods()) {
-                            if (method.isClassInitializer()) {
-                                StructuredGraph graph = new StructuredGraph(method);
-                                new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
-                                new VerifyHotSpotOptionsPhase(holder, runtime).apply(graph);
-                            }
-                        }
-                    }
+                    checkType(holder, desc, runtime, checked);
                 }
             }
         }
         return true;
     }
 
+    private static void checkType(HotSpotResolvedObjectType type, OptionDescriptor option, HotSpotRuntime runtime, Set<HotSpotResolvedObjectType> checked) {
+        if (!checked.contains(type)) {
+            checked.add(type);
+            HotSpotResolvedObjectType superType = type.getSupertype();
+            if (superType != null && !MetaUtil.isJavaLangObject(superType)) {
+                checkType(superType, option, runtime, checked);
+            }
+            for (ResolvedJavaMethod method : type.getMethods()) {
+                if (method.isClassInitializer()) {
+                    StructuredGraph graph = new StructuredGraph(method);
+                    new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+                    new VerifyHotSpotOptionsPhase(type, runtime, option).apply(graph);
+                }
+            }
+        }
+    }
+
     private final HotSpotRuntime runtime;
     private final ResolvedJavaType declaringClass;
     private final ResolvedJavaType optionValueType;
     private final Set<ResolvedJavaType> boxingTypes;
+    private final OptionDescriptor option;
 
-    public VerifyHotSpotOptionsPhase(ResolvedJavaType declaringClass, HotSpotRuntime runtime) {
+    public VerifyHotSpotOptionsPhase(ResolvedJavaType declaringClass, HotSpotRuntime runtime, OptionDescriptor option) {
         this.runtime = runtime;
         this.declaringClass = declaringClass;
         this.optionValueType = runtime.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(runtime.lookupJavaType(c));
@@ -136,7 +146,9 @@
 
     private void error(Node node, String message) {
         String loc = GraphUtil.approxSourceLocation(node);
-        throw new GraalInternalError(String.format("HotSpot option declarer %s contains code pattern implying action other than initialization of an option:%n    %s%n    %s",
+        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.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
@@ -37,18 +39,18 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (ReadNode node : graph.getNodes(ReadNode.class)) {
-            addReadNodeBarriers(node, graph);
-        }
-        for (WriteNode node : graph.getNodes(WriteNode.class)) {
-            addWriteNodeBarriers(node, graph);
-        }
-        for (LoweredCompareAndSwapNode node : graph.getNodes(LoweredCompareAndSwapNode.class)) {
-            addCASBarriers(node, graph);
-        }
-        for (ArrayRangeWriteNode node : graph.getNodes(ArrayRangeWriteNode.class)) {
-            if (node.isObjectArray()) {
-                addArrayRangeBarriers(node, graph);
+        for (Node n : graph.getNodes()) {
+            if (n instanceof ReadNode) {
+                addReadNodeBarriers((ReadNode) n, graph);
+            } else if (n instanceof WriteNode) {
+                addWriteNodeBarriers((WriteNode) n, graph);
+            } else if (n instanceof LoweredCompareAndSwapNode) {
+                addCASBarriers((LoweredCompareAndSwapNode) n, graph);
+            } else if (n instanceof ArrayRangeWriteNode) {
+                ArrayRangeWriteNode node = (ArrayRangeWriteNode) n;
+                if (node.isObjectArray()) {
+                    addArrayRangeBarriers(node, graph);
+                }
             }
         }
     }
@@ -63,53 +65,60 @@
         }
     }
 
-    private static void addWriteNodeBarriers(WriteNode node, StructuredGraph graph) {
+    protected static void addG1PreWriteBarrier(AccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean doLoad, boolean nullCheck, StructuredGraph graph) {
+        G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(object, value, location, doLoad, nullCheck));
+        preBarrier.setDeoptimizationState(node.getDeoptimizationState());
+        node.setNullCheck(false);
+        node.setDeoptimizationState(null);
+        graph.addBeforeFixed(node, preBarrier);
+    }
+
+    protected void addG1PostWriteBarrier(AccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) {
+        graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(object, value, location, precise)));
+    }
+
+    protected void addSerialPostWriteBarrier(AccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) {
+        graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(object, value, location, precise)));
+    }
+
+    private void addWriteNodeBarriers(WriteNode node, StructuredGraph graph) {
         BarrierType barrierType = node.getBarrierType();
         if (barrierType == BarrierType.PRECISE) {
             if (useG1GC()) {
                 if (!node.isInitialization()) {
-                    G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(node.object(), null, node.location(), true, node.getNullCheck()));
-                    preBarrier.setDeoptimizationState(node.getDeoptimizationState());
-                    node.setNullCheck(false);
-                    node.setDeoptimizationState(null);
-                    graph.addBeforeFixed(node, preBarrier);
+                    addG1PreWriteBarrier(node, node.object(), null, node.location(), true, node.getNullCheck(), graph);
                 }
-                graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(node.object(), node.value(), node.location(), true)));
+                addG1PostWriteBarrier(node, node.object(), node.value(), node.location(), true, graph);
             } else {
-                graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), node.value(), node.location(), true)));
+                addSerialPostWriteBarrier(node, node.object(), node.value(), node.location(), true, graph);
             }
         } else if (barrierType == BarrierType.IMPRECISE) {
             if (useG1GC()) {
-                G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(node.object(), null, node.location(), true, node.getNullCheck()));
-                preBarrier.setDeoptimizationState(node.getDeoptimizationState());
-                node.setNullCheck(false);
-                node.setDeoptimizationState(null);
-                graph.addBeforeFixed(node, preBarrier);
-                graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(node.object(), node.value(), node.location(), false)));
+                addG1PreWriteBarrier(node, node.object(), null, node.location(), true, node.getNullCheck(), graph);
+                addG1PostWriteBarrier(node, node.object(), node.value(), node.location(), false, graph);
             } else {
-                graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), node.value(), node.location(), false)));
+                addSerialPostWriteBarrier(node, node.object(), node.value(), node.location(), false, graph);
             }
         } else {
             assert barrierType == BarrierType.NONE;
         }
-
     }
 
-    private static void addCASBarriers(LoweredCompareAndSwapNode node, StructuredGraph graph) {
+    private void addCASBarriers(LoweredCompareAndSwapNode node, StructuredGraph graph) {
         BarrierType barrierType = node.getBarrierType();
         if (barrierType == BarrierType.PRECISE) {
             if (useG1GC()) {
-                graph.addBeforeFixed(node, graph.add(new G1PreWriteBarrier(node.object(), node.getExpectedValue(), node.location(), false, false)));
-                graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(node.object(), node.getNewValue(), node.location(), true)));
+                addG1PreWriteBarrier(node, node.object(), node.getExpectedValue(), node.location(), false, false, graph);
+                addG1PostWriteBarrier(node, node.object(), node.getNewValue(), node.location(), true, graph);
             } else {
-                graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), node.getNewValue(), node.location(), true)));
+                addSerialPostWriteBarrier(node, node.object(), node.getNewValue(), node.location(), true, graph);
             }
         } else if (barrierType == BarrierType.IMPRECISE) {
             if (useG1GC()) {
-                graph.addBeforeFixed(node, graph.add(new G1PreWriteBarrier(node.object(), node.getExpectedValue(), node.location(), false, false)));
-                graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(node.object(), node.getNewValue(), node.location(), false)));
+                addG1PreWriteBarrier(node, node.object(), node.getExpectedValue(), node.location(), false, false, graph);
+                addG1PostWriteBarrier(node, node.object(), node.getNewValue(), node.location(), false, graph);
             } else {
-                graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), node.getNewValue(), node.location(), false)));
+                addSerialPostWriteBarrier(node, node.object(), node.getNewValue(), node.location(), false, graph);
             }
         } else {
             assert barrierType == BarrierType.NONE;
@@ -129,5 +138,4 @@
             graph.addAfterFixed(node, serialArrayRangeWriteBarrier);
         }
     }
-
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,6 +28,7 @@
 import java.util.*;
 
 import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,9 +24,10 @@
 
 import static com.oracle.graal.compiler.GraalCompiler.*;
 
+import java.util.concurrent.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -37,7 +38,7 @@
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.nodes.*;
 
-public class ArrayCopyNode extends MacroNode implements Virtualizable, IterableNodeType, Lowerable {
+public class ArrayCopyNode extends MacroNode implements Virtualizable, Lowerable {
 
     public ArrayCopyNode(Invoke invoke) {
         super(invoke);
@@ -63,7 +64,7 @@
         return arguments.get(4);
     }
 
-    private StructuredGraph selectSnippet(LoweringTool tool, Replacements replacements) {
+    private StructuredGraph selectSnippet(LoweringTool tool, final Replacements replacements) {
         ResolvedJavaType srcType = ObjectStamp.typeOrNull(getSource().stamp());
         ResolvedJavaType destType = ObjectStamp.typeOrNull(getDestination().stamp());
 
@@ -74,8 +75,15 @@
             return null;
         }
         Kind componentKind = srcType.getComponentType().getKind();
-        ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind));
-        return replacements.getSnippet(snippetMethod);
+        final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind));
+        return Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
+
+            @Override
+            public StructuredGraph call() throws Exception {
+                return replacements.getSnippet(snippetMethod);
+            }
+        });
+
     }
 
     private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) {
@@ -87,31 +95,43 @@
         // additions, etc.
         PhaseContext context = new PhaseContext(tool.getRuntime(), tool.assumptions(), tool.getReplacements());
         new CanonicalizerPhase(true).apply(snippetGraph, context);
-        new LoopFullUnrollPhase(true).apply(snippetGraph, context);
+        new LoopFullUnrollPhase(new CanonicalizerPhase(true)).apply(snippetGraph, context);
         new CanonicalizerPhase(true).apply(snippetGraph, context);
     }
 
     @Override
-    protected StructuredGraph getSnippetGraph(LoweringTool tool) {
+    protected StructuredGraph getLoweredSnippetGraph(final LoweringTool tool) {
         if (!shouldIntrinsify(getTargetMethod())) {
             return null;
         }
 
-        Replacements replacements = tool.getReplacements();
+        final Replacements replacements = tool.getReplacements();
         StructuredGraph snippetGraph = selectSnippet(tool, replacements);
         if (snippetGraph == null) {
-            ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet);
-            snippetGraph = replacements.getSnippet(snippetMethod).copy();
+            final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet);
+            snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
+
+                @Override
+                public StructuredGraph call() throws Exception {
+                    return replacements.getSnippet(snippetMethod).copy();
+                }
+            });
             replaceSnippetInvokes(snippetGraph);
         } else {
             assert snippetGraph != null : "ArrayCopySnippets should be installed";
-
+            snippetGraph = snippetGraph.copy();
             if (getLength().isConstant() && getLength().asConstant().asInt() <= GraalOptions.MaximumEscapeAnalysisArrayLength.getValue()) {
-                snippetGraph = snippetGraph.copy();
-                unrollFixedLengthLoop(snippetGraph, getLength().asConstant().asInt(), tool);
+                final StructuredGraph copy = snippetGraph;
+                Debug.scope("ArrayCopySnippetSpecialization", snippetGraph.method(), new Runnable() {
+
+                    @Override
+                    public void run() {
+                        unrollFixedLengthLoop(copy, getLength().asConstant().asInt(), tool);
+                    }
+                });
             }
         }
-        return snippetGraph;
+        return lowerReplacement(snippetGraph, tool);
     }
 
     private static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -66,13 +66,15 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         ConstantNode target = getConstantCallTarget(tool.getRuntime(), tool.assumptions());
 
         if (target != null) {
             graph().replaceFixedWithFloating(this, target);
         } else {
-            graph().replaceFixedWithFixed(this, createInvoke());
+            InvokeNode invoke = createInvoke();
+            graph().replaceFixedWithFixed(this, invoke);
+            invoke.lower(tool);
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastDynamicSnippets.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastDynamicSnippets.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,12 +22,12 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.*;
+import static com.oracle.graal.nodes.PiNode.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
 import com.oracle.graal.api.code.*;
@@ -59,7 +59,7 @@
             }
         }
         BeginNode anchorNode = BeginNode.anchor();
-        return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic(), anchorNode);
+        return piCast(verifyOop(object), StampFactory.forNodeIntrinsic(), anchorNode);
     }
 
     public static class Templates extends AbstractTemplates {
@@ -74,7 +74,7 @@
             StructuredGraph graph = checkcast.graph();
             ValueNode object = checkcast.object();
 
-            Arguments args = new Arguments(dynamic);
+            Arguments args = new Arguments(dynamic, graph.getGuardsStage());
             args.add("hub", checkcast.hub());
             args.add("object", object);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
+import static com.oracle.graal.nodes.PiNode.*;
 
 import java.lang.reflect.*;
 
@@ -96,7 +96,7 @@
                     if (superKlass.equal(0)) {
                         return null;
                     } else {
-                        return unsafeCast(superKlass.readObject(classMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
+                        return piCast(superKlass.readObject(classMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
                     }
                 }
             }
@@ -110,7 +110,7 @@
         Word klass = loadWordFromObject(thisObj, klassOffset());
         if (klass.notEqual(0)) {
             if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) {
-                return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
+                return piCast(klass.readObject(arrayKlassComponentMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
             }
         }
         return null;
@@ -121,4 +121,7 @@
     public static boolean isInstance(final Class<?> thisObj, Object obj) {
         return !isPrimitive(thisObj) && ConditionalNode.materializeIsInstance(thisObj, obj);
     }
+
+    @MacroSubstitution(macro = ClassCastNode.class, isStatic = false)
+    public static native Object cast(final Class<?> thisObj, Object obj);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
@@ -215,24 +215,25 @@
 
                 Arguments args;
 
+                StructuredGraph graph = hub.graph();
                 if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet()) {
-                    Hints hints = createHints(hintInfo, runtime, false, hub.graph());
-                    args = new Arguments(instanceofWithProfile);
+                    Hints hints = createHints(hintInfo, runtime, false, graph);
+                    args = new Arguments(instanceofWithProfile, graph.getGuardsStage());
                     args.add("object", object);
                     args.addVarargs("hints", Word.class, StampFactory.forKind(wordKind()), hints.hubs);
                     args.addVarargs("hintIsPositive", boolean.class, StampFactory.forKind(Kind.Boolean), hints.isPositive);
                 } else if (hintInfo.exact != null) {
-                    args = new Arguments(instanceofExact);
+                    args = new Arguments(instanceofExact, graph.getGuardsStage());
                     args.add("object", object);
-                    args.add("exactHub", ConstantNode.forConstant(((HotSpotResolvedObjectType) hintInfo.exact).klass(), runtime, hub.graph()));
+                    args.add("exactHub", ConstantNode.forConstant(((HotSpotResolvedObjectType) hintInfo.exact).klass(), runtime, graph));
                 } else if (type.isPrimaryType()) {
-                    args = new Arguments(instanceofPrimary);
+                    args = new Arguments(instanceofPrimary, graph.getGuardsStage());
                     args.add("hub", hub);
                     args.add("object", object);
                     args.addConst("superCheckOffset", type.superCheckOffset());
                 } else {
-                    Hints hints = createHints(hintInfo, runtime, false, hub.graph());
-                    args = new Arguments(instanceofSecondary);
+                    Hints hints = createHints(hintInfo, runtime, false, graph);
+                    args = new Arguments(instanceofSecondary, graph.getGuardsStage());
                     args.add("hub", hub);
                     args.add("object", object);
                     args.addVarargs("hints", Word.class, StampFactory.forKind(getWordKind()), hints.hubs);
@@ -250,7 +251,7 @@
                 InstanceOfDynamicNode instanceOf = (InstanceOfDynamicNode) replacer.instanceOf;
                 ValueNode object = instanceOf.object();
 
-                Arguments args = new Arguments(instanceofDynamic);
+                Arguments args = new Arguments(instanceofDynamic, instanceOf.graph().getGuardsStage());
                 args.add("mirror", instanceOf.mirror());
                 args.add("object", object);
                 args.add("trueValue", replacer.trueValue);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,7 +24,7 @@
 
 import static com.oracle.graal.hotspot.meta.HotSpotRuntime.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
+import static com.oracle.graal.nodes.PiNode.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
 import com.oracle.graal.api.code.*;
@@ -57,7 +57,7 @@
         Object exception = readExceptionOop(thread);
         writeExceptionOop(thread, null);
         writeExceptionPc(thread, Word.zero());
-        return unsafeCast(exception, StampFactory.forNodeIntrinsic());
+        return piCast(exception, StampFactory.forNodeIntrinsic());
     }
 
     public static class Templates extends AbstractTemplates {
@@ -78,7 +78,7 @@
                 loadExceptionC.setStateAfter(loadExceptionObject.stateAfter());
                 graph.replaceFixedWithFixed(loadExceptionObject, loadExceptionC);
             } else {
-                Arguments args = new Arguments(loadException);
+                Arguments args = new Arguments(loadException, loadExceptionObject.graph().getGuardsStage());
                 template(args).instantiate(runtime, loadExceptionObject, DEFAULT_REPLACER, args);
             }
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Oct 02 13:26:31 2013 +0200
@@ -405,9 +405,9 @@
 
             Arguments args;
             if (useFastLocking) {
-                args = new Arguments(monitorenter);
+                args = new Arguments(monitorenter, graph.getGuardsStage());
             } else {
-                args = new Arguments(monitorenterStub);
+                args = new Arguments(monitorenterStub, graph.getGuardsStage());
             }
             args.add("object", monitorenterNode.object());
             args.addConst("lockDepth", monitorenterNode.getLockDepth());
@@ -430,9 +430,9 @@
 
             Arguments args;
             if (useFastLocking) {
-                args = new Arguments(monitorexit);
+                args = new Arguments(monitorexit, graph.getGuardsStage());
             } else {
-                args = new Arguments(monitorexitStub);
+                args = new Arguments(monitorexitStub, graph.getGuardsStage());
             }
             args.add("object", monitorexitNode.object());
             args.addConst("lockDepth", monitorexitNode.getLockDepth());
@@ -507,7 +507,7 @@
                         invoke.setStateAfter(graph.add(stateAfter));
                         graph.addBeforeFixed(ret, invoke);
 
-                        Arguments args = new Arguments(checkCounter);
+                        Arguments args = new Arguments(checkCounter, graph.getGuardsStage());
                         args.addConst("errMsg", msg);
                         inlineeGraph = template(args).copySpecializedGraph();
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,11 +23,10 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.api.code.UnsignedMath.*;
-import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.nodes.PiArrayNode.*;
+import static com.oracle.graal.nodes.PiNode.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static com.oracle.graal.nodes.extended.UnsafeArrayCastNode.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 import static com.oracle.graal.replacements.nodes.ExplodeLoopNode.*;
@@ -35,6 +34,8 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+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.*;
@@ -56,6 +57,8 @@
  */
 public class NewObjectSnippets implements Snippets {
 
+    public static final LocationIdentity INIT_LOCATION = new NamedLocationIdentity("Initialization");
+
     @Snippet
     public static Word allocate(int size) {
         Word thread = thread();
@@ -87,8 +90,7 @@
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
         }
-        BeginNode anchorNode = BeginNode.anchor();
-        return unsafeCast(verifyOop(result), StampFactory.forNodeIntrinsic(), anchorNode);
+        return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
     }
 
     /**
@@ -121,8 +123,7 @@
             newarray_stub.inc();
             result = NewArrayStubCall.call(hub, length);
         }
-        BeginNode anchorNode = BeginNode.anchor();
-        return unsafeArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic(), anchorNode);
+        return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
     }
 
     public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class);
@@ -182,7 +183,7 @@
         Word dims = DimensionsNode.allocaDimsArray(rank);
         ExplodeLoopNode.explodeLoop();
         for (int i = 0; i < rank; i++) {
-            dims.writeInt(i * 4, dimensions[i], ANY_LOCATION);
+            dims.writeInt(i * 4, dimensions[i], INIT_LOCATION);
         }
         return NewMultiArrayStubCall.call(hub, rank, dims);
     }
@@ -204,12 +205,12 @@
                 new_seqInit.inc();
                 explodeLoop();
                 for (int offset = instanceHeaderSize(); offset < size; offset += wordSize()) {
-                    memory.writeWord(offset, Word.zero(), ANY_LOCATION);
+                    memory.writeWord(offset, Word.zero(), INIT_LOCATION);
                 }
             } else {
                 new_loopInit.inc();
                 for (int offset = instanceHeaderSize(); offset < size; offset += wordSize()) {
-                    memory.writeWord(offset, Word.zero(), ANY_LOCATION);
+                    memory.writeWord(offset, Word.zero(), INIT_LOCATION);
                 }
             }
         }
@@ -220,7 +221,7 @@
      * Formats some allocated memory with an object header and zeroes out the rest.
      */
     public static Object formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) {
-        memory.writeInt(arrayLengthOffset(), length, ANY_LOCATION);
+        memory.writeInt(arrayLengthOffset(), length, INIT_LOCATION);
         /*
          * store hub last as the concurrent garbage collectors assume length is valid if hub field
          * is not null
@@ -228,7 +229,7 @@
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
             for (int offset = headerSize; offset < allocationSize; offset += wordSize()) {
-                memory.writeWord(offset, Word.zero(), ANY_LOCATION);
+                memory.writeWord(offset, Word.zero(), INIT_LOCATION);
             }
         }
         return memory.toObject();
@@ -255,7 +256,7 @@
             ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph);
             int size = instanceSize(type);
 
-            Arguments args = new Arguments(allocateInstance);
+            Arguments args = new Arguments(allocateInstance, graph.getGuardsStage());
             args.addConst("size", size);
             args.add("hub", hub);
             args.add("prototypeMarkWord", type.prototypeMarkWord());
@@ -278,7 +279,7 @@
             final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind);
             int log2ElementSize = CodeUtil.log2(((HotSpotRuntime) runtime).getScalingFactor(elementKind));
 
-            Arguments args = new Arguments(allocateArray);
+            Arguments args = new Arguments(allocateArray, graph.getGuardsStage());
             args.add("hub", hub);
             args.add("length", newArrayNode.length());
             args.add("prototypeMarkWord", arrayType.prototypeMarkWord());
@@ -292,7 +293,7 @@
         }
 
         public void lower(DynamicNewArrayNode newArrayNode) {
-            Arguments args = new Arguments(allocateArrayDynamic);
+            Arguments args = new Arguments(allocateArrayDynamic, newArrayNode.graph().getGuardsStage());
             args.add("elementType", newArrayNode.getElementType());
             args.add("length", newArrayNode.length());
             args.addConst("fillContents", newArrayNode.fillContents());
@@ -311,7 +312,7 @@
             HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newmultiarrayNode.type();
             ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph);
 
-            Arguments args = new Arguments(newmultiarray);
+            Arguments args = new Arguments(newmultiarray, graph.getGuardsStage());
             args.add("hub", hub);
             args.addConst("rank", rank);
             args.addVarargs("dimensions", int.class, StampFactory.forKind(Kind.Int), dims);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,9 +25,11 @@
 import static com.oracle.graal.compiler.GraalCompiler.*;
 
 import java.lang.reflect.*;
+import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -51,7 +53,7 @@
     }
 
     @Override
-    protected StructuredGraph getSnippetGraph(LoweringTool tool) {
+    protected StructuredGraph getLoweredSnippetGraph(LoweringTool tool) {
         if (!shouldIntrinsify(getTargetMethod())) {
             return null;
         }
@@ -69,12 +71,18 @@
         } else {
             method = ObjectCloneSnippets.instanceCloneMethod;
         }
-        ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method);
-        Replacements replacements = tool.getReplacements();
-        StructuredGraph snippetGraph = replacements.getSnippet(snippetMethod);
+        final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method);
+        final Replacements replacements = tool.getReplacements();
+        StructuredGraph snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
+
+            @Override
+            public StructuredGraph call() throws Exception {
+                return replacements.getSnippet(snippetMethod);
+            }
+        });
 
         assert snippetGraph != null : "ObjectCloneSnippets should be installed";
-        return snippetGraph;
+        return lowerReplacement(snippetGraph.copy(), tool);
     }
 
     private static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,7 +29,6 @@
 
 import java.lang.reflect.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -56,9 +55,12 @@
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
         Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, false);
 
-        Pointer memory = Word.fromObject(result);
         for (int offset = instanceHeaderSize(); offset < instanceSize; offset += wordSize()) {
-            memory.writeWord(offset, Word.fromObject(src).readWord(offset, ANY_LOCATION), ANY_LOCATION);
+            /*
+             * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values
+             * to be copied atomically, but here they are copied as two 4-byte word values.
+             */
+            ObjectAccess.writeWord(result, offset, ObjectAccess.readWord(src, offset, ANY_LOCATION), ANY_LOCATION);
         }
 
         return result;
@@ -73,9 +75,12 @@
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
         Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, false);
 
-        Pointer memory = Word.fromObject(result);
         for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) {
-            memory.writeWord(offset, Word.fromObject(src).readWord(offset, ANY_LOCATION), ANY_LOCATION);
+            /*
+             * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values
+             * to be copied atomically, but here they are copied as two 4-byte word values.
+             */
+            ObjectAccess.writeWord(result, offset, ObjectAccess.readWord(src, offset, ANY_LOCATION), ANY_LOCATION);
         }
         return result;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
+import static com.oracle.graal.nodes.PiNode.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
@@ -41,7 +41,7 @@
     @MethodSubstitution(isStatic = false, forced = true)
     public static Class<?> getClass(final Object thisObj) {
         Word hub = loadHub(thisObj);
-        return unsafeCast(hub.readObject(Word.signed(classMirrorOffset()), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
+        return piCast(hub.readObject(Word.signed(classMirrorOffset()), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
     }
 
     @MethodSubstitution(isStatic = false)
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -47,13 +47,15 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         ConstantNode callerClassNode = getCallerClassNode(tool.getRuntime());
 
         if (callerClassNode != null) {
             graph().replaceFixedWithFloating(this, callerClassNode);
         } else {
-            graph().replaceFixedWithFixed(this, createInvoke());
+            InvokeNode invoke = createInvoke();
+            graph().replaceFixedWithFixed(this, invoke);
+            invoke.lower(tool);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -92,8 +92,8 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        if (loweringType == LoweringType.AFTER_FSA) {
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
             UnsafeArrayCopySnippets.Templates templates = tool.getReplacements().getSnippetTemplateCache(UnsafeArrayCopySnippets.Templates.class);
             templates.lower(this);
         }
@@ -112,11 +112,7 @@
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        if (elementKind == null) {
-            return ANY_LOCATION;
-        } else {
-            return NamedLocationIdentity.getArrayLocation(elementKind);
-        }
+        return ANY_LOCATION;
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopySnippets.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopySnippets.java	Wed Oct 02 13:26:31 2013 +0200
@@ -192,6 +192,11 @@
             }
         } else {
             for (long i = 0; i < byteLength; i += VECTOR_SIZE) {
+                /*
+                 * TODO atomicity problem on 32-bit architectures: The JVM spec requires double
+                 * values to be copied atomically, but not long values. For example, on Intel 32-bit
+                 * this code is not atomic as long as the vector kind remains Kind.Long.
+                 */
                 Long a = UnsafeLoadNode.load(src, arrayBaseOffset, i + srcOffset, VECTOR_KIND);
                 UnsafeStoreNode.store(dest, arrayBaseOffset, i + destOffset, a.longValue(), VECTOR_KIND);
             }
@@ -225,22 +230,22 @@
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
 
-        Word srcOffset = (Word) Word.fromObject(src).add(headerSize).add(srcPos << log2ElementSize);
-        Word destOffset = (Word) Word.fromObject(dest).add(headerSize).add(destPos << log2ElementSize);
-        Word destStart = destOffset;
-        long sizeInBytes = ((long) length) << log2ElementSize;
-        Word destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize));
+        Unsigned srcOffset = Word.unsigned(srcPos).shiftLeft(log2ElementSize).add(headerSize);
+        Unsigned destOffset = Word.unsigned(destPos).shiftLeft(log2ElementSize).add(headerSize);
+        Unsigned destStart = destOffset;
+        Unsigned sizeInBytes = Word.unsigned(length).shiftLeft(log2ElementSize);
+        Unsigned destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize));
 
-        int nonVectorBytes = (int) (sizeInBytes % VECTOR_SIZE);
-        Word destNonVectorEnd = destStart.add(nonVectorBytes);
+        Unsigned nonVectorBytes = sizeInBytes.unsignedRemainder(Word.unsigned(VECTOR_SIZE));
+        Unsigned destNonVectorEnd = destStart.add(nonVectorBytes);
 
         while (destOffset.belowThan(destNonVectorEnd)) {
-            destOffset.writeByte(0, srcOffset.readByte(0, ANY_LOCATION), ANY_LOCATION);
+            ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, ANY_LOCATION), ANY_LOCATION);
             destOffset = destOffset.add(1);
             srcOffset = srcOffset.add(1);
         }
         while (destOffset.belowThan(destEnd)) {
-            destOffset.writeWord(0, srcOffset.readWord(0, ANY_LOCATION), ANY_LOCATION);
+            ObjectAccess.writeWord(dest, destOffset, ObjectAccess.readWord(src, srcOffset, ANY_LOCATION), ANY_LOCATION);
             destOffset = destOffset.add(wordSize());
             srcOffset = srcOffset.add(wordSize());
         }
@@ -279,7 +284,7 @@
                 assert snippet != null : "arraycopy snippet for " + elementKind.name() + " not found";
             }
 
-            Arguments args = new Arguments(snippet);
+            Arguments args = new Arguments(snippet, node.graph().getGuardsStage());
             node.addSnippetArguments(args);
 
             SnippetTemplate template = template(args);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeLoadSnippets.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeLoadSnippets.java	Wed Oct 02 13:26:31 2013 +0200
@@ -58,7 +58,7 @@
         }
 
         public void lower(UnsafeLoadNode load, @SuppressWarnings("unused") LoweringTool tool) {
-            Arguments args = new Arguments(unsafeLoad);
+            Arguments args = new Arguments(unsafeLoad, load.graph().getGuardsStage());
             args.add("object", load.object());
             args.add("offset", load.offset());
             args.add("disp", load.displacement());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Wed Oct 02 13:26:31 2013 +0200
@@ -49,18 +49,20 @@
 public class WriteBarrierSnippets implements Snippets {
 
     private static final SnippetCounter.Group countersWriteBarriers = SnippetCounters.getValue() ? new SnippetCounter.Group("WriteBarriers") : null;
-    private static final SnippetCounter serialFieldWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialFieldWriteBarrier", "Number of Serial Field Write Barriers");
-    private static final SnippetCounter serialArrayWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialArrayWriteBarrier", "Number of Serial Array Write Barriers");
-    private static final SnippetCounter g1AttemptedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPostWriteBarrierCounter",
-                    "Number of attempted G1 Post Write Barriers");
-    private static final SnippetCounter g1AttemptedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPreWriteBarrierCounter", "Number of G1 attempted Pre Write Barriers");
-    private static final SnippetCounter g1AttemptedRefFieldBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedRefFieldBarrierCounter",
-                    "Number of G1 attempted Ref Field Read Barriers");
-    private static final SnippetCounter g1EffectivePostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectivePostWriteBarrierCounter",
-                    "Number of effective G1 Post Write Barriers");
-    private static final SnippetCounter g1EffectivePreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectivePreWriteBarrierCounter", "Number of G1 effective Pre Write Barriers");
-    private static final SnippetCounter g1EffectiveRefFieldBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveRefFieldBarrierCounter",
-                    "Number of G1 effective Ref Field Read Barriers");
+    private static final SnippetCounter serialWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialWriteBarrier", "Number of Serial Write Barriers");
+    private static final SnippetCounter g1AttemptedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPreWriteBarrier", "Number of G1 attempted Pre Write Barriers");
+    private static final SnippetCounter g1EffectivePreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectivePreWriteBarrier", "Number of G1 effective Pre Write Barriers");
+    private static final SnippetCounter g1ExecutedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPreWriteBarrier", "Number of G1 executed Pre Write Barriers");
+    private static final SnippetCounter g1AttemptedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPostWriteBarrier", "Number of attempted G1 Post Write Barriers");
+    private static final SnippetCounter g1EffectiveAfterXORPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterXORPostWriteBarrier",
+                    "Number of effective G1 Post Write Barriers (after passing the XOR test)");
+    private static final SnippetCounter g1EffectiveAfterNullPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterNullPostWriteBarrier",
+                    "Number of effective G1 Post Write Barriers (after passing the NULL test)");
+    private static final SnippetCounter g1ExecutedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPostWriteBarrier", "Number of executed G1 Post Write Barriers");
+
+    public static final LocationIdentity GC_CARD_LOCATION = new NamedLocationIdentity("GC-Card");
+    public static final LocationIdentity GC_LOG_LOCATION = new NamedLocationIdentity("GC-Log");
+    public static final LocationIdentity GC_INDEX_LOCATION = new NamedLocationIdentity("GC-Index");
 
     @Snippet
     public static void serialWriteBarrier(Object object, Object location, @ConstantParameter boolean usePrecise, @ConstantParameter boolean alwaysNull) {
@@ -72,11 +74,10 @@
         Pointer oop;
         if (usePrecise) {
             oop = Word.fromArray(fixedObject, location);
-            serialArrayWriteBarrierCounter.inc();
         } else {
             oop = Word.fromObject(fixedObject);
-            serialFieldWriteBarrierCounter.inc();
         }
+        serialWriteBarrierCounter.inc();
         Word base = (Word) oop.unsignedShiftRight(cardTableShift());
         long startAddress = cardTableStart();
         int displacement = 0;
@@ -85,7 +86,7 @@
         } else {
             base = base.add(Word.unsigned(cardTableStart()));
         }
-        base.writeByte(displacement, (byte) 0);
+        base.writeByte(displacement, (byte) 0, GC_CARD_LOCATION);
     }
 
     @Snippet
@@ -132,8 +133,9 @@
             log(trace, "[%d] G1-Pre Thread %p Marking %d\n", gcCycle, thread.rawValue(), markingValue);
             log(trace, "[%d] G1-Pre Thread %p DoLoad %d\n", gcCycle, thread.rawValue(), doLoad ? 1L : 0L);
         }
+        g1AttemptedPreWriteBarrierCounter.inc();
         // If the concurrent marker is enabled, the barrier is issued.
-        if (probability(NOT_LIKELY_PROBABILITY, markingValue != (byte) 0)) {
+        if (probability(NOT_FREQUENT_PROBABILITY, markingValue != (byte) 0)) {
             // If the previous value has to be loaded (before the write), the load is issued.
             // The load is always issued except the cases of CAS and referent field.
             if (probability(LIKELY_PROBABILITY, doLoad)) {
@@ -142,25 +144,19 @@
                     log(trace, "[%d] G1-Pre Thread %p Previous Object %p\n ", gcCycle, thread.rawValue(), previousOop.rawValue());
                     verifyOop(previousOop.toObject());
                 }
-                g1AttemptedPreWriteBarrierCounter.inc();
-            } else {
-                g1AttemptedRefFieldBarrierCounter.inc();
             }
+            g1EffectivePreWriteBarrierCounter.inc();
             // If the previous value is null the barrier should not be issued.
             if (probability(FREQUENT_PROBABILITY, previousOop.notEqual(0))) {
-                if (doLoad) {
-                    g1EffectivePreWriteBarrierCounter.inc();
-                } else {
-                    g1EffectiveRefFieldBarrierCounter.inc();
-                }
+                g1ExecutedPreWriteBarrierCounter.inc();
                 // If the thread-local SATB buffer is full issue a native call which will
                 // initialize a new one and add the entry.
                 if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
                     Word nextIndex = indexValue.subtract(wordSize());
                     Word logAddress = bufferAddress.add(nextIndex);
                     // Log the object to be marked as well as update the SATB's buffer next index.
-                    logAddress.writeWord(0, previousOop);
-                    indexAddress.writeWord(0, nextIndex);
+                    logAddress.writeWord(0, previousOop, GC_LOG_LOCATION);
+                    indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION);
                 } else {
                     g1PreBarrierStub(G1WBPRECALL, previousOop.toObject());
                 }
@@ -213,15 +209,20 @@
         Word cardAddress = cardBase.add(displacement);
 
         g1AttemptedPostWriteBarrierCounter.inc();
-        if (probability(LIKELY_PROBABILITY, xorResult.notEqual(0))) {
+        if (probability(FREQUENT_PROBABILITY, xorResult.notEqual(0))) {
+            g1EffectiveAfterXORPostWriteBarrierCounter.inc();
+
             // If the written value is not null continue with the barrier addition.
             if (probability(FREQUENT_PROBABILITY, writtenValue.notEqual(0))) {
                 byte cardByte = cardAddress.readByte(0);
+                g1EffectiveAfterNullPostWriteBarrierCounter.inc();
+
                 // If the card is already dirty, (hence already enqueued) skip the insertion.
-                if (probability(LIKELY_PROBABILITY, cardByte != (byte) 0)) {
-                    g1EffectivePostWriteBarrierCounter.inc();
+                if (probability(NOT_FREQUENT_PROBABILITY, cardByte != (byte) 0)) {
                     log(trace, "[%d] G1-Post Thread: %p Card: %p \n", gcCycle, thread.rawValue(), Word.unsigned(cardByte).rawValue());
-                    cardAddress.writeByte(0, (byte) 0);
+                    cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION);
+                    g1ExecutedPostWriteBarrierCounter.inc();
+
                     // If the thread local card queue is full, issue a native call which will
                     // initialize a new one and add the card entry.
                     if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
@@ -229,8 +230,8 @@
                         Word logAddress = bufferAddress.add(nextIndex);
                         // Log the object to be scanned as well as update
                         // the card queue's next index.
-                        logAddress.writeWord(0, cardAddress);
-                        indexAddress.writeWord(0, nextIndex);
+                        logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION);
+                        indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION);
                     } else {
                         g1PostBarrierStub(G1WBPOSTCALL, cardAddress);
                     }
@@ -264,8 +265,8 @@
                     indexValue = indexValue - wordSize();
                     Word logAddress = bufferAddress.add(Word.unsigned(indexValue));
                     // Log the object to be marked as well as update the SATB's buffer next index.
-                    logAddress.writeWord(0, oop);
-                    indexAddress.writeWord(0, Word.unsigned(indexValue));
+                    logAddress.writeWord(0, oop, GC_LOG_LOCATION);
+                    indexAddress.writeWord(0, Word.unsigned(indexValue), GC_INDEX_LOCATION);
                 } else {
                     g1PreBarrierStub(G1WBPRECALL, oop.toObject());
                 }
@@ -298,7 +299,7 @@
             byte cardByte = cardAddress.readByte(0);
             // If the card is already dirty, (hence already enqueued) skip the insertion.
             if (cardByte != (byte) 0) {
-                cardAddress.writeByte(0, (byte) 0);
+                cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION);
                 // If the thread local card queue is full, issue a native call which will
                 // initialize a new one and add the card entry.
                 if (indexValue != 0) {
@@ -306,8 +307,8 @@
                     Word logAddress = bufferAddress.add(Word.unsigned(indexValue));
                     // Log the object to be scanned as well as update
                     // the card queue's next index.
-                    logAddress.writeWord(0, cardAddress);
-                    indexAddress.writeWord(0, Word.unsigned(indexValue));
+                    logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION);
+                    indexAddress.writeWord(0, Word.unsigned(indexValue), GC_INDEX_LOCATION);
                 } else {
                     g1PostBarrierStub(G1WBPOSTCALL, cardAddress);
                 }
@@ -340,7 +341,7 @@
         }
 
         public void lower(SerialWriteBarrier writeBarrier, @SuppressWarnings("unused") LoweringTool tool) {
-            Arguments args = new Arguments(serialWriteBarrier);
+            Arguments args = new Arguments(serialWriteBarrier, writeBarrier.graph().getGuardsStage());
             args.add("object", writeBarrier.getObject());
             args.add("location", writeBarrier.getLocation());
             args.addConst("usePrecise", writeBarrier.usePrecise());
@@ -349,7 +350,7 @@
         }
 
         public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) {
-            Arguments args = new Arguments(serialArrayRangeWriteBarrier);
+            Arguments args = new Arguments(serialArrayRangeWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage());
             args.add("object", arrayRangeWriteBarrier.getObject());
             args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
             args.add("length", arrayRangeWriteBarrier.getLength());
@@ -357,7 +358,7 @@
         }
 
         public void lower(G1PreWriteBarrier writeBarrierPre, @SuppressWarnings("unused") LoweringTool tool) {
-            Arguments args = new Arguments(g1PreWriteBarrier);
+            Arguments args = new Arguments(g1PreWriteBarrier, writeBarrierPre.graph().getGuardsStage());
             args.add("object", writeBarrierPre.getObject());
             args.add("expectedObject", writeBarrierPre.getExpectedObject());
             args.add("location", writeBarrierPre.getLocation());
@@ -368,7 +369,7 @@
         }
 
         public void lower(G1ReferentFieldReadBarrier readBarrier, @SuppressWarnings("unused") LoweringTool tool) {
-            Arguments args = new Arguments(g1ReferentReadBarrier);
+            Arguments args = new Arguments(g1ReferentReadBarrier, readBarrier.graph().getGuardsStage());
             args.add("object", readBarrier.getObject());
             args.add("expectedObject", readBarrier.getExpectedObject());
             args.add("location", readBarrier.getLocation());
@@ -379,7 +380,7 @@
         }
 
         public void lower(G1PostWriteBarrier writeBarrierPost, @SuppressWarnings("unused") LoweringTool tool) {
-            Arguments args = new Arguments(g1PostWriteBarrier);
+            Arguments args = new Arguments(g1PostWriteBarrier, writeBarrierPost.graph().getGuardsStage());
             args.add("object", writeBarrierPost.getObject());
             args.add("value", writeBarrierPost.getValue());
             args.add("location", writeBarrierPost.getLocation());
@@ -390,7 +391,7 @@
         }
 
         public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) {
-            Arguments args = new Arguments(g1ArrayRangePreWriteBarrier);
+            Arguments args = new Arguments(g1ArrayRangePreWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage());
             args.add("object", arrayRangeWriteBarrier.getObject());
             args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
             args.add("length", arrayRangeWriteBarrier.getLength());
@@ -398,7 +399,7 @@
         }
 
         public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) {
-            Arguments args = new Arguments(g1ArrayRangePostWriteBarrier);
+            Arguments args = new Arguments(g1ArrayRangePostWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage());
             args.add("object", arrayRangeWriteBarrier.getObject());
             args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
             args.add("length", arrayRangeWriteBarrier.getLength());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,6 +29,7 @@
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.lang.reflect.*;
+import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -223,13 +224,16 @@
         boolean isObjectResult = linkage.getOutgoingCallingConvention().getReturn().getKind() == Kind.Object;
         GraphBuilder builder = new GraphBuilder(this);
         LocalNode[] locals = createLocals(builder, args);
+        List<InvokeNode> invokes = new ArrayList<>(3);
 
         ReadRegisterNode thread = prependThread || isObjectResult ? builder.append(new ReadRegisterNode(runtime.threadRegister(), true, false)) : null;
         ValueNode result = createTargetCall(builder, locals, thread);
-        createInvoke(builder, StubUtil.class, "handlePendingException", ConstantNode.forBoolean(isObjectResult, builder.graph));
+        invokes.add(createInvoke(builder, StubUtil.class, "handlePendingException", ConstantNode.forBoolean(isObjectResult, builder.graph)));
         if (isObjectResult) {
             InvokeNode object = createInvoke(builder, HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread);
             result = createInvoke(builder, StubUtil.class, "verifyObject", object);
+            invokes.add(object);
+            invokes.add((InvokeNode) result);
         }
         builder.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
 
@@ -237,10 +241,15 @@
             Debug.dump(builder.graph, "Initial stub graph");
         }
 
-        for (InvokeNode invoke : builder.graph.getNodes(InvokeNode.class).snapshot()) {
+        /* Rewrite all word types that can come in from the method argument types. */
+        new WordTypeRewriterPhase(runtime, wordKind()).apply(builder.graph);
+        /* Inline all method calls that are create above. */
+        for (InvokeNode invoke : invokes) {
             inline(invoke);
         }
-        assert builder.graph.getNodes(InvokeNode.class).isEmpty();
+        /* Clean up all code that is now dead after inlining. */
+        new DeadCodeEliminationPhase().apply(builder.graph);
+        assert builder.graph.getNodes().filter(InvokeNode.class).isEmpty();
 
         if (Debug.isDumpEnabled()) {
             Debug.dump(builder.graph, "Stub graph before compilation");
@@ -294,13 +303,9 @@
     }
 
     private void inline(InvokeNode invoke) {
-        StructuredGraph graph = invoke.graph();
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
         ReplacementsImpl repl = new ReplacementsImpl(runtime, new Assumptions(false), runtime.getTarget());
         StructuredGraph calleeGraph = repl.makeGraph(method, null, null);
         InliningUtil.inline(invoke, calleeGraph, false);
-        new NodeIntrinsificationPhase(runtime).apply(graph);
-        new WordTypeRewriterPhase(runtime, wordKind()).apply(graph);
-        new DeadCodeEliminationPhase().apply(graph);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,6 +36,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.nodes.StructuredGraph.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
@@ -66,7 +67,7 @@
         Constant intArrayHub = intArrayType.klass();
         intArrayHub = Constant.forIntegerKind(graalRuntime().getTarget().wordKind, intArrayHub.asLong(), null);
 
-        Arguments args = new Arguments(stub);
+        Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS);
         args.add("hub", null);
         args.add("length", null);
         args.addConst("intArrayHub", intArrayHub);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Wed Oct 02 13:26:31 2013 +0200
@@ -37,6 +37,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.nodes.StructuredGraph.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
@@ -67,7 +68,7 @@
         Constant intArrayHub = intArrayType.klass();
         intArrayHub = Constant.forIntegerKind(graalRuntime().getTarget().wordKind, intArrayHub.asLong(), null);
 
-        Arguments args = new Arguments(stub);
+        Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS);
         args.add("hub", null);
         args.addConst("intArrayHub", intArrayHub);
         return args;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
@@ -79,7 +80,7 @@
      * Adds the arguments to this snippet stub.
      */
     protected Arguments makeArguments(SnippetInfo stub) {
-        Arguments args = new Arguments(stub);
+        Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS);
         for (int i = 0; i < stub.getParameterCount(); i++) {
             args.add(stub.getParameterName(i), null);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
-import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.CStringNode.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAILRegisterConfig.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,188 @@
+/*
+ * 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.hsail;
+
+import com.oracle.graal.api.code.*;
+
+import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+
+import static com.oracle.graal.hsail.HSAIL.*;
+
+/**
+ * This class defines a higher level interface for the register allocator to be able to access info
+ * about the {@link HSAIL} register set.
+ * 
+ * Note: In HSAIL, the number of registers of each type is actually a variable number that must
+ * satisfy the equation: Total num of registers = No. of S registers + 2 * (No. of D registers) + 4
+ * * (No. of Q registers) = 128 In other words we can have up to 128S or 64 D or 32Q or a blend.
+ * 
+ * For now we haven't implemented support for a variable sized register file. Instead we've fixed
+ * the number of registers of each type so that they satisfy the above equation. See {@link HSAIL}
+ * for more details.
+ */
+public class HSAILRegisterConfig implements RegisterConfig {
+
+    private final Register[] allocatable = {s0, s1, s2, s3, s4, s5, s6, /* s7, */s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, s21, s22, s23, s24, s25, s26, s27, s28, s29, s30, s31,
+                    d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14, q15};
+
+    private final Register[] regBitness32 = {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, s21, s22, s23, s24, s25, s26, s27, s28, s29, s30, s31};
+    private final Register[] regBitness64 = {d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15};
+    private final RegisterAttributes[] attributesMap = RegisterAttributes.createMap(this, HSAIL.allRegisters);
+
+    @Override
+    public Register getReturnRegister(Kind kind) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+            case Char:
+            case Short:
+            case Int:
+            case Long:
+            case Object:
+                return s0;
+            case Float:
+            case Double:
+                return d0;
+            case Void:
+            case Illegal:
+                return null;
+            default:
+                throw new UnsupportedOperationException("no return register for type " + kind);
+        }
+    }
+
+    @Override
+    public Register getFrameRegister() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) {
+        return callingConvention(regBitness32, regBitness64, returnType, parameterTypes, type, target, stackOnly);
+    }
+
+    private CallingConvention callingConvention(Register[] generalParameterRegisters, Register[] longParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type,
+                    TargetDescription target, boolean stackOnly) {
+        AllocatableValue[] locations = new AllocatableValue[parameterTypes.length];
+
+        int currentRegs32 = 0;
+        int currentRegs64 = 0;
+        int currentStackOffset = 0;
+
+        for (int i = 0; i < parameterTypes.length; i++) {
+            final Kind kind = parameterTypes[i].getKind();
+
+            switch (kind) {
+                case Byte:
+                case Boolean:
+                case Short:
+                case Char:
+                case Int:
+                case Float:
+
+                    if (!stackOnly && currentRegs32 < generalParameterRegisters.length) {
+                        Register register = generalParameterRegisters[currentRegs32++];
+                        locations[i] = register.asValue(kind);
+                    }
+                    break;
+                case Long:
+                case Object:
+                case Double:
+                    if (!stackOnly && currentRegs64 < longParameterRegisters.length) {
+                        Register register = longParameterRegisters[currentRegs64++];
+                        locations[i] = register.asValue(kind);
+                    }
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+
+            if (locations[i] == null) {
+                locations[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, !type.out);
+                currentStackOffset += Math.max(target.arch.getSizeInBytes(kind), target.wordSize);
+            }
+        }
+
+        Kind returnKind = returnType == null ? Kind.Void : returnType.getKind();
+        AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(returnKind);
+        return new CallingConvention(currentStackOffset, returnLocation, locations);
+    }
+
+    @Override
+    public Register[] getCallingConventionRegisters(Type type, Kind kind) {
+        throw new GraalInternalError("getCallingConventinoRegisters unimplemented");
+    }
+
+    @Override
+    public Register[] getAllocatableRegisters() {
+        return allocatable.clone();
+    }
+
+    @Override
+    public Register[] getAllocatableRegisters(PlatformKind kind) {
+        Kind k = (Kind) kind;
+        switch (k) {
+            case Int:
+            case Short:
+            case Byte:
+            case Float:
+                return regBitness32.clone();
+            case Long:
+            case Double:
+            case Object:
+                return regBitness64.clone();
+
+            default:
+                throw new GraalInternalError("unknown register allocation");
+        }
+    }
+
+    @Override
+    public Register[] getCallerSaveRegisters() {
+        // TODO Auto-generated method stub
+        return new Register[0];
+    }
+
+    @Override
+    public CalleeSaveLayout getCalleeSaveLayout() {
+        return null;
+    }
+
+    @Override
+    public RegisterAttributes[] getAttributesMap() {
+        return attributesMap.clone();
+    }
+
+    @Override
+    public Register getRegisterForRole(int id) {
+        throw new UnsupportedOperationException();
+    }
+
+    public HSAILRegisterConfig() {
+
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Wed Oct 02 13:26:31 2013 +0200
@@ -195,7 +195,7 @@
                 return null;
             }
 
-            PhiNode phi = graph.add(new PhiNode(currentValue.kind(), block));
+            PhiNode phi = graph.addWithoutUnique(new PhiNode(currentValue.kind(), block));
             for (int i = 0; i < block.phiPredecessorCount(); i++) {
                 phi.addInput(currentValue);
             }
@@ -293,7 +293,7 @@
         }
         assert !block.isPhiAtMerge(value) : "phi function for this block already created";
 
-        PhiNode phi = graph.add(new PhiNode(value.kind(), block));
+        PhiNode phi = graph.addWithoutUnique(new PhiNode(value.kind(), block));
         phi.addInput(value);
         return phi;
     }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,8 +22,8 @@
  */
 package com.oracle.graal.java;
 
-import static com.oracle.graal.api.code.DeoptimizationAction.*;
 import static com.oracle.graal.api.code.TypeCheckHints.*;
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
 import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*;
@@ -50,7 +50,6 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.util.*;
 
 /**
  * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph.
@@ -81,6 +80,11 @@
 
     protected StructuredGraph currentGraph;
 
+    /**
+     * Head of placeholder list.
+     */
+    protected BlockPlaceholderNode placeholders;
+
     private final MetaAccessProvider runtime;
     private ConstantPool constantPool;
     private ResolvedJavaMethod method;
@@ -109,13 +113,24 @@
     /**
      * Node that marks the begin of block during bytecode parsing. When a block is identified the
      * first time as a jump target, the placeholder is created and used as the successor for the
-     * jump. When the block is seen the second time, a MergeNode is created to correctly merge the
-     * now two different predecessor states.
+     * jump. When the block is seen the second time, a {@link MergeNode} is created to correctly
+     * merge the now two different predecessor states.
      */
-    private static class BlockPlaceholderNode extends FixedWithNextNode implements Node.IterableNodeType {
+    private static class BlockPlaceholderNode extends FixedWithNextNode {
+
+        // Cannot be explicitly declared as a Node type since it is not an input;
+        // would cause the !NODE_CLASS.isAssignableFrom(type) guarantee
+        // in NodeClass.FieldScanner.scanField() to fail.
+        private final Object nextPlaceholder;
 
-        public BlockPlaceholderNode() {
+        public BlockPlaceholderNode(GraphBuilderPhase builder) {
             super(StampFactory.forVoid());
+            nextPlaceholder = builder.placeholders;
+            builder.placeholders = this;
+        }
+
+        BlockPlaceholderNode nextPlaceholder() {
+            return (BlockPlaceholderNode) nextPlaceholder;
         }
     }
 
@@ -200,17 +215,14 @@
             lastInstr = genMonitorEnter(methodSynchronizedObject);
         }
         frameState.clearNonLiveLocals(blockMap.startBlock.localsLiveIn);
+        ((StateSplit) lastInstr).setStateAfter(frameState.create(0));
 
         if (graphBuilderConfig.eagerInfopointMode()) {
-            ((StateSplit) lastInstr).setStateAfter(frameState.create(0));
-            InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_START));
+            InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_START, frameState.create(0)));
             lastInstr.setNext(ipn);
             lastInstr = ipn;
         }
 
-        // finish the start block
-        ((StateSplit) lastInstr).setStateAfter(frameState.create(0));
-
         currentBlock = blockMap.startBlock;
         blockMap.startBlock.entryState = frameState;
         if (blockMap.startBlock.isLoopHeader) {
@@ -236,9 +248,12 @@
         connectLoopEndToBegin();
 
         // remove Placeholders
-        for (BlockPlaceholderNode n : currentGraph.getNodes(BlockPlaceholderNode.class)) {
-            currentGraph.removeFixed(n);
+        for (BlockPlaceholderNode n = placeholders; n != null; n = n.nextPlaceholder()) {
+            if (!n.isDeleted()) {
+                currentGraph.removeFixed(n);
+            }
         }
+        placeholders = null;
 
         // remove dead FrameStates
         for (Node n : currentGraph.getNodes(FrameState.class)) {
@@ -305,6 +320,7 @@
      * @param type the unresolved type of the constant
      */
     protected void handleUnresolvedLoadConstant(JavaType type) {
+        assert !graphBuilderConfig.eagerResolving();
         append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         frameState.push(Kind.Object, appendConstant(Constant.NULL_OBJECT));
     }
@@ -314,6 +330,7 @@
      * @param object the object value whose type is being checked against {@code type}
      */
     protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) {
+        assert !graphBuilderConfig.eagerResolving();
         append(new FixedGuardNode(currentGraph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
@@ -323,7 +340,8 @@
      * @param object the object value whose type is being checked against {@code type}
      */
     protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) {
-        BlockPlaceholderNode successor = currentGraph.add(new BlockPlaceholderNode());
+        assert !graphBuilderConfig.eagerResolving();
+        BlockPlaceholderNode successor = currentGraph.add(new BlockPlaceholderNode(this));
         DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         append(new IfNode(currentGraph.unique(new IsNullNode(object)), successor, deopt, 1));
         lastInstr = successor;
@@ -334,6 +352,7 @@
      * @param type the type being instantiated
      */
     protected void handleUnresolvedNewInstance(JavaType type) {
+        assert !graphBuilderConfig.eagerResolving();
         append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
@@ -343,6 +362,7 @@
      * @param length the length of the array
      */
     protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) {
+        assert !graphBuilderConfig.eagerResolving();
         append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
@@ -352,6 +372,7 @@
      * @param dims the dimensions for the multi-array
      */
     protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) {
+        assert !graphBuilderConfig.eagerResolving();
         append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
@@ -361,6 +382,7 @@
      * @param receiver the object containing the field or {@code null} if {@code field} is static
      */
     protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) {
+        assert !graphBuilderConfig.eagerResolving();
         Kind kind = field.getKind();
         append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         frameState.push(kind.getStackKind(), appendConstant(Constant.defaultForKind(kind)));
@@ -372,6 +394,7 @@
      * @param receiver the object containing the field or {@code null} if {@code field} is static
      */
     protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) {
+        assert !graphBuilderConfig.eagerResolving();
         append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
     }
 
@@ -380,10 +403,12 @@
      * @param type
      */
     protected void handleUnresolvedExceptionType(Representation representation, JavaType type) {
+        assert !graphBuilderConfig.eagerResolving();
         append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
     }
 
     protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) {
+        assert !graphBuilderConfig.eagerResolving();
         boolean withReceiver = invokeKind != InvokeKind.Static;
         append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         frameState.popArguments(javaMethod.getSignature().getParameterSlots(withReceiver), javaMethod.getSignature().getParameterCount(withReceiver));
@@ -925,8 +950,8 @@
         if (ObjectStamp.isObjectNonNull(receiver.stamp())) {
             return;
         }
-        BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode());
-        BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode());
+        BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode(this));
+        BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode(this));
         append(new IfNode(currentGraph.unique(new IsNullNode(receiver)), trueSucc, falseSucc, 0.01));
         lastInstr = falseSucc;
 
@@ -949,8 +974,8 @@
     }
 
     private void emitBoundsCheck(ValueNode index, ValueNode length) {
-        BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode());
-        BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode());
+        BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode(this));
+        BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode(this));
         append(new IfNode(currentGraph.unique(new IntegerBelowThanNode(index, length)), trueSucc, falseSucc, 0.99));
         lastInstr = trueSucc;
 
@@ -1147,7 +1172,7 @@
         }
         if (invokeKind != InvokeKind.Static) {
             emitExplicitExceptions(args[0], null);
-            if (invokeKind != InvokeKind.Special) {
+            if (invokeKind != InvokeKind.Special && this.optimisticOpts.useTypeCheckHints()) {
                 JavaTypeProfile profile = profilingInfo.getTypeProfile(bci());
                 args[0] = TypeProfileProxyNode.create(args[0], profile);
             }
@@ -1448,7 +1473,7 @@
             // This is the first time we see this block as a branch target.
             // Create and return a placeholder that later can be replaced with a MergeNode when we
             // see this block again.
-            block.firstInstruction = currentGraph.add(new BlockPlaceholderNode());
+            block.firstInstruction = currentGraph.add(new BlockPlaceholderNode(this));
             Target target = checkLoopExit(block.firstInstruction, block, state);
             FixedNode result = target.fixed;
             block.entryState = target.state == state ? state.copy() : target.state;
@@ -1601,19 +1626,13 @@
         ValueNode x = returnKind == Kind.Void ? null : frameState.pop(returnKind);
         assert frameState.stackSize() == 0;
 
-        if (Modifier.isSynchronized(method.getModifiers())) {
-            append(new ValueAnchorNode(true, x));
-            assert !frameState.rethrowException();
-        }
-
         synchronizedEpilogue(FrameState.AFTER_BCI);
         if (frameState.lockDepth() != 0) {
             throw new BailoutException("unbalanced monitors");
         }
 
         if (graphBuilderConfig.eagerInfopointMode()) {
-            InfopointNode ipn = append(new InfopointNode(InfopointReason.METHOD_END));
-            ipn.setStateAfter(frameState.create(FrameState.AFTER_BCI));
+            append(new InfopointNode(InfopointReason.METHOD_END, frameState.create(FrameState.AFTER_BCI)));
         }
 
         append(new ReturnNode(x));
@@ -1643,9 +1662,9 @@
         if (initialized && graphBuilderConfig.getSkippedExceptionTypes() != null) {
             ResolvedJavaType resolvedCatchType = (ResolvedJavaType) catchType;
             for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) {
-                initialized &= !skippedType.isAssignableFrom(resolvedCatchType);
-                if (!initialized) {
-                    break;
+                if (skippedType.isAssignableFrom(resolvedCatchType)) {
+                    append(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
+                    return;
                 }
             }
         }
@@ -1673,20 +1692,7 @@
     }
 
     private static boolean isBlockEnd(Node n) {
-        return trueSuccessorCount(n) > 1 || n instanceof ReturnNode || n instanceof UnwindNode || n instanceof DeoptimizeNode;
-    }
-
-    private static int trueSuccessorCount(Node n) {
-        if (n == null) {
-            return 0;
-        }
-        int i = 0;
-        for (Node s : n.successors()) {
-            if (Util.isFixed(s)) {
-                i++;
-            }
-        }
-        return i;
+        return n instanceof ControlSplitNode || n instanceof ControlSinkNode;
     }
 
     private void iterateBytecodesForBlock(Block block) {
@@ -1728,8 +1734,7 @@
             if (graphBuilderConfig.eagerInfopointMode() && lnt != null) {
                 currentLineNumber = lnt.getLineNumber(bci);
                 if (currentLineNumber != previousLineNumber) {
-                    InfopointNode ipn = append(new InfopointNode(InfopointReason.LINE_NUMBER));
-                    ipn.setStateAfter(frameState.create(bci));
+                    append(new InfopointNode(InfopointReason.LINE_NUMBER, frameState.create(bci)));
                     previousLineNumber = currentLineNumber;
                 }
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/ArrayCopyGeneric.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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 com.oracle.graal.jtt.*;
+
+import org.junit.*;
+
+/*
+ * Tests calls to the array copy method.
+ */
+public class ArrayCopyGeneric extends JTTTest {
+
+    public Object[] arraysFrom;
+    public Object[] arraysTo;
+
+    public void init() {
+        arraysFrom = new Object[]{new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
+                        new long[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new float[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}};
+        arraysTo = new Object[]{new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
+                        new long[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new float[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}};
+    }
+
+    public Object test() {
+        init();
+
+        for (int i = 0; i < arraysFrom.length; i++) {
+            Object from = arraysFrom[i];
+            Object to = arraysTo[i];
+            System.arraycopy(from, 1, to, 2, 2);
+            System.arraycopy(from, 8, to, 7, 2);
+        }
+        return arraysTo;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.spi.*;
@@ -182,6 +183,14 @@
         masm.ensureUniquePC();
     }
 
+    public static void directConditionalJmp(TargetMethodAssembler tasm, AMD64MacroAssembler masm, InvokeTarget target, ConditionFlag cond) {
+        int before = masm.codeBuffer.position();
+        masm.jcc(cond, 0, true);
+        int after = masm.codeBuffer.position();
+        tasm.recordDirectCall(before, after, target, null);
+        masm.ensureUniquePC();
+    }
+
     public static void indirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
         int before = masm.codeBuffer.position();
         masm.call(dst);
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,12 +28,12 @@
 
 /**
  * AMD64 specific frame map.
- * 
+ *
  * This is the format of an AMD64 stack frame:
- * 
+ *
  * <pre>
  *   Base       Contents
- * 
+ *
  *            :                                :  -----
  *   caller   | incoming overflow argument n   |    ^
  *   frame    :     ...                        :    | positive
@@ -55,9 +55,9 @@
  *            :     ...                        :    | positive   |      |
  *            | outgoing overflow argument 0   |    | offsets    v      v
  *    %sp-->  +--------------------------------+---------------------------
- * 
+ *
  * </pre>
- * 
+ *
  * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size of such
  * a block may be greater than the size of a normal spill slot or the word size.
  * <p>
@@ -67,7 +67,7 @@
  * call-free methods also have this space reserved. Then the VM can use the memory at offset 0
  * relative to the stack pointer.
  */
-public final class AMD64FrameMap extends FrameMap {
+public class AMD64FrameMap extends FrameMap {
 
     public AMD64FrameMap(CodeCacheProvider runtime, TargetDescription target, RegisterConfig registerConfig) {
         super(runtime, target, registerConfig);
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILAddressValue.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILAddressValue.java	Wed Oct 02 13:26:31 2013 +0200
@@ -66,7 +66,7 @@
     }
 
     public HSAILAddress toAddress() {
-        Register baseReg = base == Value.ILLEGAL ? Register.None : asRegister(base);
+        Register baseReg = base.equals(Value.ILLEGAL) ? Register.None : asRegister(base);
         return new HSAILAddress(baseReg, displacement);
     }
 
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,7 +25,6 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.ptx.*;
 import com.oracle.graal.lir.*;
@@ -69,8 +68,8 @@
     }
 
     public PTXAddress toAddress() {
-        Register baseReg = base == Value.ILLEGAL ? Register.None : asRegister(base);
-        return new PTXAddress(baseReg, displacement);
+        // Register baseReg = base == Value.ILLEGAL ? Register.None : asRegister(base);
+        return new PTXAddress((Variable) base, displacement);
     }
 
     @Override
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,9 @@
  */
 package com.oracle.graal.lir.ptx;
 
+import static com.oracle.graal.asm.ptx.PTXAssembler.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import com.oracle.graal.api.meta.*;
@@ -61,7 +63,22 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            PTXMove.move(tasm, masm, result, x);
+            switch (opcode) {
+                case I2L:
+                case I2C:
+                case I2B:
+                case I2F:
+                case I2D:
+                case F2I:
+                case F2L:
+                case F2D:
+                case D2I:
+                case D2L:
+                case D2F:
+                    break;  // cvt handles the move
+                default:
+                    PTXMove.move(tasm, masm, result, x);
+            }
             emit(tasm, masm, opcode, result, x, null);
         }
     }
@@ -255,9 +272,15 @@
 
     protected static void emit(@SuppressWarnings("unused") TargetMethodAssembler tasm,
                                PTXAssembler masm, PTXArithmetic opcode, Value result) {
+
+        Variable var = (Variable) result;
         switch (opcode) {
-        case L2I:  masm.and_b32(asIntReg(result), asIntReg(result), 0xFFFFFFFF); break;
-        case I2C:  masm.and_b16(asIntReg(result), asIntReg(result), (short) 0xFFFF); break;
+            case L2I:
+                new And(var, var, Constant.forLong(0xFFFFFFFF)).emit(masm);
+                break;
+            case I2C:
+                new And(var, var, Constant.forInt((short) 0xFFFF)).emit(masm);
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: "  + opcode);
         }
@@ -265,74 +288,60 @@
 
     public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value dst, Value src, LIRFrameState info) {
         int exceptionOffset = -1;
-        if (isRegister(src)) {
+        Variable dest = (Variable) dst;
+
+        if (isVariable(src)) {
+            Variable source = (Variable) src;
             switch (opcode) {
                 case INEG:
-                    masm.neg_s32(asIntReg(dst), asIntReg(src));
+                case FNEG:
+                case DNEG:
+                    new Neg(dest, source).emit(masm);
                     break;
                 case INOT:
-                    masm.not_s32(asIntReg(dst), asIntReg(src));
-                    break;
                 case LNOT:
-                    masm.not_s64(asLongReg(dst), asLongReg(src));
+                    new Not(dest, source).emit(masm);
                     break;
                 case I2L:
-                    masm.cvt_s64_s32(asLongReg(dst), asIntReg(src));
-                    break;
                 case I2C:
-                    masm.cvt_b16_s32(asIntReg(dst), asIntReg(src));
-                    break;
                 case I2B:
-                    masm.cvt_s8_s32(asIntReg(dst), asIntReg(src));
-                    break;
                 case I2F:
-                    masm.cvt_f32_s32(asFloatReg(dst), asIntReg(src));
-                    break;
                 case I2D:
-                    masm.cvt_f64_s32(asDoubleReg(dst), asIntReg(src));
-                    break;
-                case FNEG:
-                    masm.neg_f32(asFloatReg(dst), asFloatReg(src));
-                    break;
-                case DNEG:
-                    masm.neg_f64(asDoubleReg(dst), asDoubleReg(src));
-                    break;
                 case F2I:
-                    masm.cvt_s32_f32(asIntReg(dst), asFloatReg(src));
-                    break;
                 case F2L:
-                    masm.cvt_s64_f32(asLongReg(dst), asFloatReg(src));
-                    break;
                 case F2D:
-                    masm.cvt_f64_f32(asDoubleReg(dst), asFloatReg(src));
-                    break;
                 case D2I:
-                    masm.cvt_s32_f64(asIntReg(dst), asDoubleReg(src));
-                    break;
                 case D2L:
-                    masm.cvt_s64_f64(asLongReg(dst), asDoubleReg(src));
-                    break;
                 case D2F:
-                    masm.cvt_f32_f64(asFloatReg(dst), asDoubleReg(src));
+                    new Cvt(dest, source).emit(masm);
                     break;
                 case LSHL:
-                    masm.shl_b64(asLongReg(dst), asLongReg(dst), asIntReg(src));
+                    new Shl(dest, dest, src).emit(masm);
                     break;
                 case LSHR:
-                    masm.shr_s64(asLongReg(dst), asLongReg(dst), asIntReg(src));
+                    new Shr(dest, dest, src).emit(masm);
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere("missing: "  + opcode);
             }
         } else if (isConstant(src)) {
             switch (opcode) {
-                case ISUB: masm.sub_s32(asIntReg(dst), asIntReg(dst), tasm.asIntConst(src)); break;
-                case IAND: masm.and_b32(asIntReg(dst), asIntReg(dst), tasm.asIntConst(src)); break;
-                default:   throw GraalInternalError.shouldNotReachHere();
+                case ISUB:
+                    new Sub(dest, dest, src).emit(masm);
+                    break;
+                case IAND:
+                    new And(dest, dest, src).emit(masm);
+                    break;
+                case LSHL:
+                    new Shl(dest, dest, src).emit(masm);
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
         } else {
             switch (opcode) {
-                default:   throw GraalInternalError.shouldNotReachHere();
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
         }
 
@@ -342,84 +351,68 @@
         }
     }
 
-    public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value dst, Value src1, Value src2, LIRFrameState info) {
+    public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode,
+                            Value dst, Value src1, Value src2, LIRFrameState info) {
         int exceptionOffset = -1;
-        if (isConstant(src1)) {
-            switch (opcode) {
-            case ISUB:  masm.sub_s32(asIntReg(dst),    tasm.asIntConst(src1),    asIntReg(src2));         break;
-            case IAND:  masm.and_b32(asIntReg(dst),    asIntReg(src2),           tasm.asIntConst(src1));  break;
-            case IDIV:  masm.div_s32(asIntReg(dst),    tasm.asIntConst(src1),    asIntReg(src2));         break;
-            case FSUB:  masm.sub_f32(asFloatReg(dst),  tasm.asFloatConst(src1),  asFloatReg(src2));       break;
-            case FDIV:  masm.div_f32(asFloatReg(dst),  tasm.asFloatConst(src1),  asFloatReg(src2));       break;
-            case DSUB:  masm.sub_f64(asDoubleReg(dst), tasm.asDoubleConst(src1), asDoubleReg(src2));      break;
-            case DDIV:  masm.div_f64(asDoubleReg(dst), tasm.asDoubleConst(src1), asDoubleReg(src2));      break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-            }
-        } else if (isConstant(src2)) {
-            switch (opcode) {
-            case IADD:  masm.add_s32(asIntReg(dst),    asIntReg(src1),    tasm.asIntConst(src2));    break;
-            case ISUB:  masm.sub_s32(asIntReg(dst),    asIntReg(src1),    tasm.asIntConst(src2));    break;
-            case IMUL:  masm.mul_lo_s32(asIntReg(dst), asIntReg(src1),    tasm.asIntConst(src2));    break;
-            case IAND:  masm.and_b32(asIntReg(dst),    asIntReg(src1),    tasm.asIntConst(src2));    break;
-            case ISHL:  masm.shl_b32_const(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2));    break;
-            case ISHR:  masm.shr_s32(asIntReg(dst),    asIntReg(src1),    tasm.asIntConst(src2));    break;
-            case IUSHR: masm.shr_u32(asIntReg(dst),    asIntReg(src1),    tasm.asIntConst(src2));    break;
-            case IXOR:  masm.xor_b32(asIntReg(dst),    asIntReg(src1),    tasm.asIntConst(src2));    break;
-            case LXOR:  masm.xor_b64(asLongReg(dst),   asLongReg(src1),   tasm.asLongConst(src2));   break;
-            case LUSHR: masm.shr_u64(asLongReg(dst),   asLongReg(src1),   tasm.asLongConst(src2));   break;
-            case FADD:  masm.add_f32(asFloatReg(dst),  asFloatReg(src1),  tasm.asFloatConst(src2));  break;
-            case FMUL:  masm.mul_lo_f32(asFloatReg(dst), asFloatReg(src1), tasm.asFloatConst(src2)); break;
-            case FDIV:  masm.div_f32(asFloatReg(dst),  asFloatReg(src1),  tasm.asFloatConst(src2));  break;
-            case DADD:  masm.add_f64(asDoubleReg(dst), asDoubleReg(src1), tasm.asDoubleConst(src2)); break;
-            case DMUL:  masm.mul_lo_f64(asDoubleReg(dst), asDoubleReg(src1), tasm.asDoubleConst(src2)); break;
-            case DDIV:  masm.div_f64(asDoubleReg(dst), asDoubleReg(src1), tasm.asDoubleConst(src2)); break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-            }
-        } else {
-            switch (opcode) {
-            // case A:  new Add(Int, dst, src1, src2);
-            // case S:  new Sub(Int, dst, src1, src2);
-            // case U:  new Shl(UnsignedInt, dst, src1, src2);
-            // case L:  new Shl(UnsignedLong, dst, src1, src2);
-            // case F:  new Add(Float, dst, src1, src2);
-            // case D:  new Mul(Double, dst, src1, src2);
-            case IADD:  masm.add_s32(asIntReg(dst),    asIntReg(src1),    asIntReg(src2));    break;
-            case ISUB:  masm.sub_s32(asIntReg(dst),    asIntReg(src1),    asIntReg(src2));    break;
-            case IMUL:  masm.mul_lo_s32(asIntReg(dst), asIntReg(src1),    asIntReg(src2));    break;
-            case IDIV:  masm.div_s32(asIntReg(dst),    asIntReg(src1),    asIntReg(src2));    break;
-            case IAND:  masm.and_b32(asIntReg(dst),    asIntReg(src1),    asIntReg(src2));    break;
-            case IOR:    masm.or_b32(asIntReg(dst),    asIntReg(src1),    asIntReg(src2));    break;
-            case IXOR:  masm.xor_b32(asIntReg(dst),    asIntReg(src1),    asIntReg(src2));    break;
-            case ISHL:  masm.shl_b32(asIntReg(dst),    asIntReg(src1),    asIntReg(src2));    break;
-            case ISHR:  masm.shr_s32(asIntReg(dst),    asIntReg(src1),    asIntReg(src2));    break;
-            case IUSHR: masm.shr_u32(asIntReg(dst),    asIntReg(src1),    asIntReg(src2));    break;
-            case IREM:  masm.rem_s32(asIntReg(dst),    asIntReg(src1),    asIntReg(src2));    break;
-            case LADD:  masm.add_s64(asLongReg(dst),   asLongReg(src1),   asLongReg(src2));   break;
-            case LSUB:  masm.sub_s64(asLongReg(dst),   asLongReg(src1),   asLongReg(src2));   break;
-            case LMUL:  masm.mul_lo_s64(asLongReg(dst), asLongReg(src1),  asLongReg(src2));   break;
-            case LDIV:  masm.div_s64(asLongReg(dst),   asLongReg(src1),   asLongReg(src2));   break;
-            case LAND:  masm.and_b64(asLongReg(dst),   asLongReg(src1),   asLongReg(src2));   break;
-            case LOR:   masm.or_b64(asLongReg(dst),    asLongReg(src1),   asLongReg(src2));   break;
-            case LXOR:  masm.xor_b64(asLongReg(dst),   asLongReg(src1),   asLongReg(src2));   break;
-            case LSHL:  masm.shl_b64(asLongReg(dst),   asLongReg(src1),   asLongReg(src2));   break;
-            case LSHR:  masm.shr_s64(asLongReg(dst),   asLongReg(src1),   asLongReg(src2));   break;
-            case LUSHR: masm.shr_u64(asLongReg(dst),   asLongReg(src1),   asIntReg(src2));    break;
-            case LREM:  masm.rem_s64(asLongReg(dst),   asLongReg(src1),   asLongReg(src2));   break;
-            case FADD:  masm.add_f32(asFloatReg(dst),  asFloatReg(src1),  asFloatReg(src2));  break;
-            case FSUB:  masm.sub_f32(asFloatReg(dst),  asFloatReg(src1),  asFloatReg(src2));  break;
-            case FMUL:  masm.mul_lo_f32(asFloatReg(dst), asFloatReg(src1), asFloatReg(src2)); break;
-            case FDIV:  masm.div_f32(asFloatReg(dst),  asFloatReg(src1),  asFloatReg(src2));  break;
-            case FREM:  masm.div_f32(asFloatReg(dst),  asFloatReg(src1),  asFloatReg(src2));  break;
-            case DADD:  masm.add_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break;
-            case DSUB:  masm.sub_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break;
-            case DMUL:  masm.mul_lo_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break;
-            case DDIV:  masm.div_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break;
-            case DREM:  masm.div_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break;
+        Variable dest = (Variable) dst;
+
+        switch (opcode) {
+            case IADD:
+            case LADD:
+            case FADD:
+            case DADD:
+                new Add(dest, src1, src2).emit(masm);
+                break;
+            case IAND:
+            case LAND:
+                new And(dest, src1, src2).emit(masm);
+                break;
+            case ISUB:
+            case LSUB:
+            case FSUB:
+            case DSUB:
+                new Sub(dest, src1, src2).emit(masm);
+                break;
+            case IMUL:
+            case LMUL:
+            case FMUL:
+            case DMUL:
+                new Mul(dest, src1, src2).emit(masm);
+                break;
+            case IDIV:
+            case LDIV:
+            case FDIV:
+            case DDIV:
+                new Div(dest, src1, src2).emit(masm);
+                break;
+            case IOR:
+            case LOR:
+                new Or(dest, src1, src2).emit(masm);
+                break;
+            case IXOR:
+            case LXOR:
+                new Xor(dest, src1, src2).emit(masm);
+                break;
+            case ISHL:
+            case LSHL:
+                new Shl(dest, src1, src2).emit(masm);
+                break;
+            case ISHR:
+            case LSHR:
+                new Shr(dest, src1, src2).emit(masm);
+                break;
+            case IUSHR:
+            case LUSHR:
+                new Ushr(dest, src1, src2).emit(masm);
+                break;
+            case IREM:
+            case LREM:
+            case FREM:
+            case DREM:
+                new Rem(dest, src1, src2).emit(masm);
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: "  + opcode);
-            }
         }
 
         if (info != null) {
@@ -429,11 +422,73 @@
     }
 
     private static void verifyKind(PTXArithmetic opcode, Value result, Value x, Value y) {
-        if (((opcode.name().startsWith("I") && result.getKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int)
-            || (opcode.name().startsWith("L") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Long)
-            || (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float)
-            || (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double)) == false) {
-                throw GraalInternalError.shouldNotReachHere("opcode: "  + opcode.name() + " x: " + x.getKind() + " y: " + y.getKind());
+        Kind rk;
+        Kind xk;
+        Kind yk;
+        Kind xsk;
+        Kind ysk;
+
+        switch (opcode) {
+            case IADD:
+            case ISUB:
+            case IMUL:
+            case IDIV:
+            case IREM:
+            case IAND:
+            case IOR:
+            case IXOR:
+            case ISHL:
+            case ISHR:
+            case IUSHR:
+                rk = result.getKind();
+                xsk = x.getKind().getStackKind();
+                ysk = y.getKind().getStackKind();
+                assert rk == Kind.Int && xsk == Kind.Int && ysk == Kind.Int;
+                break;
+            case LADD:
+            case LSUB:
+            case LMUL:
+            case LDIV:
+            case LREM:
+            case LAND:
+            case LOR:
+            case LXOR:
+                rk = result.getKind();
+                xk = x.getKind();
+                yk = y.getKind();
+                assert rk == Kind.Long && xk == Kind.Long && yk == Kind.Long;
+                break;
+            case LSHL:
+            case LSHR:
+            case LUSHR:
+                rk = result.getKind();
+                xk = x.getKind();
+                yk = y.getKind();
+                assert rk == Kind.Long && xk == Kind.Long && (yk == Kind.Int || yk == Kind.Long);
+                break;
+            case FADD:
+            case FSUB:
+            case FMUL:
+            case FDIV:
+            case FREM:
+                rk = result.getKind();
+                xk = x.getKind();
+                yk = y.getKind();
+                assert rk == Kind.Float && xk == Kind.Float && yk == Kind.Float;
+                break;
+            case DADD:
+            case DSUB:
+            case DMUL:
+            case DDIV:
+            case DREM:
+                rk = result.getKind();
+                xk = x.getKind();
+                yk = y.getKind();
+                assert rk == Kind.Double && xk == Kind.Double && yk == Kind.Double :
+                    "opcode=" + opcode + ", result kind=" + rk + ", x kind=" + xk + ", y kind=" + yk;
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("missing: " + opcode);
         }
     }
 }
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXCompare.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXCompare.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.lir.ptx;
 
+import static com.oracle.graal.asm.ptx.PTXAssembler.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.ptx.*;
 import com.oracle.graal.graph.*;
@@ -41,18 +41,21 @@
         @Opcode private final PTXCompare opcode;
         @Use({REG, STACK, CONST}) protected Value x;
         @Use({REG, STACK, CONST}) protected Value y;
+        // Number of predicate register that would be set by this instruction.
+        protected int predRegNum;
         private final Condition condition;
 
-        public CompareOp(PTXCompare opcode, Condition condition, Value x, Value y) {
+        public CompareOp(PTXCompare opcode, Condition condition, Value x, Value y, int predReg) {
             this.opcode = opcode;
             this.condition = condition;
             this.x = x;
             this.y = y;
+            predRegNum = predReg;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            emit(tasm, masm, opcode, condition, x, y);
+            emit(masm, opcode, condition, x, y, predRegNum);
         }
 
         @Override
@@ -64,40 +67,18 @@
         }
     }
 
-    public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXCompare opcode, Condition condition, Value x, Value y) {
+    public static void emit(PTXAssembler masm, PTXCompare opcode,
+                            Condition condition, Value x, Value y, int p) {
         if (isConstant(x)) {
+            new Setp(condition, x, y, p).emit(masm);
+        } else if (isConstant(y)) {
             switch (opcode) {
                 case ICMP:
-                    emitCompareConstReg(masm, condition, tasm.asIntConst(x), asIntReg(y));
-                    break;
-                case FCMP:
-                    emitCompareConstReg(masm, condition, tasm.asFloatConst(x), asFloatReg(y));
-                    break;
-                case DCMP:
-                    emitCompareConstReg(masm, condition, tasm.asDoubleConst(x), asDoubleReg(y));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else if (isConstant(y)) {
-            Register a = asIntReg(x);
-            int b = tasm.asIntConst(y);
-            switch (opcode) {
-                case ICMP:
-                    emitCompareRegConst(masm, condition, a, b);
+                    new Setp(condition, x, y, p).emit(masm);
                     break;
                 case ACMP:
                     if (((Constant) y).isNull()) {
-                        switch (condition) {
-                            case EQ:
-                                masm.setp_eq_s32(a, b);
-                                break;
-                            case NE:
-                                masm.setp_ne_s32(a, b);
-                                break;
-                            default:
-                                throw GraalInternalError.shouldNotReachHere();
-                        }
+                        new Setp(condition, x, y, p).emit(masm);
                     } else {
                         throw GraalInternalError.shouldNotReachHere("Only null object constants are allowed in comparisons");
                     }
@@ -106,183 +87,8 @@
                     throw GraalInternalError.shouldNotReachHere();
             }
         } else {
-            switch (opcode) {
-                case ICMP:
-                    emitCompareRegReg(masm, condition, asIntReg(x), asIntReg(y));
-                    break;
-                case LCMP:
-                    emitCompareRegReg(masm, condition, asLongReg(x), asLongReg(y));
-                    break;
-                case FCMP:
-                    emitCompareRegReg(masm, condition, asFloatReg(x), asFloatReg(y));
-                    break;
-                case DCMP:
-                    emitCompareRegReg(masm, condition, asDoubleReg(x), asDoubleReg(y));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere("missing: "  + opcode);
-            }
-        }
-    }
-
-    private static void emitCompareConstReg(PTXAssembler masm, Condition condition, float a, Register b) {
-        switch (condition) {
-        case EQ:
-            masm.setp_eq_f32(a, b);
-            break;
-        case NE:
-            masm.setp_ne_f32(a, b);
-            break;
-        case LT:
-            masm.setp_lt_f32(a, b);
-            break;
-        case LE:
-            masm.setp_le_f32(a, b);
-            break;
-        case GT:
-            masm.setp_gt_f32(a, b);
-            break;
-        case GE:
-            masm.setp_ge_f32(a, b);
-            break;
-        default:
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    private static void emitCompareConstReg(PTXAssembler masm, Condition condition, double a, Register b) {
-        switch (condition) {
-        case EQ:
-            masm.setp_eq_f64(a, b);
-            break;
-        case NE:
-            masm.setp_ne_f64(a, b);
-            break;
-        case LT:
-            masm.setp_lt_f64(a, b);
-            break;
-        case LE:
-            masm.setp_le_f64(a, b);
-            break;
-        case GT:
-            masm.setp_gt_f64(a, b);
-            break;
-        case GE:
-            masm.setp_ge_f64(a, b);
-            break;
-        default:
-            throw GraalInternalError.shouldNotReachHere();
+            new Setp(condition, x, y, p).emit(masm);
         }
     }
 
-    private static void emitCompareConstReg(PTXAssembler masm, Condition condition, int a, Register b) {
-        switch (condition) {
-            case EQ:
-                masm.setp_eq_s32(a, b);
-                break;
-            case NE:
-                masm.setp_ne_s32(a, b);
-                break;
-            case LT:
-                masm.setp_lt_s32(a, b);
-                break;
-            case LE:
-                masm.setp_le_s32(a, b);
-                break;
-            case GT:
-                masm.setp_gt_s32(a, b);
-                break;
-            case GE:
-                masm.setp_ge_s32(a, b);
-                break;
-            case AT:
-                masm.setp_gt_u32(a, b);
-                break;
-            case AE:
-                masm.setp_ge_u32(a, b);
-                break;
-            case BT:
-                masm.setp_lt_u32(a, b);
-                break;
-            case BE:
-                masm.setp_le_u32(a, b);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    private static void emitCompareRegConst(PTXAssembler masm, Condition condition, Register a, int b) {
-        switch (condition) {
-            case EQ:
-                masm.setp_eq_s32(a, b);
-                break;
-            case NE:
-                masm.setp_ne_s32(a, b);
-                break;
-            case LT:
-                masm.setp_lt_s32(a, b);
-                break;
-            case LE:
-                masm.setp_le_s32(a, b);
-                break;
-            case GT:
-                masm.setp_gt_s32(a, b);
-                break;
-            case GE:
-                masm.setp_ge_s32(a, b);
-                break;
-            case AT:
-                masm.setp_gt_u32(a, b);
-                break;
-            case AE:
-                masm.setp_ge_u32(a, b);
-                break;
-            case BT:
-                masm.setp_lt_u32(a, b);
-                break;
-            case BE:
-                masm.setp_le_u32(a, b);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    private static void emitCompareRegReg(PTXAssembler masm, Condition condition, Register a, Register b) {
-        switch (condition) {
-            case EQ:
-                masm.setp_eq_s32(a, b);
-                break;
-            case NE:
-                masm.setp_ne_s32(a, b);
-                break;
-            case LT:
-                masm.setp_lt_s32(a, b);
-                break;
-            case LE:
-                masm.setp_le_s32(a, b);
-                break;
-            case GT:
-                masm.setp_gt_s32(a, b);
-                break;
-            case GE:
-                masm.setp_ge_s32(a, b);
-                break;
-            case AT:
-                masm.setp_gt_u32(a, b);
-                break;
-            case AE:
-                masm.setp_ge_u32(a, b);
-                break;
-            case BT:
-                masm.setp_lt_u32(a, b);
-                break;
-            case BE:
-                masm.setp_le_u32(a, b);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
 }
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,11 +22,11 @@
  */
 package com.oracle.graal.lir.ptx;
 
-import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.ptx.PTXAssembler.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+import static com.oracle.graal.nodes.calc.Condition.*;
 
 import com.oracle.graal.api.code.CompilationResult.JumpTable;
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.ptx.*;
@@ -72,16 +72,17 @@
 
         protected Condition condition;
         protected LabelRef destination;
+        protected int predRegNum;
 
-        public BranchOp(Condition condition, LabelRef destination) {
+        public BranchOp(Condition condition, LabelRef destination, int predReg) {
             this.condition = condition;
             this.destination = destination;
+            this.predRegNum = predReg;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            masm.at();
-            masm.bra(masm.nameOf(destination.label()));
+            masm.bra(masm.nameOf(destination.label()), predRegNum);
         }
 
         @Override
@@ -151,45 +152,36 @@
         private LabelRef defaultTarget;
         @Alive({REG}) protected Value key;
         @Temp({REG, ILLEGAL}) protected Value scratch;
+        // Number of predicate register that would be set by this instruction.
+        protected int predRegNum;
 
-        public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
+        public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, int predReg) {
             assert keyConstants.length == keyTargets.length;
             this.keyConstants = keyConstants;
             this.keyTargets = keyTargets;
             this.defaultTarget = defaultTarget;
             this.key = key;
             this.scratch = scratch;
+            predRegNum = predReg;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            if (key.getKind() == Kind.Int) {
-                Register intKey = asIntReg(key);
+            Kind keyKind = key.getKind();
+
+            if (keyKind == Kind.Int || keyKind == Kind.Long) {
                 for (int i = 0; i < keyConstants.length; i++) {
                     if (tasm.runtime.needsDataPatch(keyConstants[i])) {
                         tasm.recordDataReferenceInCode(keyConstants[i], 0, true);
                     }
-                    long lc = keyConstants[i].asLong();
-                    assert NumUtil.isInt(lc);
-                    masm.setp_eq_s32((int) lc, intKey);
-                    masm.at();
-                    masm.bra(masm.nameOf(keyTargets[i].label()));
+                    new Setp(EQ, keyConstants[i], key, predRegNum).emit(masm);
+                    masm.bra(masm.nameOf(keyTargets[i].label()), predRegNum);
                 }
-            } else if (key.getKind() == Kind.Long) {
-                Register longKey = asLongReg(key);
+            } else if (keyKind == Kind.Object) {
                 for (int i = 0; i < keyConstants.length; i++) {
-                    masm.setp_eq_s64(tasm.asLongConst(keyConstants[i]), longKey);
-                    masm.at();
-                    masm.bra(masm.nameOf(keyTargets[i].label()));
-                }
-            } else if (key.getKind() == Kind.Object) {
-                Register intKey = asObjectReg(key);
-                Register temp = asObjectReg(scratch);
-                for (int i = 0; i < keyConstants.length; i++) {
-                    PTXMove.move(tasm, masm, temp.asValue(Kind.Object), keyConstants[i]);
-                    masm.setp_eq_u32(intKey, temp);
-                    masm.at();
-                    masm.bra(keyTargets[i].label().toString());
+                    PTXMove.move(tasm, masm, scratch, keyConstants[i]);
+                    new Setp(EQ, keyConstants[i], scratch, predRegNum).emit(masm);
+                    masm.bra(keyTargets[i].label().toString(), predRegNum);
                 }
             } else {
                 throw new GraalInternalError("sequential switch only supported for int, long and object");
@@ -219,38 +211,40 @@
         private final LabelRef[] targets;
         @Alive protected Value index;
         @Temp protected Value scratch;
+        // Number of predicate register that would be set by this instruction.
+        protected int predRegNum;
 
-        public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch) {
+        public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch, int predReg) {
             this.lowKey = lowKey;
             this.defaultTarget = defaultTarget;
             this.targets = targets;
             this.index = index;
             this.scratch = scratch;
+            predRegNum = predReg;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            tableswitch(tasm, masm, lowKey, defaultTarget, targets, asIntReg(index), asLongReg(scratch));
+            tableswitch(tasm, masm, lowKey, defaultTarget, targets, index, scratch, predRegNum);
         }
     }
 
     @SuppressWarnings("unused")
-    private static void tableswitch(TargetMethodAssembler tasm, PTXAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, Register value, Register scratch) {
+    private static void tableswitch(TargetMethodAssembler tasm, PTXAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value value, Value scratch, int predNum) {
         Buffer buf = masm.codeBuffer;
         // Compare index against jump table bounds
         int highKey = lowKey + targets.length - 1;
         if (lowKey != 0) {
             // subtract the low value from the switch value
-            masm.sub_s32(value, value, lowKey);
-            masm.setp_gt_s32(value, highKey - lowKey);
+            // new Sub(value, value, lowKey).emit(masm);
+            new Setp(GT, value, Constant.forInt(highKey - lowKey), predNum).emit(masm);
         } else {
-            masm.setp_gt_s32(value, highKey);
+            new Setp(GT, value, Constant.forInt(highKey), predNum).emit(masm);
         }
 
         // Jump to default target if index is not within the jump table
         if (defaultTarget != null) {
-            masm.at();
-            masm.bra(defaultTarget.label().toString());
+            masm.bra(defaultTarget.label().toString(), predNum);
         }
 
         // address of jump table
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMemOp.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMemOp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,8 @@
  */
 package com.oracle.graal.lir.ptx;
 
-import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.ptx.PTXAssembler.*;
+import static com.oracle.graal.asm.ptx.PTXStateSpace.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import com.oracle.graal.api.meta.*;
@@ -34,15 +35,15 @@
 public class PTXMemOp {
 
     // Load operation from .global state space
-    @Opcode("LOAD")
+    @Opcode("LOAD_REGBASE_DISP")
     public static class LoadOp extends PTXLIRInstruction {
 
         private final Kind kind;
-        @Def({REG}) protected AllocatableValue result;
+        @Def({REG}) protected Variable result;
         @Use({COMPOSITE}) protected PTXAddressValue address;
         @State protected LIRFrameState state;
 
-        public LoadOp(Kind kind, AllocatableValue result, PTXAddressValue address, LIRFrameState state) {
+        public LoadOp(Kind kind, Variable result, PTXAddressValue address, LIRFrameState state) {
             this.kind = kind;
             this.result = result;
             this.address = address;
@@ -54,28 +55,14 @@
             PTXAddress addr = address.toAddress();
             switch (kind) {
                 case Byte:
-                    masm.ld_global_s8(asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Short:
-                    masm.ld_global_s16(asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Char:
-                    masm.ld_global_u16(asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Int:
-                    masm.ld_global_s32(asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Long:
-                    masm.ld_global_s64(asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Float:
-                    masm.ld_global_f32(asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Double:
-                    masm.ld_global_f64(asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Object:
-                    masm.ld_global_u32(asRegister(result), addr.getBase(), addr.getDisplacement());
+                    new Ld(Global, result, addr.getBase(), Constant.forLong(addr.getDisplacement())).emit(masm);
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -89,10 +76,10 @@
 
         private final Kind kind;
         @Use({COMPOSITE}) protected PTXAddressValue address;
-        @Use({REG}) protected AllocatableValue input;
+        @Use({REG}) protected Variable input;
         @State protected LIRFrameState state;
 
-        public StoreOp(Kind kind, PTXAddressValue address, AllocatableValue input, LIRFrameState state) {
+        public StoreOp(Kind kind, PTXAddressValue address, Variable input, LIRFrameState state) {
             this.kind = kind;
             this.address = address;
             this.input = input;
@@ -101,29 +88,16 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            assert isRegister(input);
             PTXAddress addr = address.toAddress();
             switch (kind) {
                 case Byte:
-                    masm.st_global_s8(addr.getBase(), addr.getDisplacement(), asRegister(input));
-                    break;
                 case Short:
-                    masm.st_global_s8(addr.getBase(), addr.getDisplacement(), asRegister(input));
-                    break;
                 case Int:
-                    masm.st_global_s32(addr.getBase(), addr.getDisplacement(), asRegister(input));
-                    break;
                 case Long:
-                    masm.st_global_s64(addr.getBase(), addr.getDisplacement(), asRegister(input));
-                    break;
                 case Float:
-                    masm.st_global_f32(addr.getBase(), addr.getDisplacement(), asRegister(input));
-                    break;
                 case Double:
-                    masm.st_global_f64(addr.getBase(), addr.getDisplacement(), asRegister(input));
-                    break;
                 case Object:
-                    masm.st_global_u64(addr.getBase(), addr.getDisplacement(), asRegister(input));
+                    new St(Global, input, addr.getBase(), Constant.forLong(addr.getDisplacement())).emit(masm);
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere("missing: " + address.getKind());
@@ -132,15 +106,15 @@
     }
 
     // Load operation from .param state space
-    @Opcode("LOAD")
+    @Opcode("LOAD_PARAM")
     public static class LoadParamOp extends PTXLIRInstruction {
 
         private final Kind kind;
-        @Def({REG}) protected AllocatableValue result;
+        @Def({REG}) protected Variable result;
         @Use({COMPOSITE}) protected PTXAddressValue address;
         @State protected LIRFrameState state;
 
-        public LoadParamOp(Kind kind, AllocatableValue result, PTXAddressValue address, LIRFrameState state) {
+        public LoadParamOp(Kind kind, Variable result, PTXAddressValue address, LIRFrameState state) {
             this.kind = kind;
             this.result = result;
             this.address = address;
@@ -152,28 +126,14 @@
             PTXAddress addr = address.toAddress();
             switch (kind) {
                 case Byte:
-                    masm.ld_from_state_space(".param.s8", asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Short:
-                    masm.ld_from_state_space(".param.s16", asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Char:
-                    masm.ld_from_state_space(".param.u16", asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Int:
-                    masm.ld_from_state_space(".param.s32", asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Long:
-                    masm.ld_from_state_space(".param.s64", asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Float:
-                    masm.ld_from_state_space(".param.f32", asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Double:
-                    masm.ld_from_state_space(".param.f64", asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Object:
-                    masm.ld_from_state_space(".param.u64", asRegister(result), addr.getBase(), addr.getDisplacement());
+                    new Ld(Parameter, result, addr.getBase(), Constant.forLong(addr.getDisplacement())).emit(masm);
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -187,11 +147,11 @@
     public static class LoadReturnAddrOp extends PTXLIRInstruction {
 
         private final Kind kind;
-        @Def({REG}) protected AllocatableValue result;
+        @Def({REG}) protected Variable result;
         @Use({COMPOSITE}) protected PTXAddressValue address;
         @State protected LIRFrameState state;
 
-        public LoadReturnAddrOp(Kind kind, AllocatableValue result, PTXAddressValue address, LIRFrameState state) {
+        public LoadReturnAddrOp(Kind kind, Variable result, PTXAddressValue address, LIRFrameState state) {
             this.kind = kind;
             this.result = result;
             this.address = address;
@@ -203,10 +163,10 @@
             PTXAddress addr = address.toAddress();
             switch (kind) {
                 case Int:
-                    masm.ld_return_address("u32", asRegister(result), addr.getBase(), addr.getDisplacement());
-                    break;
                 case Long:
-                    masm.ld_return_address("u64", asRegister(result), addr.getBase(), addr.getDisplacement());
+                case Float:
+                case Double:
+                    new Ld(Parameter, result, addr.getBase(), Constant.forLong(addr.getDisplacement())).emit(masm);
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -220,10 +180,10 @@
 
         private final Kind kind;
         @Use({COMPOSITE}) protected PTXAddressValue address;
-        @Use({REG}) protected AllocatableValue input;
+        @Use({REG}) protected Variable input;
         @State protected LIRFrameState state;
 
-        public StoreReturnValOp(Kind kind, PTXAddressValue address, AllocatableValue input, LIRFrameState state) {
+        public StoreReturnValOp(Kind kind, PTXAddressValue address, Variable input, LIRFrameState state) {
             this.kind = kind;
             this.address = address;
             this.input = input;
@@ -232,29 +192,17 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            assert isRegister(input);
             PTXAddress addr = address.toAddress();
-            // masm.st_global_return_value_s64(addr.getBase(), addr.getDisplacement(), asRegister(input));
 
             switch (kind) {
                 case Byte:
                 case Short:
-                    masm.st_global_return_value_s8(addr.getBase(), addr.getDisplacement(), asRegister(input));
-                    break;
                 case Int:
-                    masm.st_global_return_value_s32(addr.getBase(), addr.getDisplacement(), asRegister(input));
-                    break;
                 case Long:
-                    masm.st_global_return_value_s64(addr.getBase(), addr.getDisplacement(), asRegister(input));
-                    break;
                 case Float:
-                    masm.st_global_return_value_f32(addr.getBase(), addr.getDisplacement(), asRegister(input));
-                    break;
                 case Double:
-                    masm.st_global_return_value_f64(addr.getBase(), addr.getDisplacement(), asRegister(input));
-                    break;
                 case Object:
-                    masm.st_global_return_value_u64(addr.getBase(), addr.getDisplacement(), asRegister(input));
+                    new St(Global, input, addr.getBase(), Constant.forLong(addr.getDisplacement())).emit(masm);
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere("missing: " + address.getKind());
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,9 @@
  */
 package com.oracle.graal.lir.ptx;
 
+import static com.oracle.graal.asm.ptx.PTXAssembler.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import com.oracle.graal.api.code.*;
@@ -170,14 +172,14 @@
     }
 
     public static void move(TargetMethodAssembler tasm, PTXAssembler masm, Value result, Value input) {
-        if (isRegister(input)) {
-            if (isRegister(result)) {
+        if (isVariable(input)) {
+            if (isVariable(result)) {
                 reg2reg(masm, result, input);
             } else {
                 throw GraalInternalError.shouldNotReachHere();
             }
         } else if (isConstant(input)) {
-            if (isRegister(result)) {
+            if (isVariable(result)) {
                 const2reg(tasm, masm, result, (Constant) input);
             } else {
                 throw GraalInternalError.shouldNotReachHere();
@@ -188,24 +190,19 @@
     }
 
     private static void reg2reg(PTXAssembler masm, Value result, Value input) {
-        if (asRegister(input).equals(asRegister(result))) {
+        Variable dest = (Variable) result;
+        Variable source = (Variable) input;
+
+        if (dest.index == source.index) {
             return;
         }
         switch (input.getKind()) {
             case Int:
-                masm.mov_s32(asRegister(result), asRegister(input));
-                break;
             case Long:
-                masm.mov_s64(asRegister(result), asRegister(input));
-                break;
             case Float:
-                masm.mov_f32(asRegister(result), asRegister(input));
-                break;
             case Double:
-                masm.mov_f64(asRegister(result), asRegister(input));
-                break;
             case Object:
-                masm.mov_u64(asRegister(result), asRegister(input));
+                new Mov(dest, source).emit(masm);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind());
@@ -213,27 +210,24 @@
     }
 
     private static void const2reg(TargetMethodAssembler tasm, PTXAssembler masm, Value result, Constant input) {
+        Variable dest = (Variable) result;
+
         switch (input.getKind().getStackKind()) {
             case Int:
-                if (tasm.runtime.needsDataPatch(input)) {
-                    tasm.recordDataReferenceInCode(input, 0, true);
-                }
-                masm.mov_s32(asRegister(result), input.asInt());
-                break;
             case Long:
                 if (tasm.runtime.needsDataPatch(input)) {
                     tasm.recordDataReferenceInCode(input, 0, true);
                 }
-                masm.mov_s64(asRegister(result), input.asLong());
+                new Mov(dest, input).emit(masm);
                 break;
             case Object:
                 if (input.isNull()) {
-                    masm.mov_u64(asRegister(result), 0x0L);
+                    new Mov(dest, Constant.forLong(0x0L)).emit(masm);
                 } else if (tasm.target.inlineObjects) {
                     tasm.recordDataReferenceInCode(input, 0, true);
-                    masm.mov_u64(asRegister(result), 0xDEADDEADDEADDEADL);
+                    new Mov(dest, Constant.forLong(0xDEADDEADDEADDEADL)).emit(masm);
                 } else {
-                    masm.mov_u64(asRegister(result), tasm.recordDataReferenceInCode(input, 0, false));
+                    // new Mov(dest, tasm.recordDataReferenceInCode(input, 0, false));
                 }
                 break;
             default:
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXParameterOp.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXParameterOp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,12 +23,11 @@
 
 package com.oracle.graal.lir.ptx;
 
-import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.ptx.PTXAssembler.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.ptx.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
@@ -46,23 +45,7 @@
         // Emit parameter directives for arguments
         int argCount = params.length;
         for (int i = 0; i < argCount; i++) {
-            Kind paramKind = params[i].getKind();
-            switch (paramKind) {
-            case Int :
-                masm.param_32_decl(asIntReg(params[i]), (i == (argCount - 1)));
-                break;
-            case Long :
-                masm.param_64_decl(asLongReg(params[i]), (i == (argCount - 1)));
-                break;
-            case Float :
-                masm.param_32_decl(asFloatReg(params[i]), (i == (argCount - 1)));
-                break;
-            case Double :
-                masm.param_64_decl(asDoubleReg(params[i]), (i == (argCount - 1)));
-                break;
-            default :
-                throw GraalInternalError.shouldNotReachHere("unhandled parameter type "  + paramKind.toString());
-            }
+            new Param((Variable) params[i], (i == (argCount - 1))).emit(masm);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/ParallelOver.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,36 @@
+/*
+ * 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.lir.ptx;
+
+import static com.oracle.graal.lir.ptx.ThreadDimension.*;
+
+import java.lang.annotation.*;
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface ParallelOver {
+
+    String value() default "";
+
+    ThreadDimension dimension() default X;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/ThreadDimension.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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.lir.ptx;
+
+public enum ThreadDimension {
+X,
+Y,
+Z
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/Warp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,37 @@
+/*
+ * 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.lir.ptx;
+
+import static com.oracle.graal.lir.ptx.ThreadDimension.*;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface Warp {
+
+    String value() default "";
+
+    ThreadDimension dimension() default X;
+}
+
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Wed Oct 02 13:26:31 2013 +0200
@@ -247,8 +247,12 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, SPARCMacroAssembler masm) {
+            emitCodeHelper(tasm, masm);
+        }
+
+        public static void emitCodeHelper(TargetMethodAssembler tasm, SPARCMacroAssembler masm) {
             new Ret().emit(masm);
-            // On SPARC we always leave the frame.
+            // On SPARC we always leave the frame (in the delay slot).
             tasm.frameContext.leave(tasm);
         }
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Wed Oct 02 13:26:31 2013 +0200
@@ -116,7 +116,7 @@
     /**
      * Gets the frame size of the compiled frame, not including the size of the
      * {@link Architecture#getReturnAddressSize() return address slot}.
-     * 
+     *
      * @return The size of the frame (in bytes).
      */
     public int frameSize() {
@@ -136,7 +136,7 @@
     /**
      * Gets the total frame size of the compiled frame, including the size of the
      * {@link Architecture#getReturnAddressSize() return address slot}.
-     * 
+     *
      * @return The total size of the frame (in bytes).
      */
     public abstract int totalFrameSize();
@@ -149,7 +149,7 @@
 
     /**
      * Aligns the given frame size to the stack alignment size and return the aligned size.
-     * 
+     *
      * @param size the initial frame size to be aligned
      * @return the aligned frame size
      */
@@ -181,7 +181,7 @@
 
     /**
      * Computes the offset of a stack slot relative to the frame register.
-     * 
+     *
      * @param slot a stack slot
      * @return the offset of the stack slot
      */
@@ -197,7 +197,7 @@
     /**
      * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack
      * slots in the reference map.
-     * 
+     *
      * @param slot a stack slot
      * @return the index of the stack slot
      */
@@ -209,7 +209,7 @@
     /**
      * Gets the offset from the stack pointer to the stack area where callee-saved registers are
      * stored.
-     * 
+     *
      * @return The offset to the callee save area (in bytes).
      */
     public abstract int offsetToCalleeSaveArea();
@@ -217,7 +217,7 @@
     /**
      * Informs the frame map that the compiled code calls a particular method, which may need stack
      * space for outgoing arguments.
-     * 
+     *
      * @param cc The calling convention for the called method.
      */
     public void callsMethod(CallingConvention cc) {
@@ -226,7 +226,7 @@
 
     /**
      * Reserves space for stack-based outgoing arguments.
-     * 
+     *
      * @param argsSize The amount of space (in bytes) to reserve for stack-based outgoing arguments.
      */
     public void reserveOutgoing(int argsSize) {
@@ -239,7 +239,7 @@
      * Reserves a new spill slot in the frame of the method being compiled. The returned slot is
      * aligned on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte
      * boundary.
-     * 
+     *
      * @param kind The kind of the spill slot to be reserved.
      * @param additionalOffset
      * @return A spill slot denoting the reserved memory area.
@@ -247,9 +247,20 @@
     protected abstract StackSlot allocateNewSpillSlot(PlatformKind 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.
+     * @param kind the {@link PlatformKind} to be stored in the spill slot.
+     * @return the size in bytes
+     */
+    protected int spillSlotSize(PlatformKind kind) {
+        return target.arch.getSizeInBytes(kind);
+    }
+
+    /**
      * Reserves a spill slot in the frame of the method being compiled. The returned slot is aligned
-     * on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte boundary.
-     * 
+     * on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte boundary,
+     * unless overridden by a subclass.
+     *
      * @param kind The kind of the spill slot to be reserved.
      * @return A spill slot denoting the reserved memory area.
      */
@@ -267,7 +278,7 @@
                 }
             }
         }
-        int size = target.arch.getSizeInBytes(kind);
+        int size = spillSlotSize(kind);
         spillSize = NumUtil.roundUp(spillSize + size, size);
         return allocateNewSpillSlot(kind, 0);
     }
@@ -288,7 +299,7 @@
     /**
      * Reserves a block of memory in the frame of the method being compiled. The returned block is
      * aligned on a word boundary. If the requested size is 0, the method returns {@code null}.
-     * 
+     *
      * @param size The size to reserve (in bytes).
      * @param refs Specifies if the block is all references. If true, the block will be in all
      *            reference maps for this method. The caller is responsible to initialize the memory
@@ -340,7 +351,7 @@
      * Marks 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 registerRefMap A register reference map, as created by {@link #initRegisterRefMap()}.
      * @param frameRefMap A frame reference map, as created by {@link #initFrameRefMap()}.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
@@ -56,6 +55,8 @@
      */
     private final List<Block> codeEmittingOrder;
 
+    private int firstVariableNumber;
+
     private int numVariables;
 
     public SpillMoveFactory spillMoveFactory;
@@ -69,22 +70,15 @@
 
     private boolean hasArgInCallerFrame;
 
-    private final SpeculationLog speculationLog;
-
     /**
      * Creates a new LIR instance for the specified compilation.
      */
-    public LIR(ControlFlowGraph cfg, BlockMap<List<ScheduledNode>> blockToNodesMap, List<Block> linearScanOrder, List<Block> codeEmittingOrder, SpeculationLog speculationLog) {
+    public LIR(ControlFlowGraph cfg, BlockMap<List<ScheduledNode>> blockToNodesMap, List<Block> linearScanOrder, List<Block> codeEmittingOrder) {
         this.cfg = cfg;
         this.blockToNodesMap = blockToNodesMap;
         this.codeEmittingOrder = codeEmittingOrder;
         this.linearScanOrder = linearScanOrder;
         this.lirInstructions = new BlockMap<>(cfg);
-        this.speculationLog = speculationLog;
-    }
-
-    public SpeculationLog getDeoptimizationReasons() {
-        return speculationLog;
     }
 
     /**
@@ -135,7 +129,11 @@
     }
 
     public int nextVariable() {
-        return numVariables++;
+        return firstVariableNumber + numVariables++;
+    }
+
+    public void setFirstVariableNumber(int num) {
+        firstVariableNumber = num;
     }
 
     public void emitCode(TargetMethodAssembler tasm) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Wed Oct 02 13:26:31 2013 +0200
@@ -42,13 +42,11 @@
     private final VirtualObject[] virtualObjects;
     public final LabelRef exceptionEdge;
     private DebugInfo debugInfo;
-    private final short deoptimizationReason;
 
-    public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge, short deoptimizationReason) {
+    public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge) {
         this.topFrame = topFrame;
         this.virtualObjects = virtualObjects;
         this.exceptionEdge = exceptionEdge;
-        this.deoptimizationReason = deoptimizationReason;
     }
 
     public boolean hasDebugInfo() {
@@ -112,7 +110,7 @@
     }
 
     public void finish(BitSet registerRefMap, BitSet frameRefMap) {
-        debugInfo = new DebugInfo(topFrame, registerRefMap, frameRefMap, deoptimizationReason);
+        debugInfo = new DebugInfo(topFrame, registerRefMap, frameRefMap);
     }
 
     @Override
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Wed Oct 02 13:26:31 2013 +0200
@@ -40,6 +40,7 @@
 
     private static final Class<Value> VALUE_CLASS = Value.class;
     private static final Class<Constant> CONSTANT_CLASS = Constant.class;
+    private static final Class<Variable> VARIABLE_CLASS = Variable.class;
     private static final Class<RegisterValue> REGISTER_VALUE_CLASS = RegisterValue.class;
     private static final Class<StackSlot> STACK_SLOT_CLASS = StackSlot.class;
     private static final Class<Value[]> VALUE_ARRAY_CLASS = Value[].class;
@@ -106,7 +107,8 @@
 
         private static boolean verifyFlags(Field field, Class<?> type, EnumSet<OperandFlag> flags) {
             if (flags.contains(REG)) {
-                assert type.isAssignableFrom(REGISTER_VALUE_CLASS) : "Cannot assign RegisterValue to field with REG flag:" + field;
+                assert type.isAssignableFrom(REGISTER_VALUE_CLASS) ||
+                       type.isAssignableFrom(VARIABLE_CLASS) : "Cannot assign RegisterValue / Variable to field with REG flag:" + field;
             }
             if (flags.contains(STACK)) {
                 assert type.isAssignableFrom(STACK_SLOT_CLASS) : "Cannot assign StackSlot to field with STACK flag:" + field;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Wed Oct 02 13:26:31 2013 +0200
@@ -38,6 +38,8 @@
      */
     public final int index;
 
+    private String name;
+
     /**
      * Creates a new variable.
      * 
@@ -50,9 +52,21 @@
         this.index = index;
     }
 
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
     @Override
     public String toString() {
-        return "v" + index + getKindSuffix();
+        if (name != null) {
+            return name;
+        } else {
+            return "v" + index + getKindSuffix();
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.nodes.calc.IntegerArithmeticNode.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.loop.InductionVariable.Direction;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Wed Oct 02 13:26:31 2013 +0200
@@ -129,15 +129,10 @@
                     }
                 };
             } else {
-                dr = new DuplicationReplacement() {
-
-                    @Override
-                    public Node replacement(Node o) {
-                        return o;
-                    }
-                };
+                dr = null;
             }
-            duplicationMap = graph().addDuplicates(original().nodes(), dr);
+            NodeIterable<Node> nodesIterable = original().nodes();
+            duplicationMap = graph().addDuplicates(nodesIterable, graph(), nodesIterable.count(), dr);
             finishDuplication();
             nodesReady = true;
         } else {
@@ -295,7 +290,7 @@
                 final ValueNode replaceWith;
                 ProxyNode newVpn = getDuplicatedNode(vpn);
                 if (newVpn != null) {
-                    PhiNode phi = graph.add(vpn.type() == PhiType.Value ? new PhiNode(vpn.kind(), merge) : new PhiNode(vpn.type(), merge, vpn.getIdentity()));
+                    PhiNode phi = graph.addWithoutUnique(vpn.type() == PhiType.Value ? new PhiNode(vpn.kind(), merge) : new PhiNode(vpn.type(), merge, vpn.getIdentity()));
                     phi.addInput(vpn);
                     phi.addInput(newVpn);
                     replaceWith = phi;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Wed Oct 02 13:26:31 2013 +0200
@@ -125,16 +125,36 @@
         final StructuredGraph graph = graph();
         return new DuplicationReplacement() {
 
+            private HashMap<Node, Node> seenNode = new HashMap<>();
+
             @Override
             public Node replacement(Node original) {
                 if (original == loopBegin) {
-                    return graph.add(new BeginNode());
+                    Node value = seenNode.get(original);
+                    if (value != null) {
+                        return value;
+                    }
+                    BeginNode newValue = graph.add(new BeginNode());
+                    seenNode.put(original, newValue);
+                    return newValue;
                 }
                 if (original instanceof LoopExitNode && ((LoopExitNode) original).loopBegin() == loopBegin) {
-                    return graph.add(new BeginNode());
+                    Node value = seenNode.get(original);
+                    if (value != null) {
+                        return value;
+                    }
+                    BeginNode newValue = graph.add(new BeginNode());
+                    seenNode.put(original, newValue);
+                    return newValue;
                 }
                 if (original instanceof LoopEndNode && ((LoopEndNode) original).loopBegin() == loopBegin) {
-                    return graph.add(new EndNode());
+                    Node value = seenNode.get(original);
+                    if (value != null) {
+                        return value;
+                    }
+                    EndNode newValue = graph.add(new EndNode());
+                    seenNode.put(original, newValue);
+                    return newValue;
                 }
                 return original;
             }
@@ -160,7 +180,7 @@
             }
             // create a new phi (we don't patch the old one since some usages of the old one may
             // still be valid)
-            PhiNode newPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), loopBegin) : new PhiNode(phi.type(), loopBegin, phi.getIdentity()));
+            PhiNode newPhi = graph.addWithoutUnique(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), loopBegin) : new PhiNode(phi.type(), loopBegin, phi.getIdentity()));
             newPhi.addInput(first);
             for (LoopEndNode end : loopBegin.orderedLoopEnds()) {
                 newPhi.addInput(phi.valueAt(end));
@@ -250,7 +270,7 @@
             }
 
             for (final PhiNode phi : loopBegin.phis().snapshot()) {
-                final PhiNode firstPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), newExitMerge) : new PhiNode(phi.type(), newExitMerge, phi.getIdentity()));
+                final PhiNode firstPhi = graph.addWithoutUnique(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), newExitMerge) : new PhiNode(phi.type(), newExitMerge, phi.getIdentity()));
                 for (AbstractEndNode end : newExitMerge.forwardEnds()) {
                     LoopEndNode loopEnd = reverseEnds.get(end);
                     ValueNode prim = prim(phi.valueAt(loopEnd));
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java	Wed Oct 02 13:26:31 2013 +0200
@@ -68,10 +68,15 @@
         final Graph graph = this.graph();
         return new DuplicationReplacement() {
 
+            private EndNode endNode;
+
             @Override
             public Node replacement(Node o) {
                 if (o == entry) {
-                    return graph.add(new EndNode());
+                    if (endNode == null) {
+                        endNode = graph.add(new EndNode());
+                    }
+                    return endNode;
                 }
                 return o;
             }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Wed Oct 02 13:26:31 2013 +0200
@@ -48,11 +48,11 @@
             return false;
         }
         CountedLoopInfo counted = loop.counted();
-        long exactTrips = counted.constantMaxTripCount();
+        long maxTrips = counted.constantMaxTripCount();
         int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? ExactFullUnrollMaxNodes.getValue() : FullUnrollMaxNodes.getValue();
         maxNodes = Math.min(maxNodes, MaximumDesiredSize.getValue() - loop.loopBegin().graph().getNodeCount());
         int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count());
-        return size * exactTrips <= maxNodes;
+        return size * maxTrips <= maxNodes;
     }
 
     public static boolean shouldTryUnswitch(LoopEx loop) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,13 +25,13 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.NodeClass.NodeClassIterator;
 import com.oracle.graal.graph.NodeClass.Position;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 public abstract class LoopTransformations {
 
@@ -53,7 +53,7 @@
         loop.inside().duplicate().insertBefore(loop);
     }
 
-    public static void fullUnroll(LoopEx loop, MetaAccessProvider runtime, Assumptions assumptions, boolean canonicalizeReads) {
+    public static void fullUnroll(LoopEx loop, PhaseContext context, CanonicalizerPhase canonicalizer) {
         // assert loop.isCounted(); //TODO (gd) strenghten : counted with known trip count
         int iterations = 0;
         LoopBeginNode loopBegin = loop.loopBegin();
@@ -61,7 +61,7 @@
         while (!loopBegin.isDeleted()) {
             int mark = graph.getMark();
             peel(loop);
-            new CanonicalizerPhase.Instance(runtime, assumptions, canonicalizeReads, mark, null).apply(graph);
+            canonicalizer.applyIncremental(graph, context, mark);
             if (iterations++ > UNROLL_LIMIT || graph.getNodeCount() > MaximumDesiredSize.getValue() * 3) {
                 throw new BailoutException("FullUnroll : Graph seems to grow out of proportion");
             }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,15 +26,16 @@
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class LoopFullUnrollPhase extends BasePhase<PhaseContext> {
 
     private static final DebugMetric FULLY_UNROLLED_LOOPS = Debug.metric("FullUnrolls");
-    private final boolean canonicalizeReads;
+    private final CanonicalizerPhase canonicalizer;
 
-    public LoopFullUnrollPhase(boolean canonicalizeReads) {
-        this.canonicalizeReads = canonicalizeReads;
+    public LoopFullUnrollPhase(CanonicalizerPhase canonicalizer) {
+        this.canonicalizer = canonicalizer;
     }
 
     @Override
@@ -48,7 +49,7 @@
                 for (LoopEx loop : dataCounted.countedLoops()) {
                     if (LoopPolicies.shouldFullUnroll(loop)) {
                         Debug.log("FullUnroll %s", loop);
-                        LoopTransformations.fullUnroll(loop, context.getRuntime(), context.getAssumptions(), canonicalizeReads);
+                        LoopTransformations.fullUnroll(loop, context, canonicalizer);
                         FULLY_UNROLLED_LOOPS.increment();
                         Debug.dump(graph, "After fullUnroll %s", loop);
                         peeled = true;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -32,7 +32,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class AbstractBeginNode extends FixedWithNextNode implements StateSplit, LIRLowerable, Simplifiable, Node.IterableNodeType, GuardingNode {
+public abstract class AbstractBeginNode extends FixedWithNextNode implements StateSplit, LIRLowerable, Simplifiable, GuardingNode, IterableNodeType {
 
     @Input(notDataflow = true) private FrameState stateAfter;
 
@@ -186,8 +186,7 @@
         }
     }
 
-    @Override
-    public AbstractBeginNode asNode() {
-        return this;
+    public FrameState getState() {
+        return stateAfter();
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, 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 com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * 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 #getDeoptimizationState() deoptimization
+ * state}.
+ * 
+ */
+@NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}")
+public abstract class AbstractDeoptimizeNode extends ControlSinkNode implements IterableNodeType, DeoptimizingNode {
+
+    @Input private FrameState deoptState;
+
+    public AbstractDeoptimizeNode() {
+        super(StampFactory.forVoid());
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public FrameState getDeoptimizationState() {
+        return deoptState;
+    }
+
+    @Override
+    public void setDeoptimizationState(FrameState f) {
+        updateUsages(deoptState, f);
+        deoptState = f;
+    }
+
+    public FrameState getState() {
+        return deoptState;
+    }
+
+    public abstract ValueNode getActionAndReason(MetaAccessProvider runtime);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,7 +28,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class AbstractEndNode extends FixedNode implements Node.IterableNodeType, LIRLowerable {
+public abstract class AbstractEndNode extends FixedNode implements IterableNodeType, LIRLowerable {
 
     protected AbstractEndNode() {
         super(StampFactory.forVoid());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java	Wed Oct 02 13:26:31 2013 +0200
@@ -41,6 +41,10 @@
         stateAfter = x;
     }
 
+    public FrameState getState() {
+        return stateAfter();
+    }
+
     public boolean hasSideEffect() {
         return true;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ArrayRangeWriteBarrier.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +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.nodes;
-
-public abstract class ArrayRangeWriteBarrier extends WriteBarrier {
-
-    @Input private ValueNode startIndex;
-    @Input private ValueNode length;
-
-    public ValueNode getStartIndex() {
-        return startIndex;
-    }
-
-    public ValueNode getLength() {
-        return length;
-    }
-
-    public ArrayRangeWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
-        super(object, null, true);
-        this.startIndex = startIndex;
-        this.length = length;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,10 +22,9 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class ControlSinkNode extends FixedNode implements Node.IterableNodeType {
+public abstract class ControlSinkNode extends FixedNode {
 
     public ControlSinkNode(Stamp stamp) {
         super(stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,30 +22,15 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
-/**
- * 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 #getDeoptimizationState() deoptimization
- * state}.
- * 
- */
-@NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}")
-public class DeoptimizeNode extends ControlSinkNode implements Node.IterableNodeType, Lowerable, LIRLowerable, DeoptimizingNode {
-
-    @Input private FrameState deoptState;
+public class DeoptimizeNode extends AbstractDeoptimizeNode implements LIRLowerable {
 
     private final DeoptimizationAction action;
     private final DeoptimizationReason reason;
 
     public DeoptimizeNode(DeoptimizationAction action, DeoptimizationReason reason) {
-        super(StampFactory.forVoid());
         this.action = action;
         this.reason = reason;
     }
@@ -59,36 +44,15 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
+    public void generate(LIRGeneratorTool gen) {
+        gen.emitDeoptimize(gen.getRuntime().encodeDeoptActionAndReason(action, reason), this);
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.emitDeoptimize(action, this);
+    public ValueNode getActionAndReason(MetaAccessProvider runtime) {
+        return ConstantNode.forConstant(runtime.encodeDeoptActionAndReason(action, reason), runtime, graph());
     }
 
     @NodeIntrinsic
     public static native void deopt(@ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter DeoptimizationReason reason);
-
-    @Override
-    public boolean canDeoptimize() {
-        return true;
-    }
-
-    @Override
-    public FrameState getDeoptimizationState() {
-        return deoptState;
-    }
-
-    @Override
-    public void setDeoptimizationState(FrameState f) {
-        updateUsages(deoptState, f);
-        deoptState = f;
-    }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return reason;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -42,4 +42,8 @@
         updateUsages(deoptState, f);
         deoptState = f;
     }
+
+    public FrameState getState() {
+        return deoptState;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,12 +22,12 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.spi.*;
 
 /**
  * Interface implemented by nodes which need deoptimization information.
  */
-public interface DeoptimizingNode {
+public interface DeoptimizingNode extends NodeWithState {
 
     /**
      * Determines if this node needs deoptimization information.
@@ -45,13 +45,4 @@
      * @param state the FrameState which represents the deoptimization information
      */
     void setDeoptimizationState(FrameState state);
-
-    /**
-     * Returns the reason for deoptimization triggered by this node. If deoptimization at this point
-     * can happen for external reasons (i.e. not explicitely triggered by this node) this method can
-     * return null.
-     * 
-     * @return the reason for deoptimization triggered by this node.
-     */
-    DeoptimizationReason getDeoptimizationReason();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, 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 com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.spi.*;
+
+public class DynamicDeoptimizeNode extends AbstractDeoptimizeNode implements LIRLowerable {
+    @Input private ValueNode actionAndReason;
+
+    public DynamicDeoptimizeNode(ValueNode actionAndReason) {
+        this.actionAndReason = actionAndReason;
+    }
+
+    public ValueNode getActionAndReason() {
+        return actionAndReason;
+    }
+
+    @Override
+    public ValueNode getActionAndReason(MetaAccessProvider runtime) {
+        return getActionAndReason();
+    }
+
+    public void generate(LIRGeneratorTool generator) {
+        generator.emitDeoptimize(generator.operand(actionAndReason), this);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,7 +29,7 @@
  * This node will be inserted at point specified by {@link StructuredGraph#getEntryBCI()}, usually
  * by the graph builder.
  */
-public class EntryMarkerNode extends AbstractBeginNode implements Node.IterableNodeType, Simplifiable, LIRLowerable {
+public class EntryMarkerNode extends AbstractBeginNode implements IterableNodeType, Simplifiable, LIRLowerable {
 
     @Override
     public void simplify(SimplifierTool tool) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.extended.*;
@@ -31,7 +30,7 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(nameTemplate = "FixedGuard(!={p#negated}) {p#reason/s}")
-public final class FixedGuardNode extends DeoptimizingFixedWithNextNode implements Simplifiable, Lowerable, Node.IterableNodeType, GuardingNode {
+public final class FixedGuardNode extends DeoptimizingFixedWithNextNode implements Simplifiable, Lowerable, IterableNodeType, GuardingNode {
 
     @Input private LogicNode condition;
     private final DeoptimizationReason reason;
@@ -106,9 +105,12 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        if (loweringType == LoweringType.BEFORE_GUARDS) {
-            tool.getRuntime().lower(this, tool);
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
+            ValueNode guard = tool.createGuard(condition(), getReason(), getAction(), isNegated()).asNode();
+            this.replaceAtUsages(guard);
+            ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(guard.asNode()));
+            graph().replaceFixedWithFixed(this, newAnchor);
         } else {
             FixedNode next = next();
             setNext(null);
@@ -130,17 +132,7 @@
     }
 
     @Override
-    public FixedGuardNode asNode() {
-        return this;
-    }
-
-    @Override
     public boolean canDeoptimize() {
         return true;
     }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return reason;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -35,4 +35,9 @@
         assertTrue(this.successors().isNotEmpty() || this.predecessor() != null, "FixedNode should not float");
         return super.verify();
     }
+
+    @Override
+    public FixedNode asNode() {
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -44,4 +44,9 @@
     public FixedWithNextNode(Stamp stamp) {
         super(stamp);
     }
+
+    @Override
+    public FixedWithNextNode asNode() {
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingGuardedNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingGuardedNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -49,10 +49,4 @@
         updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode());
         this.guard = guard;
     }
-
-    @Override
-    public FloatingNode asNode() {
-        return this;
-    }
-
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed Oct 02 13:26:31 2013 +0200
@@ -35,7 +35,7 @@
  * stack) at a particular point in the abstract interpretation.
  */
 @NodeInfo(nameTemplate = "FrameState@{p#method/s}:{p#bci}")
-public final class FrameState extends VirtualState implements Node.IterableNodeType {
+public final class FrameState extends VirtualState implements IterableNodeType {
 
     protected final int localsSize;
 
@@ -103,7 +103,6 @@
     public FrameState(ResolvedJavaMethod method, int bci, List<ValueNode> values, int localsSize, int stackSize, boolean rethrowException, boolean duringCall,
                     List<EscapeObjectState> virtualObjectMappings) {
         assert stackSize >= 0;
-        assert (bci >= 0 && method != null) || (bci < 0 && method == null && values.isEmpty());
         this.method = method;
         this.bci = bci;
         this.localsSize = localsSize;
@@ -125,29 +124,24 @@
     }
 
     public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, List<ValueNode> stack, ValueNode[] locks, boolean rethrowException, boolean duringCall) {
-        this.method = method;
-        this.bci = bci;
-        this.localsSize = locals.length;
-        this.stackSize = stack.size();
-        final ValueNode[] newValues = new ValueNode[locals.length + stack.size() + locks.length];
-        int pos = 0;
+        this(method, bci, createValues(locals, stack, locks), locals.length, stack.size(), rethrowException, duringCall, Collections.<EscapeObjectState> emptyList());
+    }
+
+    private static List<ValueNode> createValues(ValueNode[] locals, List<ValueNode> stack, ValueNode[] locks) {
+        List<ValueNode> newValues = new ArrayList<>(locals.length + stack.size() + locks.length);
         for (ValueNode value : locals) {
-            newValues[pos++] = value;
+            newValues.add(value);
+            assert value == null || value.isAlive();
         }
         for (ValueNode value : stack) {
-            newValues[pos++] = value;
+            newValues.add(value);
+            assert value == null || value.isAlive();
         }
         for (ValueNode value : locks) {
-            newValues[pos++] = value;
-        }
-        for (ValueNode value : newValues) {
+            newValues.add(value);
             assert value == null || value.isAlive();
         }
-        this.values = new NodeInputList<>(this, newValues);
-        this.virtualObjectMappings = new NodeInputList<>(this);
-        this.rethrowException = rethrowException;
-        this.duringCall = duringCall;
-        assert !rethrowException || stackSize == 1 : "must have exception on top of the stack";
+        return newValues;
     }
 
     public NodeInputList<ValueNode> values() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1ArrayRangePostWriteBarrier.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +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.nodes;
-
-public final class G1ArrayRangePostWriteBarrier extends ArrayRangeWriteBarrier {
-
-    public G1ArrayRangePostWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
-        super(object, startIndex, length);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1ArrayRangePreWriteBarrier.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +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.nodes;
-
-public final class G1ArrayRangePreWriteBarrier extends ArrayRangeWriteBarrier {
-
-    public G1ArrayRangePreWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
-        super(object, startIndex, length);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1PostWriteBarrier.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +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.nodes;
-
-import com.oracle.graal.nodes.extended.*;
-
-public class G1PostWriteBarrier extends WriteBarrier {
-
-    @Input private ValueNode value;
-
-    public ValueNode getValue() {
-        return value;
-    }
-
-    public G1PostWriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
-        super(object, location, precise);
-        this.value = value;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1PreWriteBarrier.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +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.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.extended.*;
-
-public class G1PreWriteBarrier extends WriteBarrier implements DeoptimizingNode {
-
-    @Input private ValueNode expectedObject;
-    private final boolean doLoad;
-
-    @Input private FrameState deoptimizationState;
-    private final boolean nullCheck;
-
-    public ValueNode getExpectedObject() {
-        return expectedObject;
-    }
-
-    public boolean doLoad() {
-        return doLoad;
-    }
-
-    public boolean getNullCheck() {
-        return nullCheck;
-    }
-
-    public G1PreWriteBarrier(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad, boolean nullCheck) {
-        super(object, location, true);
-        this.doLoad = doLoad;
-        this.nullCheck = nullCheck;
-        this.expectedObject = expectedObject;
-    }
-
-    @Override
-    public boolean canDeoptimize() {
-        return nullCheck;
-    }
-
-    @Override
-    public FrameState getDeoptimizationState() {
-        return deoptimizationState;
-    }
-
-    @Override
-    public void setDeoptimizationState(FrameState state) {
-        updateUsages(deoptimizationState, state);
-        deoptimizationState = state;
-    }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return DeoptimizationReason.NullCheckException;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1ReferentFieldReadBarrier.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +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.nodes;
-
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * The {@code G1ReferentFieldReadBarrier} is added when a read access is performed to the referent
- * field of a {@link java.lang.ref.Reference} object (through a {@code LoadFieldNode} or an
- * {@code UnsafeLoadNode}). The return value of the read is passed to the snippet implementing the
- * read barrier and consequently is added to the SATB queue if the concurrent marker is enabled.
- */
-public class G1ReferentFieldReadBarrier extends WriteBarrier {
-
-    @Input private ValueNode expectedObject;
-    private final boolean doLoad;
-
-    public ValueNode getExpectedObject() {
-        return expectedObject;
-    }
-
-    public boolean doLoad() {
-        return doLoad;
-    }
-
-    public G1ReferentFieldReadBarrier(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad) {
-        super(object, location, true);
-        this.doLoad = doLoad;
-        this.expectedObject = expectedObject;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.extended.*;
@@ -42,7 +41,7 @@
  * control flow would have reached the guarded node (without taking exceptions into account).
  */
 @NodeInfo(nameTemplate = "Guard(!={p#negated}) {p#reason/s}")
-public final class GuardNode extends FloatingGuardedNode implements Canonicalizable, Node.IterableNodeType, GuardingNode, GuardedNode {
+public final class GuardNode extends FloatingGuardedNode implements Canonicalizable, IterableNodeType, GuardingNode, GuardedNode {
 
     @Input private LogicNode condition;
     private final DeoptimizationReason reason;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,7 +34,7 @@
  * 
  * A GuardedValueNode will only go away if its guard is null or {@link StructuredGraph#start()}.
  */
-public class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode, Canonicalizable, ValueProxy {
+public class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, GuardingNode, Canonicalizable, ValueProxy {
 
     @Input private ValueNode object;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
@@ -76,14 +75,15 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        if (loweringType == LoweringType.AFTER_GUARDS) {
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
             throw new GraalInternalError("Cannot create guards in after-guard lowering");
         }
-        FixedGuardNode guard = graph().add(new FixedGuardNode(condition, reason, action, negated));
-        PiNode pi = graph().add(new PiNode(object, stamp(), guard));
+        GuardingNode guard = tool.createGuard(condition, reason, action, negated);
+        ValueAnchorNode anchor = graph().add(new ValueAnchorNode((ValueNode) guard));
+        PiNode pi = graph().unique(new PiNode(object, stamp(), (ValueNode) guard));
         replaceAtUsages(pi);
-        graph().replaceFixedWithFixed(this, guard);
+        graph().replaceFixedWithFixed(this, anchor);
     }
 
     @Override
@@ -93,8 +93,17 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
+        if (stamp() == StampFactory.illegal(object.kind())) {
+            // The guard always fails
+            return graph().add(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));
+            }
+
             if (c.getValue() != negated && stamp().equals(object().stamp())) {
                 return object;
             }
@@ -115,11 +124,6 @@
                     @ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter Stamp stamp);
 
     @Override
-    public ValueNode asNode() {
-        return this;
-    }
-
-    @Override
     public ValueNode getOriginalValue() {
         return object;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -578,7 +578,7 @@
                 // removed
                 MergeNode newMerge = graph().add(new MergeNode());
                 PhiNode oldPhi = (PhiNode) oldMerge.usages().first();
-                PhiNode newPhi = graph().add(new PhiNode(oldPhi.stamp(), newMerge));
+                PhiNode newPhi = graph().addWithoutUnique(new PhiNode(oldPhi.stamp(), newMerge));
 
                 for (AbstractEndNode end : ends) {
                     newPhi.addInput(phiValues.get(end));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,20 +23,21 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * Nodes of this type are inserted into the graph to denote points of interest to debugging.
  */
-public class InfopointNode extends AbstractStateSplit implements LIRLowerable, IterableNodeType {
+public class InfopointNode extends FixedWithNextNode implements LIRLowerable, NodeWithState {
 
     public final InfopointReason reason;
+    @Input private FrameState state;
 
-    public InfopointNode(InfopointReason reason) {
+    public InfopointNode(InfopointReason reason, FrameState state) {
         super(StampFactory.forVoid());
         this.reason = reason;
+        this.state = state;
     }
 
     @Override
@@ -44,24 +45,13 @@
         generator.visitInfopointNode(this);
     }
 
-    @Override
-    public boolean hasSideEffect() {
-        return false;
-    }
-
-    @Override
-    public void setStateAfter(FrameState state) {
-        // shield this node from frame state removal
-        // TODO turn InfopointNode into a FixedWithNextNode subclass with a self-maintained
-        // FrameState that is correctly dealt with by scheduling and partial escape analysis
-        if (state != null) {
-            super.setStateAfter(state);
-        }
+    public FrameState getState() {
+        return state;
     }
 
     @Override
     public boolean verify() {
-        return stateAfter() != null && super.verify();
+        return getState() != null && super.verify();
     }
 
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -35,7 +35,7 @@
  * The {@code InvokeNode} represents all kinds of method calls.
  */
 @NodeInfo(nameTemplate = "Invoke#{p#targetMethod/s}")
-public final class InvokeNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, Invoke, LIRLowerable, MemoryCheckpoint.Single {
+public final class InvokeNode extends AbstractStateSplit implements Invoke, LIRLowerable, MemoryCheckpoint.Single {
 
     @Input private CallTargetNode callTarget;
     @Input private FrameState deoptState;
@@ -108,7 +108,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
@@ -133,11 +133,6 @@
     }
 
     @Override
-    public FixedNode asNode() {
-        return this;
-    }
-
-    @Override
     public FrameState stateDuring() {
         FrameState stateAfter = stateAfter();
         if (stateAfter == null) {
@@ -179,11 +174,6 @@
     }
 
     @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return null;
-    }
-
-    @Override
     public FrameState getDeoptimizationState() {
         if (deoptState == null) {
             FrameState stateDuring = stateDuring();
@@ -208,4 +198,14 @@
         updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode());
         this.guard = guard;
     }
+
+    @Override
+    public FrameState getState() {
+        if (deoptState != null) {
+            assert stateAfter() == null;
+            return deoptState;
+        } else {
+            return super.getState();
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -32,7 +32,7 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(nameTemplate = "Invoke!#{p#targetMethod/s}")
-public class InvokeWithExceptionNode extends ControlSplitNode implements Node.IterableNodeType, Invoke, MemoryCheckpoint.Single, LIRLowerable {
+public class InvokeWithExceptionNode extends ControlSplitNode implements IterableNodeType, Invoke, MemoryCheckpoint.Single, LIRLowerable {
 
     private static final double EXCEPTION_PROBA = 1e-5;
 
@@ -119,11 +119,6 @@
     }
 
     @Override
-    public FixedNode asNode() {
-        return this;
-    }
-
-    @Override
     public void setNext(FixedNode x) {
         if (x != null) {
             this.setNext(AbstractBeginNode.begin(x));
@@ -133,7 +128,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
@@ -224,11 +219,6 @@
     }
 
     @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return null;
-    }
-
-    @Override
     public FrameState getDeoptimizationState() {
         if (deoptState == null) {
             FrameState stateDuring = stateDuring();
@@ -253,4 +243,14 @@
         updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode());
         this.guard = guard;
     }
+
+    @Override
+    public FrameState getState() {
+        if (deoptState != null) {
+            assert stateAfter() == null;
+            return deoptState;
+        } else {
+            return stateAfter();
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LocalNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LocalNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,7 +29,7 @@
  * The {@code Local} instruction is a placeholder for an incoming argument to a function call.
  */
 @NodeInfo(nameTemplate = "Local({p#index})")
-public final class LocalNode extends AbstractLocalNode implements Node.IterableNodeType {
+public final class LocalNode extends AbstractLocalNode implements IterableNodeType {
 
     public LocalNode(int index, Stamp stamp) {
         super(index, stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNegationNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNegationNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,7 +28,7 @@
 /**
  * Logic node that negates its argument.
  */
-public class LogicNegationNode extends LogicNode implements Canonicalizable, Node.IterableNodeType {
+public class LogicNegationNode extends LogicNode implements Canonicalizable, IterableNodeType {
 
     @Input private LogicNode input;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -30,4 +30,22 @@
     public LogicNode() {
         super(StampFactory.condition());
     }
+
+    public static LogicNode and(LogicNode a, LogicNode b, double shortCircuitProbability) {
+        return and(a, false, b, false, shortCircuitProbability);
+    }
+
+    public static LogicNode and(LogicNode a, boolean negateA, LogicNode b, boolean negateB, double shortCircuitProbability) {
+        StructuredGraph graph = a.graph();
+        ShortCircuitOrNode notAorNotB = graph.unique(new ShortCircuitOrNode(a, !negateA, b, !negateB, shortCircuitProbability));
+        return graph.unique(new LogicNegationNode(notAorNotB));
+    }
+
+    public static LogicNode or(LogicNode a, LogicNode b, double shortCircuitProbability) {
+        return or(a, false, b, false, shortCircuitProbability);
+    }
+
+    public static LogicNode or(LogicNode a, boolean negateA, LogicNode b, boolean negateB, double shortCircuitProbability) {
+        return a.graph().unique(new ShortCircuitOrNode(a, negateA, b, negateB, shortCircuitProbability));
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,7 +31,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class LoopBeginNode extends MergeNode implements Node.IterableNodeType, LIRLowerable {
+public class LoopBeginNode extends MergeNode implements IterableNodeType, LIRLowerable {
 
     private double loopFrequency;
     private int nextEndIndex;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class LoopExitNode extends BeginStateSplitNode {
+public class LoopExitNode extends BeginStateSplitNode implements IterableNodeType {
 
     @Input(notDataflow = true) private LoopBeginNode loopBegin;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,37 @@
+/*
+ * 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 com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.type.*;
+
+public abstract class MemoryMapNode extends FloatingNode {
+
+    public MemoryMapNode() {
+        super(StampFactory.forVoid());
+    }
+
+    public abstract Node getLastLocationAccess(LocationIdentity locationIdentity);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -33,7 +33,7 @@
 /**
  * Denotes the merging of multiple control-flow paths.
  */
-public class MergeNode extends BeginStateSplitNode implements Node.IterableNodeType, LIRLowerable {
+public class MergeNode extends BeginStateSplitNode implements IterableNodeType, LIRLowerable {
 
     @Input(notDataflow = true) private final NodeInputList<AbstractEndNode> ends = new NodeInputList<>(this);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,7 +34,7 @@
  * variable.
  */
 @NodeInfo(nameTemplate = "{p#type/s}Phi({i#values})")
-public class PhiNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType, GuardingNode {
+public class PhiNode extends FloatingNode implements Canonicalizable, IterableNodeType, GuardingNode {
 
     public static enum PhiType {
         Value(null), // normal value phis
@@ -248,9 +248,4 @@
     public boolean isLoopPhi() {
         return merge() instanceof LoopBeginNode;
     }
-
-    @Override
-    public PhiNode asNode() {
-        return this;
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiArrayNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012, 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.nodes;
+
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * A {@link PiNode} that also provides an array length in addition to a more refined stamp. A usage
+ * that reads the array length, such as an {@link ArrayLengthNode}, can be canonicalized base on
+ * this information.
+ */
+public final class PiArrayNode extends PiNode implements ArrayLengthProvider {
+
+    @Input private ValueNode length;
+
+    public ValueNode length() {
+        return length;
+    }
+
+    public PiArrayNode(ValueNode object, ValueNode length, Stamp stamp) {
+        super(object, stamp);
+        this.length = length;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (!(object() instanceof ArrayLengthProvider) || length() != ((ArrayLengthProvider) object()).length()) {
+            return this;
+        }
+        return super.canonical(tool);
+    }
+
+    @NodeIntrinsic
+    public static native <T> T piArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,7 +36,7 @@
  * is as narrow or narrower than the PiNode's type. The PiNode, and therefore also the scheduling
  * restriction enforced by the anchor, will go away.
  */
-public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode, Canonicalizable, ValueProxy {
+public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, GuardingNode, Canonicalizable, ValueProxy {
 
     @Input private ValueNode object;
 
@@ -49,11 +49,15 @@
         this.object = object;
     }
 
-    public PiNode(ValueNode object, Stamp stamp, GuardingNode anchor) {
-        super(stamp, anchor);
+    public PiNode(ValueNode object, Stamp stamp, ValueNode anchor) {
+        super(stamp, (GuardingNode) anchor);
         this.object = object;
     }
 
+    public PiNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
+        this(object, StampFactory.object(toType, exactType, nonNull || ObjectStamp.isObjectNonNull(object.stamp())));
+    }
+
     @Override
     public void generate(LIRGeneratorTool generator) {
         if (object.kind() != Kind.Void && object.kind() != Kind.Illegal) {
@@ -63,6 +67,9 @@
 
     @Override
     public boolean inferStamp() {
+        if (stamp() == StampFactory.forNodeIntrinsic()) {
+            return false;
+        }
         return updateStamp(stamp().join(object().stamp()));
     }
 
@@ -70,6 +77,7 @@
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object);
         if (state != null && state.getState() == EscapeState.Virtual) {
+            assert ObjectStamp.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type());
             tool.replaceWithVirtual(state.getVirtualObject());
         }
     }
@@ -87,4 +95,16 @@
     public ValueNode getOriginalValue() {
         return object;
     }
+
+    @NodeIntrinsic
+    public static native <T> T piCast(Object object, @ConstantNodeParameter Stamp stamp);
+
+    @NodeIntrinsic
+    public static native <T> T piCast(Object object, @ConstantNodeParameter Stamp stamp, GuardingNode anchor);
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static <T> T piCast(Object object, @ConstantNodeParameter Class<T> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull) {
+        return toType.cast(object);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -35,7 +35,7 @@
  * loop.
  */
 @NodeInfo(nameTemplate = "{p#type/s}Proxy")
-public class ProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable, ValueProxy, GuardingNode {
+public class ProxyNode extends FloatingNode implements IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable, ValueProxy, GuardingNode {
 
     @Input(notDataflow = true) private AbstractBeginNode proxyPoint;
     @Input private ValueNode value;
@@ -120,8 +120,4 @@
     public ValueNode getOriginalValue() {
         return value;
     }
-
-    public ValueNode asNode() {
-        return this;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,13 +22,13 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public final class ReturnNode extends ControlSinkNode implements LIRLowerable, Node.IterableNodeType {
+public final class ReturnNode extends ControlSinkNode implements LIRLowerable {
 
     @Input private ValueNode result;
+    @Input private MemoryMapNode memoryMap;
 
     public ValueNode result() {
         return result;
@@ -41,8 +41,13 @@
      *            void return
      */
     public ReturnNode(ValueNode result) {
+        this(result, null);
+    }
+
+    public ReturnNode(ValueNode result, MemoryMapNode memoryMap) {
         super(StampFactory.forVoid());
         this.result = result;
+        this.memoryMap = memoryMap;
     }
 
     @Override
@@ -54,4 +59,13 @@
     public void generate(LIRGeneratorTool gen) {
         gen.visitReturn(this);
     }
+
+    public void setMemoryMap(MemoryMapNode memoryMap) {
+        updateUsages(this.memoryMap, memoryMap);
+        this.memoryMap = memoryMap;
+    }
+
+    public MemoryMapNode getMemoryMap() {
+        return memoryMap;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,22 +22,16 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * Marks a position in the graph where a safepoint should be emitted.
  */
-public class SafepointNode extends DeoptimizingFixedWithNextNode implements LIRLowerable, Node.IterableNodeType {
+public class SafepointNode extends DeoptimizingFixedWithNextNode implements LIRLowerable {
 
     public SafepointNode() {
-        this(StampFactory.forVoid());
-    }
-
-    public SafepointNode(Stamp stamp) {
-        super(stamp);
+        super(StampFactory.forVoid());
     }
 
     @Override
@@ -46,11 +40,6 @@
     }
 
     @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return null;
-    }
-
-    @Override
     public boolean canDeoptimize() {
         return true;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialArrayRangeWriteBarrier.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +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.nodes;
-
-public final class SerialArrayRangeWriteBarrier extends ArrayRangeWriteBarrier {
-
-    public SerialArrayRangeWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
-        super(object, startIndex, length);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +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.nodes;
-
-import com.oracle.graal.nodes.extended.*;
-
-public class SerialWriteBarrier extends WriteBarrier {
-
-    @Input private ValueNode value;
-
-    public ValueNode getValue() {
-        return value;
-    }
-
-    public SerialWriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
-        super(object, location, precise);
-        this.value = value;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitAndNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.nodes.spi.*;
-
-/**
- * The short-circuit <b>AND</b> (i.e. {@code &&} in Java) operator.
- */
-public class ShortCircuitAndNode extends ShortCircuitBooleanNode implements Canonicalizable {
-
-    public ShortCircuitAndNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, double shortCircuitProbability) {
-        super(x, xNegated, y, yNegated, shortCircuitProbability);
-    }
-
-    @Override
-    public LogicNode canonical(CanonicalizerTool tool) {
-        ShortCircuitBooleanNode ret = canonicalizeNegation();
-        if (ret != null) {
-            return ret;
-        }
-
-        LogicNode x = getX();
-        LogicNode y = getY();
-        if (x == y) {
-            // @formatter:off
-            //  a &&  a = a
-            //  a && !a = false
-            // !a &&  a = false
-            // !a && !a = !a
-            // @formatter:on
-            if (isXNegated()) {
-                if (isYNegated()) {
-                    // !a && !a = !a
-                    return graph().unique(new LogicNegationNode(x));
-                } else {
-                    // !a && a = false
-                    return LogicConstantNode.contradiction(graph());
-                }
-            } else {
-                if (isYNegated()) {
-                    // a && !a = false
-                    return LogicConstantNode.contradiction(graph());
-                } else {
-                    // a && a = a
-                    return x;
-                }
-            }
-        }
-        if (x instanceof LogicConstantNode) {
-            if (((LogicConstantNode) x).getValue() ^ isXNegated()) {
-                if (isYNegated()) {
-                    return graph().unique(new LogicNegationNode(y));
-                } else {
-                    return y;
-                }
-            } else {
-                return LogicConstantNode.contradiction(graph());
-            }
-        }
-        if (y instanceof LogicConstantNode) {
-            if (((LogicConstantNode) y).getValue() ^ isYNegated()) {
-                if (isXNegated()) {
-                    return graph().unique(new LogicNegationNode(x));
-                } else {
-                    return x;
-                }
-            } else {
-                return LogicConstantNode.contradiction(graph());
-            }
-        }
-        return this;
-    }
-
-    @Override
-    protected ShortCircuitBooleanNode createCopy(LogicNode xCond, boolean xNeg, LogicNode yCond, boolean yNeg, double probability) {
-        return new ShortCircuitAndNode(xCond, xNeg, yCond, yNeg, probability);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitBooleanNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.graph.*;
-
-/**
- * Base class for the short-circuit boolean operators.
- */
-public abstract class ShortCircuitBooleanNode extends LogicNode implements Node.IterableNodeType {
-
-    @Input private LogicNode x;
-    @Input private LogicNode y;
-    private boolean xNegated;
-    private boolean yNegated;
-    private double shortCircuitProbability;
-
-    public ShortCircuitBooleanNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, double shortCircuitProbability) {
-        this.x = x;
-        this.xNegated = xNegated;
-        this.y = y;
-        this.yNegated = yNegated;
-        this.shortCircuitProbability = shortCircuitProbability;
-    }
-
-    public LogicNode getX() {
-        return x;
-    }
-
-    public LogicNode getY() {
-        return y;
-    }
-
-    public boolean isXNegated() {
-        return xNegated;
-    }
-
-    public boolean isYNegated() {
-        return yNegated;
-    }
-
-    /**
-     * Gets the probability that the {@link #getY() y} part of this binary node is <b>not</b>
-     * evaluated. This is the probability that this operator will short-circuit its execution.
-     */
-    public double getShortCircuitProbability() {
-        return shortCircuitProbability;
-    }
-
-    protected abstract ShortCircuitBooleanNode createCopy(LogicNode xCond, boolean xNeg, LogicNode yCond, boolean yNeg, double probability);
-
-    protected ShortCircuitBooleanNode canonicalizeNegation() {
-        LogicNode xCond = x;
-        boolean xNeg = xNegated;
-        while (xCond instanceof LogicNegationNode) {
-            xCond = ((LogicNegationNode) xCond).getInput();
-            xNeg = !xNeg;
-        }
-
-        LogicNode yCond = y;
-        boolean yNeg = yNegated;
-        while (yCond instanceof LogicNegationNode) {
-            yCond = ((LogicNegationNode) yCond).getInput();
-            yNeg = !yNeg;
-        }
-
-        if (xCond != x || yCond != y) {
-            return graph().unique(createCopy(xCond, xNeg, yCond, yNeg, shortCircuitProbability));
-        } else {
-            return null;
-        }
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitOrNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitOrNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,27 +22,79 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
 
-/**
- * The short-circuit <b>OR</b> (i.e. {@code ||} in Java) operator.
- */
-public class ShortCircuitOrNode extends ShortCircuitBooleanNode implements Canonicalizable {
+public class ShortCircuitOrNode extends LogicNode implements IterableNodeType, Canonicalizable {
+
+    @Input private LogicNode x;
+    @Input private LogicNode y;
+    private boolean xNegated;
+    private boolean yNegated;
+    private double shortCircuitProbability;
 
     public ShortCircuitOrNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, double shortCircuitProbability) {
-        super(x, xNegated, y, yNegated, shortCircuitProbability);
+        this.x = x;
+        this.xNegated = xNegated;
+        this.y = y;
+        this.yNegated = yNegated;
+        this.shortCircuitProbability = shortCircuitProbability;
+    }
+
+    public LogicNode getX() {
+        return x;
+    }
+
+    public LogicNode getY() {
+        return y;
+    }
+
+    public boolean isXNegated() {
+        return xNegated;
+    }
+
+    public boolean isYNegated() {
+        return yNegated;
+    }
+
+    /**
+     * Gets the probability that the {@link #getY() y} part of this binary node is <b>not</b>
+     * evaluated. This is the probability that this operator will short-circuit its execution.
+     */
+    public double getShortCircuitProbability() {
+        return shortCircuitProbability;
+    }
+
+    protected ShortCircuitOrNode canonicalizeNegation() {
+        LogicNode xCond = x;
+        boolean xNeg = xNegated;
+        while (xCond instanceof LogicNegationNode) {
+            xCond = ((LogicNegationNode) xCond).getInput();
+            xNeg = !xNeg;
+        }
+
+        LogicNode yCond = y;
+        boolean yNeg = yNegated;
+        while (yCond instanceof LogicNegationNode) {
+            yCond = ((LogicNegationNode) yCond).getInput();
+            yNeg = !yNeg;
+        }
+
+        if (xCond != x || yCond != y) {
+            return graph().unique(new ShortCircuitOrNode(xCond, xNeg, yCond, yNeg, shortCircuitProbability));
+        } else {
+            return null;
+        }
     }
 
     @Override
     public LogicNode canonical(CanonicalizerTool tool) {
-        ShortCircuitBooleanNode ret = canonicalizeNegation();
+        ShortCircuitOrNode ret = canonicalizeNegation();
         if (ret != null) {
             return ret;
         }
 
-        LogicNode x = getX();
-        LogicNode y = getY();
-        if (x == y) {
+        if (getX() == getY()) {
             // @formatter:off
             //  a ||  a = a
             //  a || !a = true
@@ -52,7 +104,7 @@
             if (isXNegated()) {
                 if (isYNegated()) {
                     // !a || !a = !a
-                    return graph().unique(new LogicNegationNode(x));
+                    return graph().unique(new LogicNegationNode(getX()));
                 } else {
                     // !a || a = true
                     return LogicConstantNode.tautology(graph());
@@ -63,37 +115,32 @@
                     return LogicConstantNode.tautology(graph());
                 } else {
                     // a || a = a
-                    return x;
+                    return getX();
                 }
             }
         }
-        if (x instanceof LogicConstantNode) {
-            if (((LogicConstantNode) x).getValue() ^ isXNegated()) {
+        if (getX() instanceof LogicConstantNode) {
+            if (((LogicConstantNode) getX()).getValue() ^ isXNegated()) {
                 return LogicConstantNode.tautology(graph());
             } else {
                 if (isYNegated()) {
-                    return graph().unique(new LogicNegationNode(y));
+                    return graph().unique(new LogicNegationNode(getY()));
                 } else {
-                    return y;
+                    return getY();
                 }
             }
         }
-        if (y instanceof LogicConstantNode) {
-            if (((LogicConstantNode) y).getValue() ^ isYNegated()) {
+        if (getY() instanceof LogicConstantNode) {
+            if (((LogicConstantNode) getY()).getValue() ^ isYNegated()) {
                 return LogicConstantNode.tautology(graph());
             } else {
                 if (isXNegated()) {
-                    return graph().unique(new LogicNegationNode(x));
+                    return graph().unique(new LogicNegationNode(getX()));
                 } else {
-                    return x;
+                    return getX();
                 }
             }
         }
         return this;
     }
-
-    @Override
-    protected ShortCircuitBooleanNode createCopy(LogicNode xCond, boolean xNeg, LogicNode yCond, boolean yNeg, double probability) {
-        return new ShortCircuitOrNode(xCond, xNeg, yCond, yNeg, probability);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,10 +22,12 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.nodes.spi.*;
+
 /**
  * A state split is a node that may have a frame state associated with it.
  */
-public interface StateSplit {
+public interface StateSplit extends NodeWithState {
 
     /**
      * Gets the state of the JVM frame after execution of this node.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Wed Oct 02 13:26:31 2013 +0200
@@ -37,6 +37,35 @@
  */
 public class StructuredGraph extends Graph {
 
+    /**
+     * The different stages of the compilation of a {@link Graph} regarding the status of
+     * {@link GuardNode guards}, {@link DeoptimizingNode deoptimizations} and {@link FrameState
+     * framestates}. The stage of a graph progresses monotonously.
+     * 
+     */
+    public static enum GuardsStage {
+        /**
+         * During this stage, there can be {@link FloatingNode floating} {@link DeoptimizingNode}
+         * such as {@link GuardNode GuardNodes}. New {@link DeoptimizingNode DeoptimizingNodes} can
+         * be introduced without constraints. {@link FrameState} nodes are associated with
+         * {@link StateSplit} nodes.
+         */
+        FLOATING_GUARDS,
+        /**
+         * During this stage, all {@link DeoptimizingNode DeoptimizingNodes} must be
+         * {@link FixedNode fixed} but new {@link DeoptimizingNode DeoptimizingNodes} can still be
+         * introduced. {@link FrameState} nodes are still associated with {@link StateSplit} nodes.
+         */
+        FIXED_DEOPTS,
+        /**
+         * During this stage, all {@link DeoptimizingNode DeoptimizingNodes} must be
+         * {@link FixedNode fixed}. New {@link DeoptimizingNode DeoptimizingNodes} can not be
+         * introduced any more. {@link FrameState} nodes are now associated with
+         * {@link DeoptimizingNode} nodes.
+         */
+        AFTER_FSA
+    }
+
     public static final int INVOCATION_ENTRY_BCI = -1;
     public static final long INVALID_GRAPH_ID = -1;
 
@@ -48,6 +77,8 @@
     private final ResolvedJavaMethod method;
     private final long graphId;
     private final int entryBCI;
+    private GuardsStage guardsStage = GuardsStage.FLOATING_GUARDS;
+    private boolean isAfterFloatingReadPhase = false;
 
     /**
      * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
@@ -148,7 +179,7 @@
         StructuredGraph copy = new StructuredGraph(newName, newMethod, graphId, entryBCI);
         HashMap<Node, Node> replacements = new HashMap<>();
         replacements.put(start, copy.start);
-        copy.addDuplicates(getNodes(), replacements);
+        copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements);
         return copy;
     }
 
@@ -386,4 +417,22 @@
             singleEnd.replaceAndDelete(sux);
         }
     }
+
+    public GuardsStage getGuardsStage() {
+        return guardsStage;
+    }
+
+    public void setGuardsStage(GuardsStage guardsStage) {
+        assert guardsStage.ordinal() >= this.guardsStage.ordinal();
+        this.guardsStage = guardsStage;
+    }
+
+    public boolean isAfterFloatingReadPhase() {
+        return isAfterFloatingReadPhase;
+    }
+
+    public void setAfterFloatingReadPhase(boolean state) {
+        assert state : "cannot 'unapply' floating read phase on graph";
+        isAfterFloatingReadPhase = state;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -32,7 +32,7 @@
 /**
  * A node that attaches a type profile to a proxied input node.
  */
-public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType, ValueProxy {
+public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, IterableNodeType, ValueProxy {
 
     @Input private ValueNode object;
     private final JavaTypeProfile profile;
@@ -52,7 +52,7 @@
             // Only null profiling is not beneficial enough to keep the node around.
             return object;
         }
-        return object.graph().add(new TypeProfileProxyNode(object, profile));
+        return object.graph().addWithoutUnique(new TypeProfileProxyNode(object, profile));
     }
 
     private TypeProfileProxyNode(ValueNode object, JavaTypeProfile profile) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,14 +23,13 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * Unwinds the current frame to an exception handler in the caller frame.
  */
-public final class UnwindNode extends ControlSinkNode implements Lowerable, LIRLowerable, Node.IterableNodeType {
+public final class UnwindNode extends ControlSinkNode implements LIRLowerable {
 
     @Input private ValueNode exception;
 
@@ -48,9 +47,4 @@
     public void generate(LIRGeneratorTool gen) {
         gen.emitUnwind(gen.operand(exception()));
     }
-
-    @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -140,4 +140,8 @@
         assertTrue(kind() == kind().getStackKind(), "Should have a stack kind : %s", kind());
         return super.verify();
     }
+
+    public ValueNode asNode() {
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/WriteBarrier.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +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.nodes;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-public abstract class WriteBarrier extends FixedWithNextNode implements Lowerable, Node.IterableNodeType {
-
-    @Input private ValueNode object;
-    @Input private LocationNode location;
-    private final boolean precise;
-
-    public ValueNode getObject() {
-        return object;
-    }
-
-    public LocationNode getLocation() {
-        return location;
-    }
-
-    public boolean usePrecise() {
-        return precise;
-    }
-
-    public WriteBarrier(ValueNode object, LocationNode location, boolean precise) {
-        super(StampFactory.forVoid());
-        this.object = object;
-        this.location = location;
-        this.precise = precise;
-    }
-
-    @Override
-    public void lower(LoweringTool generator, LoweringType loweringType) {
-        assert loweringType == LoweringType.AFTER_FSA;
-        generator.getRuntime().lower(this, generator);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -41,6 +41,12 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() & inputs[1].asLong(), null);
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x() == y()) {
             return x();
@@ -49,12 +55,7 @@
             return graph().unique(new AndNode(kind(), y(), x()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() & y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() & y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             if (kind() == Kind.Int) {
                 int c = y().asConstant().asInt();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -150,14 +150,22 @@
         return null;
     }
 
+    //@formatter:off
     /*
      * In reassociate, complexity comes from the handling of IntegerSub (non commutative) which can
-     * be mixed with IntegerAdd. if first tries to find m1, m2 which match the criterion : (a o m2)
-     * o m1 (m2 o a) o m1 m1 o (a o m2) m1 o (m2 o a) It then produces 4 boolean for the -/+ case
-     * invertA : should the final expression be like *-a (rather than a+*) aSub : should the final
-     * expression be like a-* (rather than a+*) invertM1 : should the final expression contain -m1
+     * be mixed with IntegerAdd. It first tries to find m1, m2 which match the criterion :
+     * (a o m2) o m1
+     * (m2 o a) o m1
+     * m1 o (a o m2)
+     * m1 o (m2 o a)
+     * It then produces 4 boolean for the -/+ cases:
+     * invertA : should the final expression be like *-a (rather than a+*)
+     * aSub : should the final expression be like a-* (rather than a+*)
+     * invertM1 : should the final expression contain -m1
      * invertM2 : should the final expression contain -m2
+     *
      */
+    //@formatter:on
     /**
      * Tries to re-associate values which satisfy the criterion. For example with a constantness
      * criterion : (a + 2) + 1 => a + (1 + 2)<br>
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -116,7 +116,7 @@
     }
 
     private ConditionalNode(ValueNode type, ValueNode object) {
-        this(type.graph().add(new InstanceOfDynamicNode(type, object)));
+        this(type.graph().unique(new InstanceOfDynamicNode(type, object)));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -150,52 +150,59 @@
         this.value = value;
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 1;
+        Constant c = inputs[0];
+        switch (opcode) {
+            case I2L:
+                return Constant.forLong(c.asInt());
+            case L2I:
+                return Constant.forInt((int) c.asLong());
+            case I2B:
+                return Constant.forByte((byte) c.asInt());
+            case I2C:
+                return Constant.forChar((char) c.asInt());
+            case I2S:
+                return Constant.forShort((short) c.asInt());
+            case F2D:
+                return Constant.forDouble(c.asFloat());
+            case D2F:
+                return Constant.forFloat((float) c.asDouble());
+            case I2F:
+                return Constant.forFloat(c.asInt());
+            case I2D:
+                return Constant.forDouble(c.asInt());
+            case F2I:
+                return Constant.forInt((int) c.asFloat());
+            case D2I:
+                return Constant.forInt((int) c.asDouble());
+            case L2F:
+                return Constant.forFloat(c.asLong());
+            case L2D:
+                return Constant.forDouble(c.asLong());
+            case F2L:
+                return Constant.forLong((long) c.asFloat());
+            case D2L:
+                return Constant.forLong((long) c.asDouble());
+            case UNSIGNED_I2L:
+                return Constant.forLong(c.asInt() & 0xffffffffL);
+            case MOV_I2F:
+                return Constant.forFloat(java.lang.Float.intBitsToFloat(c.asInt()));
+            case MOV_L2D:
+                return Constant.forDouble(java.lang.Double.longBitsToDouble(c.asLong()));
+            case MOV_F2I:
+                return Constant.forInt(java.lang.Float.floatToRawIntBits(c.asFloat()));
+            case MOV_D2L:
+                return Constant.forLong(java.lang.Double.doubleToRawLongBits(c.asDouble()));
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (value instanceof ConstantNode) {
-            Constant c = ((ConstantNode) value).asConstant();
-            switch (opcode) {
-                case I2L:
-                    return ConstantNode.forLong(c.asInt(), graph());
-                case L2I:
-                    return ConstantNode.forInt((int) c.asLong(), graph());
-                case I2B:
-                    return ConstantNode.forByte((byte) c.asInt(), graph());
-                case I2C:
-                    return ConstantNode.forChar((char) c.asInt(), graph());
-                case I2S:
-                    return ConstantNode.forShort((short) c.asInt(), graph());
-                case F2D:
-                    return ConstantNode.forDouble(c.asFloat(), graph());
-                case D2F:
-                    return ConstantNode.forFloat((float) c.asDouble(), graph());
-                case I2F:
-                    return ConstantNode.forFloat(c.asInt(), graph());
-                case I2D:
-                    return ConstantNode.forDouble(c.asInt(), graph());
-                case F2I:
-                    return ConstantNode.forInt((int) c.asFloat(), graph());
-                case D2I:
-                    return ConstantNode.forInt((int) c.asDouble(), graph());
-                case L2F:
-                    return ConstantNode.forFloat(c.asLong(), graph());
-                case L2D:
-                    return ConstantNode.forDouble(c.asLong(), graph());
-                case F2L:
-                    return ConstantNode.forLong((long) c.asFloat(), graph());
-                case D2L:
-                    return ConstantNode.forLong((long) c.asDouble(), graph());
-                case UNSIGNED_I2L:
-                    return ConstantNode.forLong(c.asInt() & 0xffffffffL, graph());
-                case MOV_I2F:
-                    return ConstantNode.forFloat(java.lang.Float.intBitsToFloat(c.asInt()), graph());
-                case MOV_L2D:
-                    return ConstantNode.forDouble(java.lang.Double.longBitsToDouble(c.asLong()), graph());
-                case MOV_F2I:
-                    return ConstantNode.forInt(java.lang.Float.floatToRawIntBits(c.asFloat()), graph());
-                case MOV_D2L:
-                    return ConstantNode.forLong(java.lang.Double.doubleToRawLongBits(c.asDouble()), graph());
-            }
+        if (value.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(value.asConstant()), graph());
         }
         return this;
     }
@@ -235,7 +242,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -44,9 +44,4 @@
         this.x = x;
         this.y = y;
     }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return DeoptimizationReason.ArithmeticException;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,18 +34,23 @@
         super(kind, x, y, isStrictFP);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Float) {
+            return Constant.forFloat(x().asConstant().asFloat() + y().asConstant().asFloat());
+        } else {
+            assert kind() == Kind.Double;
+            return Constant.forDouble(x().asConstant().asDouble() + y().asConstant().asDouble());
+        }
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
             return graph().unique(new FloatAddNode(kind(), y(), x(), isStrictFP()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Float) {
-                return ConstantNode.forFloat(x().asConstant().asFloat() + y().asConstant().asFloat(), graph());
-            } else {
-                assert kind() == Kind.Double;
-                return ConstantNode.forDouble(x().asConstant().asDouble() + y().asConstant().asDouble(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             if (kind() == Kind.Float) {
                 float c = y().asConstant().asFloat();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,19 +34,20 @@
         super(kind, x, y, isStrictFP);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Float) {
+            return Constant.forFloat(x().asConstant().asFloat() / y().asConstant().asFloat());
+        } else {
+            assert kind() == Kind.Double;
+            return Constant.forDouble(x().asConstant().asDouble() / y().asConstant().asDouble());
+        }
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x().isConstant() && y().isConstant()) {
-            if (kind() == Kind.Float) {
-                if (y().asConstant().asFloat() != 0) {
-                    return ConstantNode.forFloat(x().asConstant().asFloat() / y().asConstant().asFloat(), graph());
-                }
-            } else {
-                assert kind() == Kind.Double;
-                if (y().asConstant().asDouble() != 0) {
-                    return ConstantNode.forDouble(x().asConstant().asDouble() / y().asConstant().asDouble(), graph());
-                }
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,18 +34,23 @@
         super(kind, x, y, isStrictFP);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Float) {
+            return Constant.forFloat(x().asConstant().asFloat() * y().asConstant().asFloat());
+        } else {
+            assert kind() == Kind.Double;
+            return Constant.forDouble(x().asConstant().asDouble() * y().asConstant().asDouble());
+        }
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
             return graph().unique(new FloatMulNode(kind(), y(), x(), isStrictFP()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Float) {
-                return ConstantNode.forFloat(x().asConstant().asFloat() * y().asConstant().asFloat(), graph());
-            } else {
-                assert kind() == Kind.Double;
-                return ConstantNode.forDouble(x().asConstant().asDouble() * y().asConstant().asDouble(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,15 +34,20 @@
         super(kind, x, y, isStrictFP);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Float) {
+            return Constant.forFloat(x().asConstant().asFloat() % y().asConstant().asFloat());
+        } else {
+            assert kind() == Kind.Double;
+            return Constant.forDouble(x().asConstant().asDouble() % y().asConstant().asDouble());
+        }
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x().isConstant() && y().isConstant()) {
-            if (kind() == Kind.Float) {
-                return ConstantNode.forFloat(x().asConstant().asFloat() % y().asConstant().asFloat(), graph());
-            } else {
-                assert kind() == Kind.Double;
-                return ConstantNode.forDouble(x().asConstant().asDouble() % y().asConstant().asDouble(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,18 +34,23 @@
         super(kind, x, y, isStrictFP);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Float) {
+            return Constant.forFloat(x().asConstant().asFloat() - y().asConstant().asFloat());
+        } else {
+            assert kind() == Kind.Double;
+            return Constant.forDouble(x().asConstant().asDouble() - y().asConstant().asDouble());
+        }
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x() == y()) {
             return ConstantNode.forFloatingKind(kind(), 0.0f, graph());
         }
         if (x().isConstant() && y().isConstant()) {
-            if (kind() == Kind.Float) {
-                return ConstantNode.forFloat(x().asConstant().asFloat() - y().asConstant().asFloat(), graph());
-            } else {
-                assert kind() == Kind.Double;
-                return ConstantNode.forDouble(x().asConstant().asDouble() - y().asConstant().asDouble(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             if (kind() == Kind.Float) {
                 float c = y().asConstant().asFloat();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,4 +31,9 @@
     public FloatingNode(Stamp stamp) {
         super(stamp);
     }
+
+    @Override
+    public FloatingNode asNode() {
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -41,6 +41,12 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() + inputs[1].asLong(), null);
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
             return graph().unique(new IntegerAddNode(kind(), y(), x()));
@@ -60,12 +66,7 @@
             }
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() + y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() + y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             long c = y().asConstant().asLong();
             if (c == 0) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -110,7 +110,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,17 +36,18 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() * inputs[1].asLong(), null);
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
             return graph().unique(new IntegerMulNode(kind(), y(), x()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() * y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() * y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             long c = y().asConstant().asLong();
             if (c == 1) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -61,7 +61,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -41,6 +41,12 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() - inputs[1].asLong(), null);
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x() == y()) {
             return ConstantNode.forIntegerKind(kind(), 0, graph());
@@ -80,12 +86,7 @@
             }
         }
         if (x().isConstant() && y().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() - y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() - y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             long c = y().asConstant().asLong();
             if (c == 0) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -41,8 +41,21 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Int) {
+            return Constant.forInt(inputs[0].asInt() << inputs[1].asInt());
+        } else {
+            assert kind() == Kind.Long;
+            return Constant.forLong(inputs[0].asLong() << inputs[1].asLong());
+        }
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (y().isConstant()) {
+        if (x().isConstant() && y().isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+        } else if (y().isConstant()) {
             int amount = y().asConstant().asInt();
             int originalAmout = amount;
             int mask;
@@ -53,14 +66,6 @@
                 mask = 0x3f;
             }
             amount &= mask;
-            if (x().isConstant()) {
-                if (kind() == Kind.Int) {
-                    return ConstantNode.forInt(x().asConstant().asInt() << amount, graph());
-                } else {
-                    assert kind() == Kind.Long;
-                    return ConstantNode.forLong(x().asConstant().asLong() << amount, graph());
-                }
-            }
             if (amount == 0) {
                 return x();
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -52,19 +54,26 @@
         this.x = x;
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 1;
+        switch (inputs[0].getKind()) {
+            case Int:
+                return Constant.forInt(-inputs[0].asInt());
+            case Long:
+                return Constant.forLong(-inputs[0].asLong());
+            case Float:
+                return Constant.forFloat(-inputs[0].asFloat());
+            case Double:
+                return Constant.forDouble(-inputs[0].asDouble());
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x().isConstant()) {
-            switch (x().kind()) {
-                case Int:
-                    return ConstantNode.forInt(-x().asConstant().asInt(), graph());
-                case Long:
-                    return ConstantNode.forLong(-x().asConstant().asLong(), graph());
-                case Float:
-                    return ConstantNode.forFloat(-x().asConstant().asFloat(), graph());
-                case Double:
-                    return ConstantNode.forDouble(-x().asConstant().asDouble(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x.asConstant()), graph());
         }
         if (x() instanceof NegateNode) {
             return ((NegateNode) x()).x();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -48,7 +48,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         LogicNode equalComp;
         LogicNode lessComp;
         if (x().kind() == Kind.Double || x().kind() == Kind.Float) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -43,6 +43,12 @@
         return updateStamp(StampTool.not(x().stamp()));
     }
 
+    @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 1;
+        return Constant.forIntegerKind(kind(), ~inputs[0].asLong(), null);
+    }
+
     /**
      * Creates new NegateNode instance.
      * 
@@ -57,12 +63,7 @@
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x().isConstant()) {
-            switch (x().kind()) {
-                case Int:
-                    return ConstantNode.forInt(~x().asConstant().asInt(), graph());
-                case Long:
-                    return ConstantNode.forLong(~x().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant()), graph());
         }
         if (x() instanceof NotNode) {
             return ((NotNode) x()).x();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -41,6 +41,12 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() | inputs[1].asLong(), null);
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x() == y()) {
             return x();
@@ -49,12 +55,7 @@
             return graph().unique(new OrNode(kind(), y(), x()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() | y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() | y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             if (kind() == Kind.Int) {
                 int c = y().asConstant().asInt();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,11 +36,24 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Int) {
+            return Constant.forInt(inputs[0].asInt() >> inputs[1].asInt());
+        } else {
+            assert kind() == Kind.Long;
+            return Constant.forLong(inputs[0].asLong() >> inputs[1].asLong());
+        }
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x().stamp() instanceof IntegerStamp && ((IntegerStamp) x().stamp()).isPositive()) {
             return graph().unique(new UnsignedRightShiftNode(kind(), x(), y()));
         }
-        if (y().isConstant()) {
+        if (x().isConstant() && y().isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+        } else if (y().isConstant()) {
             int amount = y().asConstant().asInt();
             int originalAmout = amount;
             int mask;
@@ -51,14 +64,6 @@
                 mask = 0x3f;
             }
             amount &= mask;
-            if (x().isConstant()) {
-                if (kind() == Kind.Int) {
-                    return ConstantNode.forInt(x().asConstant().asInt() >> amount, graph());
-                } else {
-                    assert kind() == Kind.Long;
-                    return ConstantNode.forLong(x().asConstant().asLong() >> amount, graph());
-                }
-            }
             if (amount == 0) {
                 return x();
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -62,7 +62,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -61,7 +61,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -41,8 +41,21 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Int) {
+            return Constant.forInt(inputs[0].asInt() >>> inputs[1].asInt());
+        } else {
+            assert kind() == Kind.Long;
+            return Constant.forLong(inputs[0].asLong() >>> inputs[1].asLong());
+        }
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (y().isConstant()) {
+        if (x().isConstant() && y().isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+        } else if (y().isConstant()) {
             int amount = y().asConstant().asInt();
             int originalAmout = amount;
             int mask;
@@ -53,14 +66,6 @@
                 mask = 0x3f;
             }
             amount &= mask;
-            if (x().isConstant()) {
-                if (kind() == Kind.Int) {
-                    return ConstantNode.forInt(x().asConstant().asInt() >>> amount, graph());
-                } else {
-                    assert kind() == Kind.Long;
-                    return ConstantNode.forLong(x().asConstant().asLong() >>> amount, graph());
-                }
-            }
             if (amount == 0) {
                 return x();
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -41,6 +41,12 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() ^ inputs[1].asLong(), null);
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x() == y()) {
             return ConstantNode.forIntegerKind(kind(), 0, graph());
@@ -49,12 +55,7 @@
             return graph().unique(new XorNode(kind(), y(), x()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() ^ y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() ^ y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             if (kind() == Kind.Int) {
                 int c = y().asConstant().asInt();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Wed Oct 02 13:26:31 2013 +0200
@@ -154,12 +154,10 @@
     private void identifyBlocks() {
         // Find all block headers
         int numBlocks = 0;
-        for (Node node : graph.getNodes()) {
-            if (node instanceof AbstractBeginNode) {
-                Block block = new Block((AbstractBeginNode) node);
-                numBlocks++;
-                identifyBlock(block);
-            }
+        for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.class)) {
+            Block block = new Block(begin);
+            numBlocks++;
+            identifyBlock(block);
         }
 
         // Compute postorder.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -166,7 +166,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         if (!enabled) {
             throw new GraalInternalError("counter nodes shouldn't exist when not enabled");
         }
@@ -183,6 +183,8 @@
 
             graph().addBeforeFixed(this, load);
             graph().addBeforeFixed(this, store);
+            load.lower(tool);
+            store.lower(tool);
         }
         graph().removeFixed(this);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractCallNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +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.nodes.extended;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-
-public abstract class AbstractCallNode extends AbstractStateSplit implements StateSplit {
-
-    @Input private final NodeInputList<ValueNode> arguments;
-
-    public AbstractCallNode(Stamp stamp, ValueNode[] arguments) {
-        super(stamp);
-        this.arguments = new NodeInputList<>(this, arguments);
-    }
-
-    public NodeInputList<ValueNode> arguments() {
-        return arguments;
-    }
-
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -78,21 +77,11 @@
     }
 
     @Override
-    public AccessNode asNode() {
-        return this;
-    }
-
-    @Override
     public boolean canDeoptimize() {
         return nullCheck;
     }
 
     @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return DeoptimizationReason.NullCheckException;
-    }
-
-    @Override
     public GuardingNode getGuard() {
         return guard;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * Base class for nodes that modify a range of an array.
  */
-public abstract class ArrayRangeWriteNode extends AbstractStateSplit implements Node.IterableNodeType {
+public abstract class ArrayRangeWriteNode extends AbstractStateSplit {
 
     protected ArrayRangeWriteNode(Stamp stamp) {
         super(stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -53,7 +53,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BranchProbabilityNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BranchProbabilityNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -123,7 +123,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         throw new GraalInternalError("Branch probability could not be injected, because the probability value did not reduce to a constant value.");
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -70,21 +69,11 @@
     }
 
     @Override
-    public FloatingAccessNode asNode() {
-        return this;
-    }
-
-    @Override
     public boolean canDeoptimize() {
         return nullCheck;
     }
 
     @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return DeoptimizationReason.NullCheckException;
-    }
-
-    @Override
     public FrameState getDeoptimizationState() {
         return deoptState;
     }
@@ -100,6 +89,10 @@
         return barrierType;
     }
 
+    public FrameState getState() {
+        return deoptState;
+    }
+
     @Override
     public boolean isCompressible() {
         return compressible;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -32,7 +32,7 @@
  * A floating read of a value from memory specified in terms of an object base and an object
  * relative location. This node does not null check the object.
  */
-public final class FloatingReadNode extends FloatingAccessNode implements Node.IterableNodeType, LIRLowerable, Canonicalizable {
+public final class FloatingReadNode extends FloatingAccessNode implements IterableNodeType, LIRLowerable, Canonicalizable {
 
     @Input private Node lastLocationAccess;
 
@@ -53,6 +53,11 @@
         return lastLocationAccess;
     }
 
+    public void setLastLocationAccess(Node newlla) {
+        updateUsages(lastLocationAccess, newlla);
+        lastLocationAccess = newlla;
+    }
+
     @Override
     public void generate(LIRGeneratorTool gen) {
         Value address = location().generateAddress(gen, gen.operand(object()));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -130,7 +130,12 @@
     }
 
     @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return null;
+    public FrameState getState() {
+        if (deoptState != null) {
+            assert stateAfter() == null;
+            return deoptState;
+        } else {
+            return super.getState();
+        }
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -58,8 +58,8 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        if (loweringType == LoweringType.AFTER_GUARDS) {
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
             tool.getRuntime().lower(this, tool);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -51,7 +51,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -49,14 +48,4 @@
     public boolean canDeoptimize() {
         return true;
     }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return DeoptimizationReason.NullCheckException;
-    }
-
-    @Override
-    public ValueNode asNode() {
-        return this;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRLocalNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRLocalNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(nameTemplate = "OSRLocal({p#index})")
-public class OSRLocalNode extends AbstractLocalNode implements Node.IterableNodeType {
+public class OSRLocalNode extends AbstractLocalNode implements IterableNodeType {
 
     public OSRLocalNode(int index, Stamp stamp) {
         super(index, stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRStartNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRStartNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,7 +29,7 @@
 public class OSRStartNode extends StartNode implements Lowerable {
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -32,7 +31,7 @@
 /**
  * Reads an {@linkplain AccessNode accessed} value.
  */
-public final class ReadNode extends FloatableAccessNode implements Node.IterableNodeType, LIRLowerable, Canonicalizable, PiPushable, Virtualizable {
+public final class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, PiPushable, Virtualizable {
 
     public ReadNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType, boolean compressible) {
         super(object, location, stamp, barrierType, compressible);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/StoreHubNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/StoreHubNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -46,7 +46,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -170,10 +170,9 @@
     }
 
     @Override
-    public SwitchNode clone(Graph into) {
-        SwitchNode newSwitch = (SwitchNode) super.clone(into);
-        newSwitch.keyProbabilities = Arrays.copyOf(keyProbabilities, keyProbabilities.length);
-        newSwitch.keySuccessors = Arrays.copyOf(keySuccessors, keySuccessors.length);
-        return newSwitch;
+    public void afterClone(Node other) {
+        SwitchNode oldSwitch = (SwitchNode) other;
+        keyProbabilities = Arrays.copyOf(oldSwitch.keyProbabilities, oldSwitch.keyProbabilities.length);
+        keySuccessors = Arrays.copyOf(oldSwitch.keySuccessors, oldSwitch.keySuccessors.length);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -48,7 +48,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2012, 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.nodes.extended;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * The {@code UnsafeCastNode} produces the same value as its input, but with a different type.
- */
-public final class UnsafeArrayCastNode extends UnsafeCastNode implements ArrayLengthProvider {
-
-    @Input private ValueNode length;
-
-    public ValueNode length() {
-        return length;
-    }
-
-    public UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp) {
-        super(object, stamp);
-        this.length = length;
-    }
-
-    public UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp, GuardingNode anchor) {
-        super(object, stamp, anchor);
-        this.length = length;
-    }
-
-    private UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp, ValueNode anchor) {
-        this(object, length, stamp, (GuardingNode) anchor);
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
-        if (!(object() instanceof ArrayLengthProvider) || length() != ((ArrayLengthProvider) object()).length()) {
-            return this;
-        }
-        return super.canonical(tool);
-    }
-
-    @NodeIntrinsic
-    public static native <T> T unsafeArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp);
-
-    @NodeIntrinsic
-    public static native <T> T unsafeArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp, Object anchor);
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,25 +23,29 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
- * The {@code UnsafeCastNode} produces the same value as its input, but with a different type.
+ * The {@code UnsafeCastNode} produces the same value as its input, but with a different type. It
+ * allows unsafe casts "sideways" in the type hierarchy. It does not allow to "drop" type
+ * information, i.e., an unsafe cast is removed if the input object has a more precise or equal type
+ * than the type this nodes casts to.
  */
-public class UnsafeCastNode extends PiNode implements Canonicalizable, LIRLowerable {
+public class UnsafeCastNode extends FloatingGuardedNode implements LIRLowerable, GuardingNode, IterableNodeType, Canonicalizable, ValueProxy {
+
+    @Input private ValueNode object;
 
     public UnsafeCastNode(ValueNode object, Stamp stamp) {
-        super(object, stamp);
-    }
-
-    public UnsafeCastNode(ValueNode object, Stamp stamp, GuardingNode anchor) {
-        super(object, stamp, anchor);
+        super(stamp);
+        this.object = object;
     }
 
     public UnsafeCastNode(ValueNode object, Stamp stamp, ValueNode anchor) {
-        this(object, stamp, (GuardingNode) anchor);
+        super(stamp, (GuardingNode) anchor);
+        this.object = object;
     }
 
     public UnsafeCastNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
@@ -49,66 +53,44 @@
     }
 
     @Override
-    public boolean inferStamp() {
-        if (stamp() == StampFactory.forNodeIntrinsic()) {
-            return false;
-        }
-        if (stamp() instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
-            return updateStamp(((ObjectStamp) object().stamp()).castTo((ObjectStamp) stamp()));
-        }
-        return false;
+    public ValueNode getOriginalValue() {
+        return object;
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (kind() != object().kind()) {
+        assert kind() == Kind.Object && object.kind() == Kind.Object;
+
+        ObjectStamp my = (ObjectStamp) stamp();
+        ObjectStamp other = (ObjectStamp) object.stamp();
+
+        if (my.type() == null || other.type() == null) {
+            return this;
+        }
+        if (my.isExactType() && !other.isExactType()) {
             return this;
         }
-
-        if (stamp() instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
-            ObjectStamp my = (ObjectStamp) stamp();
-            ObjectStamp other = (ObjectStamp) object().stamp();
-
-            if (my.type() == null || other.type() == null) {
-                return this;
-            }
-            if (my.isExactType() && !other.isExactType()) {
-                return this;
-            }
-            if (my.nonNull() && !other.nonNull()) {
-                return this;
-            }
-            if (!my.type().isAssignableFrom(other.type())) {
-                return this;
-            }
+        if (my.nonNull() && !other.nonNull()) {
+            return this;
+        }
+        if (!my.type().isAssignableFrom(other.type())) {
+            return this;
         }
-        return object();
+        /*
+         * The unsafe cast does not add any new type information, so it can be removed. Note that
+         * this means that the unsafe cast cannot be used to "drop" type information (in which case
+         * it must not be canonicalized in any case).
+         */
+        return object;
     }
 
     @Override
     public void generate(LIRGeneratorTool generator) {
-        if (kind() != object().kind()) {
-            assert generator.target().arch.getSizeInBytes(kind()) == generator.target().arch.getSizeInBytes(object().kind()) : "unsafe cast cannot be used to change the size of a value";
-            AllocatableValue result = generator.newVariable(kind());
-            generator.emitMove(result, generator.operand(object()));
-            generator.setResult(this, result);
-        } else {
-            // The LIR only cares about the kind of an operand, not the actual type of an object. So
-            // we do not have to
-            // introduce a new operand when the kind is the same.
-            generator.setResult(this, generator.operand(object()));
-        }
-    }
-
-    @NodeIntrinsic
-    public static native <T> T unsafeCast(Object object, @ConstantNodeParameter Stamp stamp);
-
-    @NodeIntrinsic
-    public static native <T> T unsafeCast(Object object, @ConstantNodeParameter Stamp stamp, GuardingNode anchor);
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static <T> T unsafeCast(Object object, @ConstantNodeParameter Class<T> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull) {
-        return toType.cast(object);
+        assert kind() == Kind.Object && object.kind() == Kind.Object;
+        /*
+         * The LIR only cares about the kind of an operand, not the actual type of an object. So we
+         * do not have to introduce a new operand.
+         */
+        generator.setResult(this, generator.operand(object));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -49,7 +49,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -68,7 +68,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
@@ -107,6 +107,10 @@
         return unsafeStoreNode;
     }
 
+    public FrameState getState() {
+        return stateAfter;
+    }
+
     // specialized on value type until boxing/unboxing is sorted out in intrinsification
 
     @SuppressWarnings("unused")
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -32,82 +30,44 @@
 /**
  * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph.
  */
-public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, Virtualizable, GuardingNode {
-
-    @Input private final NodeInputList<ValueNode> anchored;
+public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, IterableNodeType, Virtualizable, GuardingNode {
 
-    public ValueAnchorNode(ValueNode... values) {
-        this(false, values);
-    }
+    @Input private ValueNode anchored;
 
-    public ValueAnchorNode(boolean permanent, ValueNode... values) {
+    public ValueAnchorNode(ValueNode value) {
         super(StampFactory.dependency());
-        this.permanent = permanent;
-        this.anchored = new NodeInputList<>(this, values);
+        this.anchored = value;
     }
 
-    private boolean permanent;
-
     @Override
     public void generate(LIRGeneratorTool gen) {
         // Nothing to emit, since this node is used for structural purposes only.
     }
 
-    public void addAnchoredNode(ValueNode value) {
-        if (!anchored.contains(value)) {
-            this.anchored.add(value);
-        }
-    }
-
-    public void removeAnchoredNode(ValueNode value) {
-        this.anchored.remove(value);
-    }
-
-    public NodeInputList<ValueNode> getAnchoredNodes() {
+    public ValueNode getAnchoredNode() {
         return anchored;
     }
 
-    public void setPermanent(boolean permanent) {
-        this.permanent = permanent;
-    }
-
-    public boolean isPermanent() {
-        return permanent;
-    }
-
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (permanent) {
+        if (anchored != null && !anchored.isConstant() && !(anchored instanceof FixedNode)) {
+            // Found entry that needs this anchor.
             return this;
         }
-        if (this.predecessor() instanceof ValueAnchorNode) {
-            ValueAnchorNode previousAnchor = (ValueAnchorNode) this.predecessor();
-            if (previousAnchor.usages().isEmpty()) { // avoid creating cycles
-                // transfer values and remove
-                for (ValueNode node : anchored.nonNull().distinct()) {
-                    previousAnchor.addAnchoredNode(node);
-                }
-                return previousAnchor;
-            }
+
+        if (usages().isNotEmpty()) {
+            // A not uses this anchor => anchor is necessary.
+            return this;
         }
-        for (Node node : anchored.nonNull().and(isNotA(FixedNode.class))) {
-            if (!(node instanceof ConstantNode)) {
-                return this; // still necessary
-            }
-        }
-        if (usages().isEmpty()) {
-            return null; // no node which require an anchor found
-        }
-        return this;
+
+        // Anchor is not necessary any more => remove.
+        return null;
     }
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        if (permanent) {
-            return;
-        }
-        for (ValueNode node : anchored.nonNull().and(isNotA(AbstractBeginNode.class))) {
-            State state = tool.getObjectState(node);
+        if (anchored != null && !(anchored instanceof AbstractBeginNode)) {
+            State state = tool.getObjectState(anchored);
             if (state == null || state.getState() != EscapeState.Virtual) {
                 return;
             }
@@ -115,8 +75,8 @@
         tool.delete();
     }
 
-    @Override
-    public ValueNode asNode() {
-        return this;
+    public void removeAnchoredNode() {
+        this.updateUsages(anchored, null);
+        this.anchored = null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.LocationNode.Location;
 import com.oracle.graal.nodes.spi.*;
@@ -33,7 +32,7 @@
 /**
  * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}.
  */
-public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, Node.IterableNodeType, Virtualizable {
+public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, Virtualizable {
 
     @Input private ValueNode value;
     @Input(notDataflow = true) private FrameState stateAfter;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -31,7 +29,7 @@
 /**
  * The {@code AbstractNewArrayNode} is used for all 1-dimensional array allocations.
  */
-public class AbstractNewArrayNode extends DeoptimizingFixedWithNextNode implements Canonicalizable, Lowerable, ArrayLengthProvider, Node.IterableNodeType {
+public class AbstractNewArrayNode extends DeoptimizingFixedWithNextNode implements Canonicalizable, Lowerable, ArrayLengthProvider {
 
     @Input private ValueNode length;
     private final boolean fillContents;
@@ -88,7 +86,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
@@ -96,9 +94,4 @@
     public boolean canDeoptimize() {
         return true;
     }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return DeoptimizationReason.RuntimeConstraint;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -83,7 +83,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -64,7 +64,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -33,7 +33,7 @@
  * The Java bytecode specification allows non-balanced locking. Graal does not handle such cases and
  * throws a {@link BailoutException} instead during graph building.
  */
-public abstract class AccessMonitorNode extends AbstractStateSplit implements StateSplit, MemoryCheckpoint {
+public abstract class AccessMonitorNode extends AbstractStateSplit implements MemoryCheckpoint {
 
     @Input private ValueNode object;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -45,24 +45,40 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (array() instanceof ArrayLengthProvider) {
-            ValueNode length = ((ArrayLengthProvider) array()).length();
+        ValueNode length = readArrayLength(array(), tool.runtime());
+        if (length != null) {
+            return length;
+        }
+        return this;
+    }
+
+    /**
+     * Gets the length of an array if possible.
+     * 
+     * @param array an array
+     * @return a node representing the length of {@code array} or null if it is not available
+     */
+    public static ValueNode readArrayLength(ValueNode array, MetaAccessProvider runtime) {
+        if (array instanceof ArrayLengthProvider) {
+            ValueNode length = ((ArrayLengthProvider) array).length();
             if (length != null) {
                 return length;
             }
         }
-        MetaAccessProvider runtime = tool.runtime();
-        if (runtime != null && array().isConstant() && !array().isNullConstant()) {
-            Constant constantValue = array().asConstant();
+        if (runtime != null && array.isConstant() && !array.isNullConstant()) {
+            Constant constantValue = array.asConstant();
             if (constantValue != null && constantValue.isNonNull()) {
-                return ConstantNode.forInt(runtime.lookupArrayLength(constantValue), graph());
+                Integer constantLength = runtime.lookupArrayLength(constantValue);
+                if (constantLength != null) {
+                    return ConstantNode.forInt(constantLength, array.graph());
+                }
             }
         }
-        return this;
+        return null;
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -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.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -32,7 +31,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, Node.IterableNodeType {
+public final class CheckCastDynamicNode extends FixedWithNextNode implements Canonicalizable, Lowerable {
 
     @Input private ValueNode object;
     @Input private ValueNode hub;
@@ -59,7 +58,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,11 +22,10 @@
  */
 package com.oracle.graal.nodes.java;
 
-import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.graph.*;
@@ -38,7 +37,7 @@
 /**
  * Implements a type check against a compile-time known type.
  */
-public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Lowerable, Node.IterableNodeType, Virtualizable, ValueProxy {
+public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Lowerable, Virtualizable, ValueProxy {
 
     @Input private ValueNode object;
     private final ResolvedJavaType type;
@@ -96,8 +95,8 @@
      * {@code LoweringPhase.checkUsagesAreScheduled()}.
      */
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        InstanceOfNode typeTest = graph().add(new InstanceOfNode(type, object, profile));
+    public void lower(LoweringTool tool) {
+        InstanceOfNode typeTest = graph().addWithoutUnique(new InstanceOfNode(type, object, profile));
         Stamp stamp = StampFactory.declared(type);
         if (stamp() instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
             stamp = ((ObjectStamp) object().stamp()).castTo((ObjectStamp) stamp);
@@ -115,14 +114,16 @@
                 graph().addBeforeFixed(this, nullGuard);
                 condition = typeTest;
                 stamp = stamp.join(StampFactory.objectNonNull());
+                nullGuard.lower(tool);
             } else {
                 // TODO (ds) replace with probability of null-seen when available
                 double shortCircuitProbability = NOT_FREQUENT_PROBABILITY;
-                condition = graph().unique(new ShortCircuitOrNode(graph().unique(new IsNullNode(object)), false, typeTest, false, shortCircuitProbability));
+                condition = LogicNode.or(graph().unique(new IsNullNode(object)), typeTest, shortCircuitProbability);
             }
         }
         GuardingPiNode checkedObject = graph().add(new GuardingPiNode(object, condition, false, forStoreCheck ? ArrayStoreException : ClassCastException, InvalidateReprofile, stamp));
         graph().replaceFixedWithFixed(this, checkedObject);
+        checkedObject.lower(tool);
     }
 
     @Override
@@ -159,7 +160,7 @@
         if (ObjectStamp.isObjectAlwaysNull(object())) {
             return object();
         }
-        if (tool.assumptions().useOptimisticAssumptions()) {
+        if (tool.assumptions() != null && tool.assumptions().useOptimisticAssumptions()) {
             ResolvedJavaType exactType = type.findUniqueConcreteSubtype();
             if (exactType != null && exactType != type) {
                 // Propagate more precise type information to usages of the checkcast.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,7 +34,7 @@
  * Represents an atomic compare-and-swap operation The result is a boolean that contains whether the
  * value matched the expected value.
  */
-public class CompareAndSwapNode extends AbstractStateSplit implements StateSplit, Lowerable, MemoryCheckpoint.Single {
+public class CompareAndSwapNode extends AbstractStateSplit implements Lowerable, MemoryCheckpoint.Single {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
@@ -78,7 +78,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -64,7 +64,7 @@
      * runtime/interpreter would not have a valid location for the exception object to be rethrown.
      */
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         if (isLowered()) {
             return;
         }
@@ -89,6 +89,7 @@
         graph().addAfterFixed(this, loadException);
         setStateAfter(null);
         setStamp(StampFactory.forVoid());
+        loadException.lower(tool);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -50,7 +50,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -51,7 +51,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -44,7 +44,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,7 +36,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, Node.IterableNodeType, VirtualizableRoot {
+public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable, IterableNodeType, VirtualizableRoot {
 
     /**
      * Creates a new LoadFieldNode instance.
@@ -100,7 +100,7 @@
                 }
                 constants[i] = constantValue;
             }
-            PhiNode newPhi = graph().add(new PhiNode(stamp(), phi.merge()));
+            PhiNode newPhi = graph().addWithoutUnique(new PhiNode(stamp(), phi.merge()));
             for (int i = 0; i < phi.valueCount(); i++) {
                 newPhi.addInput(ConstantNode.forConstant(constants[i], runtime, graph()));
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,7 +31,7 @@
 /**
  * The {@code LoadIndexedNode} represents a read from an element of an array.
  */
-public final class LoadIndexedNode extends AccessIndexedNode implements Node.IterableNodeType, Virtualizable {
+public final class LoadIndexedNode extends AccessIndexedNode implements IterableNodeType, Virtualizable {
 
     /**
      * Creates a new LoadIndexedNode.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -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.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
@@ -32,7 +31,7 @@
 /**
  * Represents the lowered version of an atomic compare-and-swap operation{@code CompareAndSwapNode}.
  */
-public class LoweredCompareAndSwapNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, Node.IterableNodeType {
+public class LoweredCompareAndSwapNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single {
 
     @Input private ValueNode expectedValue;
     @Input private ValueNode newValue;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -30,7 +30,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public class MethodCallTargetNode extends CallTargetNode implements Node.IterableNodeType, Canonicalizable {
+public class MethodCallTargetNode extends CallTargetNode implements IterableNodeType, Canonicalizable {
 
     public enum InvokeKind {
         Interface, Special, Static, Virtual
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -50,7 +50,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,7 +31,7 @@
 /**
  * The {@code MonitorEnterNode} represents a monitor release.
  */
-public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Lowerable, Node.IterableNodeType, MonitorExit, MemoryCheckpoint.Single, MonitorReference {
+public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single, MonitorReference {
 
     private int lockDepth;
 
@@ -51,7 +51,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -33,7 +33,7 @@
  * The {@code NewInstanceNode} represents the allocation of an instance class object.
  */
 @NodeInfo(nameTemplate = "New {p#instanceClass/s}")
-public final class NewInstanceNode extends DeoptimizingFixedWithNextNode implements Node.IterableNodeType, Canonicalizable, Lowerable, VirtualizableAllocation {
+public final class NewInstanceNode extends DeoptimizingFixedWithNextNode implements Canonicalizable, Lowerable, VirtualizableAllocation {
 
     private final ResolvedJavaType instanceClass;
     private final boolean fillContents;
@@ -77,7 +77,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
@@ -100,9 +100,4 @@
     public boolean canDeoptimize() {
         return true;
     }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return DeoptimizationReason.RuntimeConstraint;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -62,7 +62,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
@@ -74,9 +74,4 @@
     public boolean canDeoptimize() {
         return true;
     }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return DeoptimizationReason.RuntimeConstraint;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -32,7 +32,7 @@
  * 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 StateSplit, Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode {
+public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode {
 
     public static final ForeignCallDescriptor REGISTER_FINALIZER = new ForeignCallDescriptor("registerFinalizer", void.class, Object.class);
 
@@ -105,11 +105,6 @@
         deoptState = f;
     }
 
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return null;
-    }
-
     @SuppressWarnings("unused")
     @NodeIntrinsic
     public static void register(Object thisObj) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,7 +28,7 @@
 import com.oracle.graal.api.meta.ResolvedJavaMethod;
 import com.oracle.graal.graph.GraalInternalError;
 import com.oracle.graal.graph.NodeInputList;
-import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.LIRGeneratorTool;
 import com.oracle.graal.nodes.spi.Lowerable;
 import com.oracle.graal.nodes.spi.LoweringTool;
@@ -68,7 +68,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         InvokeKind invokeKind = Modifier.isStatic(replacementTargetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special;
         MethodCallTargetNode replacement = graph().add(
                         new MethodCallTargetNode(invokeKind, replacementTargetMethod, replacementArguments.toArray(new ValueNode[replacementArguments.size()]), replacementReturnType));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -79,4 +79,8 @@
             }
         }
     }
+
+    public FrameState getState() {
+        return stateAfter;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -81,4 +81,8 @@
             }
         }
     }
+
+    public FrameState getState() {
+        return stateAfter;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/DelegatingGraalCodeCacheProvider.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, 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.nodes.spi;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * A {@link GraalCodeCacheProvider} that delegates to another {@link GraalCodeCacheProvider}.
+ */
+public class DelegatingGraalCodeCacheProvider extends DelegatingCodeCacheProvider implements GraalCodeCacheProvider {
+
+    public DelegatingGraalCodeCacheProvider(CodeCacheProvider delegate) {
+        super(delegate);
+    }
+
+    @Override
+    protected GraalCodeCacheProvider delegate() {
+        return (GraalCodeCacheProvider) super.delegate();
+    }
+
+    public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, Graph graph) {
+        return delegate().addMethod(method, compResult, graph);
+    }
+
+    public void lower(Node n, LoweringTool tool) {
+        delegate().lower(n, tool);
+    }
+
+    public ValueNode reconstructArrayIndex(LocationNode location) {
+        return delegate().reconstructArrayIndex(location);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Wed Oct 02 13:26:31 2013 +0200
@@ -63,7 +63,7 @@
 
     void emitMembar(int barriers);
 
-    void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting);
+    void emitDeoptimize(Value actionAndReason, DeoptimizingNode deopting);
 
     void emitNullCheck(ValueNode v, DeoptimizingNode deopting);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,11 +22,19 @@
  */
 package com.oracle.graal.nodes.spi;
 
+import com.oracle.graal.nodes.*;
+
+/**
+ * Interface implemented by nodes that can replace themselves with lower level nodes during a phase
+ * that transforms a graph to replace higher level nodes with lower level nodes.
+ */
 public interface Lowerable {
 
-    public enum LoweringType {
-        BEFORE_GUARDS, AFTER_GUARDS, AFTER_FSA
-    }
+    /**
+     * Expand this node into lower level nodes expressing the same semantics. If the introduced
+     * nodes are themselves lowerable, they should be recursively lowered as part of this call.
+     */
+    void lower(LoweringTool tool);
 
-    void lower(LoweringTool tool, LoweringType loweringType);
+    ValueNode asNode();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,14 +28,11 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 
 public interface LoweringTool {
 
     GraalCodeCacheProvider getRuntime();
 
-    LoweringType getLoweringType();
-
     Replacements getReplacements();
 
     GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013, 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.spi;
+
+import com.oracle.graal.nodes.*;
+
+public interface NodeWithState {
+    FrameState getState();
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IntegerStamp.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IntegerStamp.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.type;
 
+import java.util.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -133,10 +135,12 @@
             str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
         }
         if (downMask != 0) {
-            str.append(" \u21ca").append(Long.toHexString(downMask));
+            str.append(" \u21ca");
+            new Formatter(str).format("%016x", downMask);
         }
         if (upMask != defaultMask(kind())) {
-            str.append(" \u21c8").append(Long.toHexString(upMask));
+            str.append(" \u21c8");
+            new Formatter(str).format("%016x", upMask);
         }
         return str.toString();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.type;
 
-import com.oracle.graal.api.code.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.type.GenericStamp.GenericStampType;
@@ -43,7 +41,6 @@
     private static final Stamp conditionStamp = new GenericStamp(GenericStampType.Condition);
     private static final Stamp voidStamp = new GenericStamp(GenericStampType.Void);
     private static final Stamp nodeIntrinsicStamp = new ObjectStamp(null, false, false, false);
-    private static final Stamp wordStamp = new ObjectStamp(null, false, false, false);
     private static final Stamp positiveInt = forInteger(Kind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
 
     private static void setCache(Kind kind, Stamp stamp) {
@@ -85,14 +82,6 @@
         return nodeIntrinsicStamp;
     }
 
-    /**
-     * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by the
-     * actual primitive type stamp for the target-specific {@link TargetDescription#wordKind}.
-     */
-    public static Stamp forWord() {
-        return wordStamp;
-    }
-
     public static Stamp intValue() {
         return forKind(Kind.Int);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,7 +31,7 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(nameTemplate = "Alloc {i#virtualObjects}")
-public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Node.IterableNodeType, Simplifiable {
+public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Simplifiable {
 
     @Input private final NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this);
     @Input private final NodeInputList<ValueNode> values = new NodeInputList<>(this);
@@ -55,7 +55,7 @@
 
     @Override
     public boolean verify() {
-        assertTrue(virtualObjects.size() == locks.size(), "lockCounts size doesn't match");
+        assertTrue(virtualObjects.size() == locks.size(), "lockCounts size doesn't match " + virtualObjects + ", " + locks);
         int valueCount = 0;
         for (VirtualObjectNode virtual : virtualObjects) {
             valueCount += virtual.entryCount();
@@ -65,15 +65,13 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
 
     @Override
-    public Node clone(Graph into) {
-        CommitAllocationNode clone = (CommitAllocationNode) super.clone(into);
-        clone.locks = new ArrayList<>(locks);
-        return clone;
+    public void afterClone(Node other) {
+        locks = new ArrayList<>(((CommitAllocationNode) other).locks);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EscapeObjectState.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EscapeObjectState.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,7 +25,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
-public abstract class EscapeObjectState extends VirtualState implements Node.IterableNodeType {
+public abstract class EscapeObjectState extends VirtualState implements IterableNodeType {
 
     @Input private VirtualObjectNode object;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,7 +28,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class VirtualObjectNode extends ValueNode implements LIRLowerable, Node.IterableNodeType {
+public abstract class VirtualObjectNode extends ValueNode implements LIRLowerable, IterableNodeType {
 
     private boolean hasIdentity;
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,24 +31,25 @@
 import com.oracle.graal.graph.Graph.NodeChangedListener;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.phases.tiers.*;
 
 public class CanonicalizerPhase extends BasePhase<PhaseContext> {
 
     private static final int MAX_ITERATION_PER_NODE = 10;
     private static final DebugMetric METRIC_CANONICALIZED_NODES = Debug.metric("CanonicalizedNodes");
+    private static final DebugMetric METRIC_PROCESSED_NODES = Debug.metric("ProcessedNodes");
     private static final DebugMetric METRIC_CANONICALIZATION_CONSIDERED_NODES = Debug.metric("CanonicalizationConsideredNodes");
     private static final DebugMetric METRIC_INFER_STAMP_CALLED = Debug.metric("InferStampCalled");
     private static final DebugMetric METRIC_STAMP_CHANGED = Debug.metric("StampChanged");
     private static final DebugMetric METRIC_SIMPLIFICATION_CONSIDERED_NODES = Debug.metric("SimplificationConsideredNodes");
-    public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits");
+    private static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits");
 
     private final boolean canonicalizeReads;
+    private final CustomCanonicalizer customCanonicalizer;
 
     public interface CustomCanonicalizer {
 
@@ -56,15 +57,57 @@
     }
 
     public CanonicalizerPhase(boolean canonicalizeReads) {
+        this(canonicalizeReads, null);
+    }
+
+    public CanonicalizerPhase(boolean canonicalizeReads, CustomCanonicalizer customCanonicalizer) {
         this.canonicalizeReads = canonicalizeReads;
+        this.customCanonicalizer = customCanonicalizer;
     }
 
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
-        new Instance(context.getRuntime(), context.getAssumptions(), canonicalizeReads).run(graph);
+        new Instance(context.getRuntime(), context.getAssumptions(), canonicalizeReads, customCanonicalizer).run(graph);
+    }
+
+    /**
+     * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by this
+     *            mark are processed
+     */
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, int newNodesMark) {
+        applyIncremental(graph, context, newNodesMark, true);
+    }
+
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, int newNodesMark, boolean dumpGraph) {
+        new Instance(context.getRuntime(), context.getAssumptions(), canonicalizeReads, newNodesMark, customCanonicalizer).apply(graph, dumpGraph);
     }
 
-    public static class Instance extends Phase {
+    /**
+     * @param workingSet the initial working set of nodes on which the canonicalizer works, should
+     *            be an auto-grow node bitmap
+     */
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<Node> workingSet) {
+        applyIncremental(graph, context, workingSet, true);
+    }
+
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<Node> workingSet, boolean dumpGraph) {
+        new Instance(context.getRuntime(), context.getAssumptions(), canonicalizeReads, workingSet, customCanonicalizer).apply(graph, dumpGraph);
+    }
+
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<Node> workingSet, int newNodesMark) {
+        applyIncremental(graph, context, workingSet, newNodesMark, true);
+    }
+
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<Node> workingSet, int newNodesMark, boolean dumpGraph) {
+        new Instance(context.getRuntime(), context.getAssumptions(), canonicalizeReads, workingSet, newNodesMark, customCanonicalizer).apply(graph, dumpGraph);
+    }
+
+    @Deprecated
+    public void addToPhasePlan(PhasePlan plan, PhaseContext context) {
+        plan.addPhase(PhasePosition.AFTER_PARSING, new Instance(context.getRuntime(), context.getAssumptions(), canonicalizeReads, customCanonicalizer));
+    }
+
+    private static final class Instance extends Phase {
 
         private final int newNodesMark;
         private final Assumptions assumptions;
@@ -76,34 +119,19 @@
         private NodeWorkList workList;
         private Tool tool;
 
-        public Instance(MetaAccessProvider runtime, Assumptions assumptions, boolean canonicalizeReads) {
-            this(runtime, assumptions, canonicalizeReads, null, 0, null);
+        private Instance(MetaAccessProvider runtime, Assumptions assumptions, boolean canonicalizeReads, CustomCanonicalizer customCanonicalizer) {
+            this(runtime, assumptions, canonicalizeReads, null, 0, customCanonicalizer);
         }
 
-        /**
-         * @param runtime
-         * @param assumptions
-         * @param workingSet the initial working set of nodes on which the canonicalizer works,
-         *            should be an auto-grow node bitmap
-         * @param customCanonicalizer
-         * @param canonicalizeReads flag to indicate if
-         *            {@link LoadFieldNode#canonical(CanonicalizerTool)} and
-         *            {@link ReadNode#canonical(CanonicalizerTool)} should canonicalize reads of
-         *            constant fields.
-         */
-        public Instance(MetaAccessProvider runtime, Assumptions assumptions, boolean canonicalizeReads, Iterable<Node> workingSet, CustomCanonicalizer customCanonicalizer) {
+        private Instance(MetaAccessProvider runtime, Assumptions assumptions, boolean canonicalizeReads, Iterable<Node> workingSet, CustomCanonicalizer customCanonicalizer) {
             this(runtime, assumptions, canonicalizeReads, workingSet, 0, customCanonicalizer);
         }
 
-        /**
-         * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by
-         *            this mark are processed otherwise all nodes in the graph are processed
-         */
-        public Instance(MetaAccessProvider runtime, Assumptions assumptions, boolean canonicalizeReads, int newNodesMark, CustomCanonicalizer customCanonicalizer) {
+        private Instance(MetaAccessProvider runtime, Assumptions assumptions, boolean canonicalizeReads, int newNodesMark, CustomCanonicalizer customCanonicalizer) {
             this(runtime, assumptions, canonicalizeReads, null, newNodesMark, customCanonicalizer);
         }
 
-        public Instance(MetaAccessProvider runtime, Assumptions assumptions, boolean canonicalizeReads, Iterable<Node> workingSet, int newNodesMark, CustomCanonicalizer customCanonicalizer) {
+        private Instance(MetaAccessProvider runtime, Assumptions assumptions, boolean canonicalizeReads, Iterable<Node> workingSet, int newNodesMark, CustomCanonicalizer customCanonicalizer) {
             super("Canonicalizer");
             this.newNodesMark = newNodesMark;
             this.assumptions = assumptions;
@@ -160,14 +188,13 @@
                     if (!tryCanonicalize(node)) {
                         if (node instanceof ValueNode) {
                             ValueNode valueNode = (ValueNode) node;
-                            if (tryInferStamp(valueNode)) {
-                                Constant constant = valueNode.stamp().asConstant();
-                                if (constant != null) {
-                                    performReplacement(valueNode, ConstantNode.forConstant(constant, runtime, valueNode.graph()));
-                                } else {
-                                    // the improved stamp may enable additional canonicalization
-                                    tryCanonicalize(valueNode);
-                                }
+                            boolean improvedStamp = tryInferStamp(valueNode);
+                            Constant constant = valueNode.stamp().asConstant();
+                            if (constant != null && !(node instanceof ConstantNode)) {
+                                performReplacement(valueNode, ConstantNode.forConstant(constant, runtime, valueNode.graph()));
+                            } else if (improvedStamp) {
+                                // the improved stamp may enable additional canonicalization
+                                tryCanonicalize(valueNode);
                             }
                         }
                     }
@@ -188,7 +215,8 @@
         }
 
         public static boolean tryGlobalValueNumbering(Node node) {
-            if (node.getNodeClass().valueNumberable()) {
+            NodeClass nodeClass = node.getNodeClass();
+            if (nodeClass.valueNumberable() && !nodeClass.isLeafNode()) {
                 Node newNode = node.graph().findDuplicate(node);
                 if (newNode != null) {
                     assert !(node instanceof FixedNode || newNode instanceof FixedNode);
@@ -248,6 +276,8 @@
 //                                         --------------------------------------------
 //                          Fixed-connected|   2    |        X        |       6       |
 //                                         --------------------------------------------
+//                              ControlSink|   X    |        X        |       7       |
+//                                         --------------------------------------------
 //       X: must not happen (checked with assertions)
 // @formatter:on
         private boolean performReplacement(final Node node, ValueNode canonical) {
@@ -272,9 +302,16 @@
                     assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")";
                     FixedWithNextNode fixedWithNext = (FixedWithNextNode) node;
 
-                    // When removing a fixed node, new canonicalization opportunities for its
-// successor
-                    // may arise
+                    if (canonical instanceof ControlSinkNode) {
+                        // case 7
+                        FixedWithNextNode pred = (FixedWithNextNode) node.predecessor();
+                        GraphUtil.killCFG(fixedWithNext);
+                        pred.setNext((FixedNode) canonical);
+                        return true;
+                    }
+
+                    // When removing a fixed node, new canonicalization
+                    // opportunities for its successor may arise
                     assert fixedWithNext.next() != null;
                     tool.addToWorkList(fixedWithNext.next());
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -258,6 +258,14 @@
                 metricTypeRegistered.increment();
             }
         }
+
+        public void clear() {
+            knownTypes.clear();
+            knownNonNull.clear();
+            knownNull.clear();
+            trueConditions.clear();
+            falseConditions.clear();
+        }
     }
 
     public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) {
@@ -355,6 +363,9 @@
 
         private void registerControlSplitInfo(Node pred, AbstractBeginNode begin) {
             assert pred != null && begin != null;
+            if (begin instanceof LoopExitNode) {
+                state.clear();
+            }
 
             if (pred instanceof IfNode) {
                 IfNode ifNode = (IfNode) pred;
@@ -494,15 +505,15 @@
                     }
                     ValueAnchorNode anchor = null;
                     if (replacementAnchor == null) {
-                        anchor = graph.add(new ValueAnchorNode());
+                        anchor = graph.add(new ValueAnchorNode(null));
                         replacementAnchor = anchor;
                     }
                     PiNode piNode;
                     if (isNull) {
                         ConstantNode nullObject = ConstantNode.forObject(null, metaAccessProvider, graph);
-                        piNode = graph.unique(new PiNode(nullObject, StampFactory.forConstant(nullObject.value, metaAccessProvider), replacementAnchor));
+                        piNode = graph.unique(new PiNode(nullObject, StampFactory.forConstant(nullObject.value, metaAccessProvider), replacementAnchor.asNode()));
                     } else {
-                        piNode = graph.unique(new PiNode(object, StampFactory.declared(type, nonNull), replacementAnchor));
+                        piNode = graph.unique(new PiNode(object, StampFactory.declared(type, nonNull), replacementAnchor.asNode()));
                     }
                     checkCast.replaceAtUsages(piNode);
                     if (anchor != null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, 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;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
+
+/**
+ * This phase tries to find {@link AbstractDeoptimizeNode DeoptimizeNodes} which use the same
+ * {@link FrameState} and merges them together.
+ */
+public class DeoptimizationGroupingPhase extends BasePhase<MidTierContext> {
+
+    @Override
+    protected void run(StructuredGraph graph, MidTierContext context) {
+        ControlFlowGraph cfg = null;
+        for (FrameState fs : graph.getNodes(FrameState.class)) {
+            FixedNode target = null;
+            PhiNode phi = null;
+            List<AbstractDeoptimizeNode> obsoletes = null;
+            for (AbstractDeoptimizeNode deopt : fs.usages().filter(AbstractDeoptimizeNode.class)) {
+                if (target == null) {
+                    target = deopt;
+                } else {
+                    if (cfg == null) {
+                        cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+                    }
+                    MergeNode merge;
+                    if (target instanceof AbstractDeoptimizeNode) {
+                        merge = graph.add(new MergeNode());
+                        EndNode firstEnd = graph.add(new EndNode());
+                        phi = graph.addWithoutUnique(new PhiNode(Kind.Int, merge));
+                        merge.addForwardEnd(firstEnd);
+                        phi.addInput(((AbstractDeoptimizeNode) target).getActionAndReason(context.getRuntime()));
+                        target.predecessor().replaceFirstSuccessor(target, firstEnd);
+
+                        exitLoops((AbstractDeoptimizeNode) target, firstEnd, cfg);
+
+                        merge.setNext(graph.add(new DynamicDeoptimizeNode(phi)));
+                        obsoletes = new LinkedList<>();
+                        obsoletes.add((AbstractDeoptimizeNode) target);
+                        target = merge;
+                    } else {
+                        merge = (MergeNode) target;
+                    }
+                    EndNode newEnd = graph.add(new EndNode());
+                    merge.addForwardEnd(newEnd);
+                    phi.addInput(deopt.getActionAndReason(context.getRuntime()));
+                    deopt.predecessor().replaceFirstSuccessor(deopt, newEnd);
+                    exitLoops(deopt, newEnd, cfg);
+                    obsoletes.add(deopt);
+                }
+            }
+            if (obsoletes != null) {
+                ((DynamicDeoptimizeNode) ((MergeNode) target).next()).setDeoptimizationState(fs);
+                for (AbstractDeoptimizeNode obsolete : obsoletes) {
+                    obsolete.safeDelete();
+                }
+            }
+        }
+    }
+
+    private static void exitLoops(AbstractDeoptimizeNode deopt, EndNode end, ControlFlowGraph cfg) {
+        Block block = cfg.blockFor(deopt);
+        Loop loop = block.getLoop();
+        while (loop != null) {
+            end.graph().addBeforeFixed(end, end.graph().add(new LoopExitNode(loop.loopBegin())));
+            loop = loop.parent;
+        }
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,7 +25,6 @@
 import java.util.*;
 import java.util.Map.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
@@ -133,7 +132,7 @@
         }
         Graph graph = merge.graph();
         for (GuardNode guard : hits) {
-            PhiNode phi = graph.add(new PhiNode(PhiType.Guard, merge, null));
+            PhiNode phi = graph.addWithoutUnique(new PhiNode(PhiType.Guard, merge, null));
             for (AbstractEndNode otherEnd : merge.forwardEnds()) {
                 phi.addInput(graph.unique(new GuardNode(guard.condition(), AbstractBeginNode.prevBegin(otherEnd), guard.reason(), guard.action(), guard.negated())));
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandLogicPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandLogicPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,33 +31,21 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (ShortCircuitBooleanNode logic : graph.getNodes(ShortCircuitBooleanNode.class)) {
+        for (ShortCircuitOrNode logic : graph.getNodes(ShortCircuitOrNode.class)) {
             processBinary(logic);
         }
-        assert graph.getNodes(ShortCircuitBooleanNode.class).isEmpty();
+        assert graph.getNodes(ShortCircuitOrNode.class).isEmpty();
     }
 
-    private static void processBinary(ShortCircuitBooleanNode binary) {
+    private static void processBinary(ShortCircuitOrNode binary) {
         while (binary.usages().isNotEmpty()) {
             Node usage = binary.usages().first();
-            if (usage instanceof ShortCircuitBooleanNode) {
-                processBinary((ShortCircuitBooleanNode) usage);
+            if (usage instanceof ShortCircuitOrNode) {
+                processBinary((ShortCircuitOrNode) usage);
             } else if (usage instanceof IfNode) {
-                if (binary instanceof ShortCircuitAndNode) {
-                    processIf(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (IfNode) usage, false, binary.getShortCircuitProbability());
-                } else if (binary instanceof ShortCircuitOrNode) {
-                    processIf(binary.getX(), !binary.isXNegated(), binary.getY(), !binary.isYNegated(), (IfNode) usage, true, binary.getShortCircuitProbability());
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
+                processIf(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (IfNode) usage, binary.getShortCircuitProbability());
             } else if (usage instanceof ConditionalNode) {
-                if (binary instanceof ShortCircuitOrNode) {
-                    processConditional(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (ConditionalNode) usage, false);
-                } else if (binary instanceof ShortCircuitOrNode) {
-                    processConditional(binary.getX(), !binary.isXNegated(), binary.getY(), !binary.isYNegated(), (ConditionalNode) usage, true);
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
+                processConditional(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (ConditionalNode) usage);
             } else {
                 throw GraalInternalError.shouldNotReachHere();
             }
@@ -65,33 +53,44 @@
         binary.safeDelete();
     }
 
-    private static void processIf(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, IfNode ifNode, boolean negateTargets, double shortCircuitProbability) {
-        AbstractBeginNode trueTarget = negateTargets ? ifNode.falseSuccessor() : ifNode.trueSuccessor();
-        AbstractBeginNode falseTarget = negateTargets ? ifNode.trueSuccessor() : ifNode.falseSuccessor();
+    private static void processIf(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, IfNode ifNode, double shortCircuitProbability) {
+        AbstractBeginNode trueTarget = ifNode.trueSuccessor();
+        AbstractBeginNode falseTarget = ifNode.falseSuccessor();
         double firstIfProbability = shortCircuitProbability;
-        double secondIfProbability = 1 - ifNode.probability(trueTarget);
+        /*
+         * P(Y | not(X)) = P(Y inter not(X)) / P(not(X)) = (P(X union Y) - P(X)) / (1 - P(X))
+         * 
+         * P(X) = shortCircuitProbability
+         * 
+         * P(X union Y) = ifNode.probability(trueTarget)
+         */
+        double secondIfProbability = (ifNode.probability(trueTarget) - shortCircuitProbability) / (1 - shortCircuitProbability);
+        secondIfProbability = Math.min(1.0, Math.max(0.0, secondIfProbability));
+        if (Double.isNaN(secondIfProbability)) {
+            secondIfProbability = 0.5;
+        }
         ifNode.clearSuccessors();
         Graph graph = ifNode.graph();
-        MergeNode falseTargetMerge = graph.add(new MergeNode());
-        falseTargetMerge.setNext(falseTarget);
-        EndNode firstFalseEnd = graph.add(new EndNode());
-        EndNode secondFalseEnd = graph.add(new EndNode());
-        falseTargetMerge.addForwardEnd(firstFalseEnd);
-        falseTargetMerge.addForwardEnd(secondFalseEnd);
-        AbstractBeginNode firstFalseTarget = AbstractBeginNode.begin(firstFalseEnd);
-        AbstractBeginNode secondFalseTarget = AbstractBeginNode.begin(secondFalseEnd);
-        AbstractBeginNode secondIf = AbstractBeginNode.begin(graph.add(new IfNode(y, yNegated ? firstFalseTarget : trueTarget, yNegated ? trueTarget : firstFalseTarget, secondIfProbability)));
-        IfNode firstIf = graph.add(new IfNode(x, xNegated ? secondFalseTarget : secondIf, xNegated ? secondIf : secondFalseTarget, firstIfProbability));
+        MergeNode trueTargetMerge = graph.add(new MergeNode());
+        trueTargetMerge.setNext(trueTarget);
+        EndNode firstTrueEnd = graph.add(new EndNode());
+        EndNode secondTrueEnd = graph.add(new EndNode());
+        trueTargetMerge.addForwardEnd(firstTrueEnd);
+        trueTargetMerge.addForwardEnd(secondTrueEnd);
+        AbstractBeginNode firstTrueTarget = AbstractBeginNode.begin(firstTrueEnd);
+        AbstractBeginNode secondTrueTarget = AbstractBeginNode.begin(secondTrueEnd);
+        AbstractBeginNode secondIf = AbstractBeginNode.begin(graph.add(new IfNode(y, yNegated ? falseTarget : secondTrueTarget, yNegated ? secondTrueTarget : falseTarget, secondIfProbability)));
+        IfNode firstIf = graph.add(new IfNode(x, xNegated ? secondIf : firstTrueTarget, xNegated ? firstTrueTarget : secondIf, firstIfProbability));
         ifNode.replaceAtPredecessor(firstIf);
         ifNode.safeDelete();
     }
 
-    private static void processConditional(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, ConditionalNode conditional, boolean negateTargets) {
-        ValueNode trueTarget = negateTargets ? conditional.falseValue() : conditional.trueValue();
-        ValueNode falseTarget = negateTargets ? conditional.trueValue() : conditional.falseValue();
+    private static void processConditional(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, ConditionalNode conditional) {
+        ValueNode trueTarget = conditional.trueValue();
+        ValueNode falseTarget = conditional.falseValue();
         Graph graph = conditional.graph();
         ConditionalNode secondConditional = graph.unique(new ConditionalNode(y, yNegated ? falseTarget : trueTarget, yNegated ? trueTarget : falseTarget));
-        ConditionalNode firstConditional = graph.unique(new ConditionalNode(x, xNegated ? falseTarget : secondConditional, xNegated ? secondConditional : falseTarget));
+        ConditionalNode firstConditional = graph.unique(new ConditionalNode(x, xNegated ? secondConditional : trueTarget, xNegated ? trueTarget : secondConditional));
         conditional.replaceAndDelete(firstConditional);
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -37,24 +37,29 @@
 
 public class FloatingReadPhase extends Phase {
 
-    private static class MemoryMap {
+    public enum ExecutionMode {
+        ANALYSIS_ONLY, CREATE_FLOATING_READS
+    }
+
+    public static class MemoryMapImpl extends MemoryMapNode {
 
         private IdentityHashMap<LocationIdentity, ValueNode> lastMemorySnapshot;
 
-        public MemoryMap(MemoryMap memoryMap) {
+        public MemoryMapImpl(MemoryMapImpl memoryMap) {
             lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot);
         }
 
-        public MemoryMap(StartNode start) {
+        public MemoryMapImpl(StartNode start) {
             this();
             lastMemorySnapshot.put(ANY_LOCATION, start);
         }
 
-        public MemoryMap() {
+        public MemoryMapImpl() {
             lastMemorySnapshot = new IdentityHashMap<>();
         }
 
-        private ValueNode getLastLocationAccess(LocationIdentity locationIdentity) {
+        @Override
+        public ValueNode getLastLocationAccess(LocationIdentity locationIdentity) {
             ValueNode lastLocationAccess;
             if (locationIdentity == FINAL_LOCATION) {
                 return null;
@@ -68,17 +73,43 @@
             }
         }
 
-        @Override
-        public String toString() {
-            return "Map=" + lastMemorySnapshot.toString();
+        public boolean isEmpty() {
+            if (lastMemorySnapshot.size() == 0) {
+                return true;
+            }
+            if (lastMemorySnapshot.size() == 1) {
+                if (lastMemorySnapshot.get(ANY_LOCATION) instanceof StartNode) {
+                    return true;
+                }
+            }
+            return false;
         }
+
+        public Set<LocationIdentity> getLocations() {
+            return lastMemorySnapshot.keySet();
+        }
+
+    }
+
+    private final ExecutionMode execmode;
+
+    public FloatingReadPhase() {
+        this(ExecutionMode.CREATE_FLOATING_READS);
+    }
+
+    public FloatingReadPhase(ExecutionMode execmode) {
+        this.execmode = execmode;
     }
 
     @Override
     protected void run(StructuredGraph graph) {
         Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops = new IdentityHashMap<>();
         ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), new HashSet<LocationIdentity>(), null);
-        ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops), graph.start(), new MemoryMap(graph.start()), null);
+        ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, execmode), graph.start(), new MemoryMapImpl(graph.start()), null);
+        if (execmode == ExecutionMode.CREATE_FLOATING_READS) {
+            assert !graph.isAfterFloatingReadPhase();
+            graph.setAfterFloatingReadPhase(true);
+        }
     }
 
     private static class CollectMemoryCheckpointsClosure extends NodeIteratorClosure<Set<LocationIdentity>> {
@@ -133,17 +164,19 @@
 
     }
 
-    private static class FloatingReadClosure extends NodeIteratorClosure<MemoryMap> {
+    private static class FloatingReadClosure extends NodeIteratorClosure<MemoryMapImpl> {
 
         private final Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops;
+        private final ExecutionMode execmode;
 
-        public FloatingReadClosure(Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops) {
+        public FloatingReadClosure(Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops, ExecutionMode execmode) {
             this.modifiedInLoops = modifiedInLoops;
+            this.execmode = execmode;
         }
 
         @Override
-        protected MemoryMap processNode(FixedNode node, MemoryMap state) {
-            if (node instanceof FloatableAccessNode) {
+        protected MemoryMapImpl processNode(FixedNode node, MemoryMapImpl state) {
+            if (node instanceof FloatableAccessNode && execmode == ExecutionMode.CREATE_FLOATING_READS) {
                 processFloatable((FloatableAccessNode) node, state);
             } else if (node instanceof MemoryCheckpoint.Single) {
                 processCheckpoint((MemoryCheckpoint.Single) node, state);
@@ -151,27 +184,31 @@
                 processCheckpoint((MemoryCheckpoint.Multi) node, state);
             }
             assert MemoryCheckpoint.TypeAssertion.correctType(node) : node;
+
+            if (execmode == ExecutionMode.ANALYSIS_ONLY && node instanceof ReturnNode) {
+                ((ReturnNode) node).setMemoryMap(node.graph().unique(new MemoryMapImpl(state)));
+            }
             return state;
         }
 
-        private static void processCheckpoint(MemoryCheckpoint.Single checkpoint, MemoryMap state) {
-            LocationIdentity identity = checkpoint.getLocationIdentity();
+        private static void processCheckpoint(MemoryCheckpoint.Single checkpoint, MemoryMapImpl state) {
+            processIdentity(checkpoint.getLocationIdentity(), checkpoint, state);
+        }
+
+        private static void processCheckpoint(MemoryCheckpoint.Multi checkpoint, MemoryMapImpl state) {
+            for (LocationIdentity identity : checkpoint.getLocationIdentities()) {
+                processIdentity(identity, checkpoint, state);
+            }
+        }
+
+        private static void processIdentity(LocationIdentity identity, MemoryCheckpoint checkpoint, MemoryMapImpl state) {
             if (identity == ANY_LOCATION) {
                 state.lastMemorySnapshot.clear();
             }
             state.lastMemorySnapshot.put(identity, (ValueNode) checkpoint);
         }
 
-        private static void processCheckpoint(MemoryCheckpoint.Multi checkpoint, MemoryMap state) {
-            for (LocationIdentity identity : checkpoint.getLocationIdentities()) {
-                if (identity == ANY_LOCATION) {
-                    state.lastMemorySnapshot.clear();
-                }
-                state.lastMemorySnapshot.put(identity, (ValueNode) checkpoint);
-            }
-        }
-
-        private static void processFloatable(FloatableAccessNode accessNode, MemoryMap state) {
+        private static void processFloatable(FloatableAccessNode accessNode, MemoryMapImpl state) {
             StructuredGraph graph = accessNode.graph();
             assert accessNode.getNullCheck() == false;
             LocationIdentity locationIdentity = accessNode.location().getLocationIdentity();
@@ -190,11 +227,11 @@
         }
 
         @Override
-        protected MemoryMap merge(MergeNode merge, List<MemoryMap> states) {
-            MemoryMap newState = new MemoryMap();
+        protected MemoryMapImpl merge(MergeNode merge, List<MemoryMapImpl> states) {
+            MemoryMapImpl newState = new MemoryMapImpl();
 
             Set<LocationIdentity> keys = new HashSet<>();
-            for (MemoryMap other : states) {
+            for (MemoryMapImpl other : states) {
                 keys.addAll(other.lastMemorySnapshot.keySet());
             }
             assert !keys.contains(FINAL_LOCATION);
@@ -203,7 +240,7 @@
                 int mergedStatesCount = 0;
                 boolean isPhi = false;
                 ValueNode merged = null;
-                for (MemoryMap state : states) {
+                for (MemoryMapImpl state : states) {
                     ValueNode last = state.getLastLocationAccess(key);
                     if (isPhi) {
                         ((PhiNode) merged).addInput(last);
@@ -213,7 +250,7 @@
                         } else if (merged == null) {
                             merged = last;
                         } else {
-                            PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge, key));
+                            PhiNode phi = merge.graph().addWithoutUnique(new PhiNode(PhiType.Memory, merge, key));
                             for (int j = 0; j < mergedStatesCount; j++) {
                                 phi.addInput(merged);
                             }
@@ -230,8 +267,8 @@
         }
 
         @Override
-        protected MemoryMap afterSplit(AbstractBeginNode node, MemoryMap oldState) {
-            MemoryMap result = new MemoryMap(oldState);
+        protected MemoryMapImpl afterSplit(AbstractBeginNode node, MemoryMapImpl oldState) {
+            MemoryMapImpl result = new MemoryMapImpl(oldState);
             if (node.predecessor() instanceof InvokeWithExceptionNode) {
                 /*
                  * InvokeWithException cannot be the lastLocationAccess for a FloatingReadNode.
@@ -247,7 +284,7 @@
         }
 
         @Override
-        protected Map<LoopExitNode, MemoryMap> processLoop(LoopBeginNode loop, MemoryMap initialState) {
+        protected Map<LoopExitNode, MemoryMapImpl> processLoop(LoopBeginNode loop, MemoryMapImpl initialState) {
             Set<LocationIdentity> modifiedLocations = modifiedInLoops.get(loop);
             if (modifiedLocations.contains(ANY_LOCATION)) {
                 // create phis for all locations if ANY is modified in the loop
@@ -257,15 +294,15 @@
 
             Map<LocationIdentity, PhiNode> phis = new HashMap<>();
             for (LocationIdentity location : modifiedLocations) {
-                PhiNode phi = loop.graph().add(new PhiNode(PhiType.Memory, loop, location));
+                PhiNode phi = loop.graph().addWithoutUnique(new PhiNode(PhiType.Memory, loop, location));
                 phi.addInput(initialState.getLastLocationAccess(location));
                 phis.put(location, phi);
                 initialState.lastMemorySnapshot.put(location, phi);
             }
 
-            LoopInfo<MemoryMap> loopInfo = ReentrantNodeIterator.processLoop(this, loop, initialState);
+            LoopInfo<MemoryMapImpl> loopInfo = ReentrantNodeIterator.processLoop(this, loop, initialState);
 
-            for (Map.Entry<LoopEndNode, MemoryMap> entry : loopInfo.endStates.entrySet()) {
+            for (Map.Entry<LoopEndNode, MemoryMapImpl> entry : loopInfo.endStates.entrySet()) {
                 int endIndex = loop.phiPredecessorIndex(entry.getKey());
                 for (Map.Entry<LocationIdentity, PhiNode> phiEntry : phis.entrySet()) {
                     LocationIdentity key = phiEntry.getKey();
@@ -273,9 +310,9 @@
                     phi.initializeValueAt(endIndex, entry.getValue().getLastLocationAccess(key));
                 }
             }
-            for (Map.Entry<LoopExitNode, MemoryMap> entry : loopInfo.exitStates.entrySet()) {
+            for (Map.Entry<LoopExitNode, MemoryMapImpl> entry : loopInfo.exitStates.entrySet()) {
                 LoopExitNode exit = entry.getKey();
-                MemoryMap state = entry.getValue();
+                MemoryMapImpl state = entry.getValue();
                 for (LocationIdentity location : modifiedLocations) {
                     ValueNode lastAccessAtExit = state.lastMemorySnapshot.get(location);
                     if (lastAccessAtExit != null) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -27,11 +27,22 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
 
+/**
+ * This phase transfers {@link FrameState} nodes from {@link StateSplit} nodes to
+ * {@link DeoptimizingNode DeoptimizingNodes}.
+ * 
+ * This allow to enter the {@link GuardsStage#AFTER_FSA AFTER_FSA} stage of the graph where no new
+ * node that may cause deoptimization can be introduced anymore.
+ * <p>
+ * This Phase processes the graph in post order, assigning the {@link FrameState} from the last
+ * {@link StateSplit} node to {@link DeoptimizingNode DeoptimizingNodes}.
+ */
 public class FrameStateAssignmentPhase extends Phase {
 
     private static class FrameStateAssignmentClosure extends NodeIteratorClosure<FrameState> {
@@ -77,6 +88,8 @@
     protected void run(StructuredGraph graph) {
         assert checkFixedDeopts(graph);
         ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null, null);
+
+        graph.setGuardsStage(GuardsStage.AFTER_FSA);
     }
 
     private static boolean checkFixedDeopts(StructuredGraph graph) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,6 +29,7 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
@@ -36,15 +37,16 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.phases.schedule.SchedulePhase.SchedulingStrategy;
 import com.oracle.graal.phases.tiers.*;
 
 /**
  * This phase lowers {@link GuardNode GuardNodes} into corresponding control-flow structure and
  * {@link DeoptimizeNode DeoptimizeNodes}.
  * 
- * This allow to enter a phase of the compiler where all node that may cause deoptimization are
- * fixed.
- * 
+ * This allow to enter the {@link GuardsStage#FIXED_DEOPTS FIXED_DEOPTS} stage of the graph where
+ * all node that may cause deoptimization are fixed.
+ * <p>
  * It first makes a schedule in order to know where the control flow should be placed. Then, for
  * each block, it applies two passes. The first one tries to replace null-check guards with implicit
  * null checks performed by access to the objects that need to be null checked. The second phase
@@ -181,19 +183,20 @@
 
     @Override
     protected void run(StructuredGraph graph, MidTierContext context) {
-        SchedulePhase schedule = new SchedulePhase();
+        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
         schedule.apply(graph);
 
         for (Block block : schedule.getCFG().getBlocks()) {
             processBlock(block, schedule, context.getTarget().implicitNullCheckLimit);
         }
+
+        graph.setGuardsStage(GuardsStage.FIXED_DEOPTS);
     }
 
     private static void processBlock(Block block, SchedulePhase schedule, int implicitNullCheckLimit) {
-        List<ScheduledNode> nodes = schedule.nodesFor(block);
         if (OptImplicitNullChecks.getValue() && implicitNullCheckLimit > 0) {
-            new UseImplicitNullChecks(implicitNullCheckLimit).processNodes(nodes, block.getBeginNode());
+            new UseImplicitNullChecks(implicitNullCheckLimit).processNodes(block, schedule);
         }
-        new LowerGuards(block).processNodes(nodes, block.getBeginNode());
+        new LowerGuards(block).processNodes(block, schedule);
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,29 +22,48 @@
  */
 package com.oracle.graal.phases.common;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import java.util.*;
 
+import com.oracle.graal.graph.Graph.NodeChangedListener;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
 import com.oracle.graal.phases.tiers.*;
 
+/**
+ * A phase suite that applies {@linkplain CanonicalizerPhase canonicalization} to a graph after all
+ * phases in the suite have been applied if any of the phases changed the graph.
+ */
 public class IncrementalCanonicalizerPhase<C extends PhaseContext> extends PhaseSuite<C> {
 
-    private final CustomCanonicalizer customCanonicalizer;
+    private final CanonicalizerPhase canonicalizer;
 
-    public IncrementalCanonicalizerPhase() {
-        this(null);
-    }
-
-    public IncrementalCanonicalizerPhase(CustomCanonicalizer customCanonicalizer) {
-        this.customCanonicalizer = customCanonicalizer;
+    public IncrementalCanonicalizerPhase(CanonicalizerPhase canonicalizer) {
+        this.canonicalizer = canonicalizer;
     }
 
     @Override
     protected void run(StructuredGraph graph, C context) {
-        int mark = graph.getMark();
+        int newNodesMark = graph.getMark();
+        final Set<Node> changedNodes = new HashSet<>();
+
+        NodeChangedListener listener = new NodeChangedListener() {
+
+            @Override
+            public void nodeChanged(Node node) {
+                changedNodes.add(node);
+            }
+        };
+        graph.trackInputChange(listener);
+        graph.trackUsagesDroppedZero(listener);
+
         super.run(graph, context);
-        new CanonicalizerPhase.Instance(context.getRuntime(), context.getAssumptions(), !AOTCompilation.getValue(), mark, customCanonicalizer).apply(graph);
+
+        graph.stopTrackingInputChange();
+        graph.stopTrackingUsagesDroppedZero();
+
+        if (graph.getMark() != newNodesMark || !changedNodes.isEmpty()) {
+            canonicalizer.applyIncremental(graph, context, changedNodes, newNodesMark, false);
+        }
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -39,7 +39,6 @@
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
-import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
 import com.oracle.graal.phases.common.InliningUtil.InlineInfo;
 import com.oracle.graal.phases.common.InliningUtil.Inlineable;
 import com.oracle.graal.phases.common.InliningUtil.InlineableGraph;
@@ -59,7 +58,7 @@
     }
 
     private final InliningPolicy inliningPolicy;
-    private final CustomCanonicalizer customCanonicalizer;
+    private final CanonicalizerPhase canonicalizer;
 
     private int inliningCount;
     private int maxMethodPerInlining = Integer.MAX_VALUE;
@@ -68,27 +67,19 @@
     private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
     private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
     private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize");
-    private static final DebugMetric metricInliningRuns = Debug.metric("Runs");
+    private static final DebugMetric metricInliningRuns = Debug.metric("InliningRuns");
 
-    public InliningPhase() {
-        this(new GreedyInliningPolicy(null), null);
-    }
-
-    public InliningPhase(CustomCanonicalizer canonicalizer) {
+    public InliningPhase(CanonicalizerPhase canonicalizer) {
         this(new GreedyInliningPolicy(null), canonicalizer);
     }
 
-    public InliningPhase(Map<Invoke, Double> hints) {
-        this(new GreedyInliningPolicy(hints), null);
+    public InliningPhase(Map<Invoke, Double> hints, CanonicalizerPhase canonicalizer) {
+        this(new GreedyInliningPolicy(hints), canonicalizer);
     }
 
-    public InliningPhase(InliningPolicy policy) {
-        this(policy, null);
-    }
-
-    private InliningPhase(InliningPolicy policy, CustomCanonicalizer customCanonicalizer) {
+    public InliningPhase(InliningPolicy policy, CanonicalizerPhase canonicalizer) {
         this.inliningPolicy = policy;
-        this.customCanonicalizer = customCanonicalizer;
+        this.canonicalizer = canonicalizer;
     }
 
     public void setMaxMethodsPerInlining(int max) {
@@ -163,7 +154,7 @@
             MethodInvocation calleeInvocation = data.pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance);
 
             for (int i = 0; i < info.numberOfMethods(); i++) {
-                Inlineable elem = getInlineableElement(info.methodAt(i), info.invoke(), calleeInvocation.assumptions(), context);
+                Inlineable elem = getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeInvocation.assumptions()));
                 info.setInlinableElement(i, elem);
                 if (elem instanceof InlineableGraph) {
                     data.pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
@@ -200,7 +191,7 @@
 
             if (OptCanonicalizer.getValue()) {
                 int markBeforeCanonicalization = callerGraph.getMark();
-                new CanonicalizerPhase.Instance(context.getRuntime(), callerAssumptions, !AOTCompilation.getValue(), invokeUsages, markBeforeInlining, customCanonicalizer).apply(callerGraph);
+                canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining);
 
                 // process invokes that are possibly created during canonicalization
                 for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
@@ -223,16 +214,16 @@
         }
     }
 
-    private static Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, Assumptions assumptions, HighTierContext context) {
+    private Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context) {
         Class<? extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(context.getReplacements(), method);
         if (macroNodeClass != null) {
             return new InlineableMacroNode(macroNodeClass);
         } else {
-            return new InlineableGraph(buildGraph(method, invoke, assumptions, context));
+            return new InlineableGraph(buildGraph(method, invoke, context));
         }
     }
 
-    private static StructuredGraph buildGraph(final ResolvedJavaMethod method, final Invoke invoke, final Assumptions assumptions, final HighTierContext context) {
+    private StructuredGraph buildGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context) {
         final StructuredGraph newGraph;
         final boolean parseBytecodes;
 
@@ -258,7 +249,7 @@
             @Override
             public StructuredGraph call() throws Exception {
                 if (parseBytecodes) {
-                    parseBytecodes(newGraph, assumptions, context);
+                    parseBytecodes(newGraph, context);
                 }
 
                 boolean callerHasMoreInformationAboutArguments = false;
@@ -285,7 +276,7 @@
                 }
 
                 if (OptCanonicalizer.getValue()) {
-                    new CanonicalizerPhase.Instance(context.getRuntime(), assumptions, !AOTCompilation.getValue()).apply(newGraph);
+                    canonicalizer.apply(newGraph, context);
                 }
 
                 return newGraph;
@@ -303,7 +294,7 @@
         return null;
     }
 
-    private static StructuredGraph parseBytecodes(StructuredGraph newGraph, Assumptions assumptions, HighTierContext context) {
+    private StructuredGraph parseBytecodes(StructuredGraph newGraph, HighTierContext context) {
         boolean hasMatureProfilingInfo = newGraph.method().getProfilingInfo().isMature();
 
         if (context.getPhasePlan() != null) {
@@ -314,7 +305,7 @@
         new DeadCodeEliminationPhase().apply(newGraph);
 
         if (OptCanonicalizer.getValue()) {
-            new CanonicalizerPhase.Instance(context.getRuntime(), assumptions, !AOTCompilation.getValue()).apply(newGraph);
+            canonicalizer.apply(newGraph, context);
         }
 
         if (CacheGraphs.getValue() && context.getGraphCache() != null) {
@@ -416,7 +407,7 @@
         }
     }
 
-    private static final class GreedyInliningPolicy extends AbstractInliningPolicy {
+    public static class GreedyInliningPolicy extends AbstractInliningPolicy {
 
         public GreedyInliningPolicy(Map<Invoke, Double> hints) {
             super(hints);
@@ -646,10 +637,15 @@
             }
         }
 
+        private static final Object[] NO_CONTEXT = {};
+
         /**
-         * Gets the call hierarchy of this inling from outer most call to inner most callee.
+         * Gets the call hierarchy of this inlining from outer most call to inner most callee.
          */
         public Object[] inliningContext() {
+            if (!Debug.isDumpEnabled()) {
+                return NO_CONTEXT;
+            }
             Object[] result = new Object[graphQueue.size()];
             int i = 0;
             for (GraphInfo g : graphQueue) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.phases.common;
 
-import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.nodes.type.StampFactory.*;
 import static com.oracle.graal.phases.GraalOptions.*;
@@ -38,7 +38,8 @@
 import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Node.*;
+import com.oracle.graal.graph.Graph.DuplicationReplacement;
+import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
@@ -349,10 +350,11 @@
      * Represents an inlining opportunity where the compiler can statically determine a monomorphic
      * target method and therefore is able to determine the called method exactly.
      */
-    private static class ExactInlineInfo extends AbstractInlineInfo {
+    public static class ExactInlineInfo extends AbstractInlineInfo {
 
         protected final ResolvedJavaMethod concrete;
         private Inlineable inlineableElement;
+        private boolean suppressNullCheck;
 
         public ExactInlineInfo(Invoke invoke, ResolvedJavaMethod concrete) {
             super(invoke);
@@ -360,9 +362,13 @@
             assert concrete != null;
         }
 
+        public void suppressNullCheck() {
+            suppressNullCheck = true;
+        }
+
         @Override
         public void inline(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements) {
-            inline(invoke, concrete, inlineableElement, assumptions, true);
+            inline(invoke, concrete, inlineableElement, assumptions, !suppressNullCheck);
         }
 
         @Override
@@ -478,7 +484,7 @@
         private void createGuard(StructuredGraph graph, MetaAccessProvider runtime) {
             ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
             ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), runtime, graph);
-            LoadHubNode receiverHub = graph.add(new LoadHubNode(nonNullReceiver, typeHub.kind(), null));
+            LoadHubNode receiverHub = graph.unique(new LoadHubNode(nonNullReceiver, typeHub.kind(), null));
 
             CompareNode typeCheck = CompareNode.createCompareNode(Condition.EQ, receiverHub, typeHub);
             FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
@@ -604,11 +610,11 @@
             ValueNode originalReceiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
             // setup merge and phi nodes for results and exceptions
             MergeNode returnMerge = graph.add(new MergeNode());
-            returnMerge.setStateAfter(invoke.stateAfter().duplicate(invoke.stateAfter().bci));
+            returnMerge.setStateAfter(invoke.stateAfter());
 
             PhiNode returnValuePhi = null;
             if (invoke.asNode().kind() != Kind.Void) {
-                returnValuePhi = graph.add(new PhiNode(invoke.asNode().kind(), returnMerge));
+                returnValuePhi = graph.addWithoutUnique(new PhiNode(invoke.asNode().kind(), returnMerge));
             }
 
             MergeNode exceptionMerge = null;
@@ -621,7 +627,7 @@
 
                 FixedNode exceptionSux = exceptionEdge.next();
                 graph.addBeforeFixed(exceptionSux, exceptionMerge);
-                exceptionObjectPhi = graph.add(new PhiNode(Kind.Object, exceptionMerge));
+                exceptionObjectPhi = graph.addWithoutUnique(new PhiNode(Kind.Object, exceptionMerge));
                 exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Object, exceptionObjectPhi));
             }
 
@@ -707,7 +713,8 @@
                 if (opportunities > 0) {
                     metricInliningTailDuplication.increment();
                     Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
-                    TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, new PhaseContext(runtime, assumptions, replacements));
+                    TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, new PhaseContext(runtime, assumptions, replacements), new CanonicalizerPhase(
+                                    !AOTCompilation.getValue()));
                 }
             }
         }
@@ -763,7 +770,7 @@
             assert ptypes.size() >= 1;
             ValueNode nonNullReceiver = nonNullReceiver(invoke);
             Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
-            LoadHubNode hub = graph.add(new LoadHubNode(nonNullReceiver, hubKind, null));
+            LoadHubNode hub = graph.unique(new LoadHubNode(nonNullReceiver, hubKind, null));
 
             if (!invokeIsOnlySuccessor && chooseMethodDispatch()) {
                 assert successors.length == concretes.size() + 1;
@@ -1287,7 +1294,7 @@
      *            false if no such check is required
      */
     public static Map<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
-        NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
+        final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
         StructuredGraph graph = invoke.asNode().graph();
 
         FrameState stateAfter = invoke.stateAfter();
@@ -1296,17 +1303,17 @@
             nonNullReceiver(invoke);
         }
 
-        IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
-        ArrayList<Node> nodes = new ArrayList<>();
+        ArrayList<Node> nodes = new ArrayList<>(inlineGraph.getNodes().count());
         ReturnNode returnNode = null;
         UnwindNode unwindNode = null;
-        StartNode entryPointNode = inlineGraph.start();
+        final StartNode entryPointNode = inlineGraph.start();
         FixedNode firstCFGNode = entryPointNode.next();
+        if (firstCFGNode == null) {
+            throw new IllegalStateException("Inlined graph is in invalid state");
+        }
         for (Node node : inlineGraph.getNodes()) {
-            if (node == entryPointNode || node == entryPointNode.stateAfter()) {
+            if (node == entryPointNode || node == entryPointNode.stateAfter() || node instanceof LocalNode) {
                 // Do nothing.
-            } else if (node instanceof LocalNode) {
-                replacements.put(node, parameters.get(((LocalNode) node).index()));
             } else {
                 nodes.add(node);
                 if (node instanceof ReturnNode) {
@@ -1318,13 +1325,24 @@
                 }
             }
         }
-        // ensure proper anchoring of things that were anchored to the StartNode
-        replacements.put(entryPointNode, AbstractBeginNode.prevBegin(invoke.asNode()));
+
+        final AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(invoke.asNode());
+        DuplicationReplacement localReplacement = new DuplicationReplacement() {
+
+            public Node replacement(Node node) {
+                if (node instanceof LocalNode) {
+                    return parameters.get(((LocalNode) node).index());
+                } else if (node == entryPointNode) {
+                    return prevBegin;
+                }
+                return node;
+            }
+        };
 
         assert invoke.asNode().successors().first() != null : invoke;
         assert invoke.asNode().predecessor() != null;
 
-        Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements);
+        Map<Node, Node> duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
         FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
         invoke.asNode().replaceAtPredecessor(firstCFGNodeDuplicate);
 
@@ -1367,7 +1385,8 @@
         if (stateAfter != null) {
             FrameState outerFrameState = null;
             int callerLockDepth = stateAfter.nestedLockDepth();
-            for (Node node : duplicates.values()) {
+            for (Node inlinedNode : inlineGraph.getNodes()) {
+                Node node = duplicates.get(inlinedNode);
                 if (node instanceof FrameState) {
                     FrameState frameState = (FrameState) node;
                     assert frameState.bci != FrameState.BEFORE_BCI : frameState;
@@ -1391,12 +1410,6 @@
                             frameState.setOuterFrameState(outerFrameState);
                         }
                     }
-                } else if (node instanceof ValueAnchorNode) {
-                    /*
-                     * Synchronized inlinees have a valid point to deopt to after the monitor exit
-                     * at the end, so there's no need for the value anchor to be permanent anymore.
-                     */
-                    ((ValueAnchorNode) node).setPermanent(false);
                 }
                 if (callerLockDepth != 0 && node instanceof MonitorReference) {
                     MonitorReference monitor = (MonitorReference) node;
@@ -1409,8 +1422,8 @@
         Node returnValue = null;
         if (returnNode != null) {
             if (returnNode.result() instanceof LocalNode) {
-                returnValue = replacements.get(returnNode.result());
-            } else {
+                returnValue = localReplacement.replacement(returnNode.result());
+            } else if (returnNode.result() != null) {
                 returnValue = duplicates.get(returnNode.result());
             }
             invoke.asNode().replaceAtUsages(returnValue);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InsertStateAfterPlaceholderPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * 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.phases.common;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.phases.*;
-
-public class InsertStateAfterPlaceholderPhase extends Phase {
-
-    private static class PlaceholderNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, LIRLowerable, Canonicalizable {
-
-        public PlaceholderNode() {
-            super(StampFactory.forVoid());
-        }
-
-        @Override
-        public void generate(LIRGeneratorTool gen) {
-            // nothing to do
-        }
-
-        @Override
-        public boolean hasSideEffect() {
-            return false;
-        }
-
-        @Override
-        public ValueNode canonical(CanonicalizerTool tool) {
-            if (!usages().isEmpty()) {
-                return this;
-            }
-            if (stateAfter() == null) {
-                return null;
-            }
-            FixedNode next = next();
-            if (next instanceof PlaceholderNode && ((PlaceholderNode) next).stateAfter() != null) {
-                return null;
-            }
-            return this;
-        }
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        boolean needsPlaceHolder = false;
-        for (Node node : graph.getNodes().filterInterface(StateSplit.class)) {
-            StateSplit stateSplit = (StateSplit) node;
-            if (stateSplit.hasSideEffect() && stateSplit.stateAfter() != null) {
-                needsPlaceHolder = true;
-            }
-        }
-        if (needsPlaceHolder) {
-            for (ReturnNode ret : graph.getNodes(ReturnNode.class)) {
-                PlaceholderNode p = graph.add(new PlaceholderNode());
-                p.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI)));
-                graph.addBeforeFixed(ret, p);
-            }
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.phases.common;
 
-import static com.oracle.graal.phases.GraalOptions.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -36,6 +34,12 @@
 
     private static final int MAX_ITERATIONS = 256;
 
+    private final CanonicalizerPhase canonicalizer;
+
+    public IterativeConditionalEliminationPhase(CanonicalizerPhase canonicalizer) {
+        this.canonicalizer = canonicalizer;
+    }
+
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
         ConditionalEliminationPhase eliminate = new ConditionalEliminationPhase(context.getRuntime());
@@ -55,7 +59,7 @@
                     listener.getChangedNodes().add(node);
                 }
             }
-            new CanonicalizerPhase.Instance(context.getRuntime(), context.getAssumptions(), !AOTCompilation.getValue(), listener.getChangedNodes(), null).apply(graph);
+            canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
             listener.getChangedNodes().clear();
             if (++count > MAX_ITERATIONS) {
                 throw new BailoutException("Number of iterations in conditional elimination phase exceeds " + MAX_ITERATIONS);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoopSafepointInsertionPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011, 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;
+
+import static com.oracle.graal.phases.GraalOptions.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+
+/**
+ * Adds safepoints to loops.
+ */
+public class LoopSafepointInsertionPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (GenLoopSafepoints.getValue()) {
+            for (LoopEndNode loopEndNode : graph.getNodes(LoopEndNode.class)) {
+                if (loopEndNode.canSafepoint()) {
+                    SafepointNode safepointNode = graph.add(new SafepointNode());
+                    graph.addBeforeFixed(loopEndNode, safepointNode);
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,11 +31,11 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.schedule.*;
@@ -73,20 +73,22 @@
         }
 
         @Override
-        public LoweringType getLoweringType() {
-            return loweringType;
-        }
-
-        @Override
         public GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object) {
             if (ObjectStamp.isObjectNonNull(object)) {
                 // Short cut creation of null check guard if the object is known to be non-null.
                 return null;
             }
-            GuardingNode guard = createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
-            assert guardedNode.getGuard() == null;
-            guardedNode.setGuard(guard);
-            return guard;
+            StructuredGraph graph = object.graph();
+            if (graph.getGuardsStage().ordinal() > GuardsStage.FLOATING_GUARDS.ordinal()) {
+                NullCheckNode nullCheck = graph.add(new NullCheckNode(object));
+                graph.addBeforeFixed((FixedNode) guardedNode, nullCheck);
+                return nullCheck;
+            } else {
+                GuardingNode guard = createGuard(graph.unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
+                assert guardedNode.getGuard() == null;
+                guardedNode.setGuard(guard);
+                return guard;
+            }
         }
 
         @Override
@@ -101,8 +103,8 @@
 
         @Override
         public GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
-            if (loweringType != LoweringType.BEFORE_GUARDS) {
-                throw new GraalInternalError("Cannot create guards in after-guard lowering");
+            if (condition.graph().getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
+                throw new GraalInternalError("Cannot create guards after guard lowering");
             }
             if (OptEliminateGuards.getValue()) {
                 for (Node usage : condition.usages()) {
@@ -134,39 +136,61 @@
         }
     }
 
-    private final LoweringType loweringType;
+    private final CanonicalizerPhase canonicalizer;
 
-    public LoweringPhase(LoweringType loweringType) {
-        super("Lowering (" + loweringType.name() + ")");
-        this.loweringType = loweringType;
+    public LoweringPhase(CanonicalizerPhase canonicalizer) {
+        this.canonicalizer = canonicalizer;
     }
 
-    private static boolean containsLowerable(NodeIterable<Node> nodes) {
-        for (Node n : nodes) {
-            if (n instanceof Lowerable) {
-                return true;
-            }
-        }
-        return false;
+    /**
+     * Checks that second lowering of a given graph did not introduce any new nodes.
+     * 
+     * @param graph a graph that was just {@linkplain #lower lowered}
+     * @throws AssertionError if the check fails
+     */
+    private boolean checkPostLowering(StructuredGraph graph, PhaseContext context) {
+        int expectedMark = graph.getMark();
+        lower(graph, context, 1);
+        int mark = graph.getMark();
+        assert mark == expectedMark : graph + ": a second round in the current lowering phase introduced these new nodes: " + graph.getNewNodes(mark).snapshot();
+        return true;
     }
 
     @Override
     protected void run(final StructuredGraph graph, PhaseContext context) {
-        int i = 0;
-        while (true) {
-            Round round = new Round(i++, context);
-            int mark = graph.getMark();
+        lower(graph, context, 0);
+        assert checkPostLowering(graph, context);
+    }
+
+    private void lower(StructuredGraph graph, PhaseContext context, int i) {
+        IncrementalCanonicalizerPhase<PhaseContext> incrementalCanonicalizer = new IncrementalCanonicalizerPhase<>(canonicalizer);
+        incrementalCanonicalizer.appendPhase(new Round(i, context));
+        incrementalCanonicalizer.apply(graph, context);
+        assert graph.verify();
+    }
 
-            IncrementalCanonicalizerPhase<PhaseContext> canonicalizer = new IncrementalCanonicalizerPhase<>();
-            canonicalizer.appendPhase(round);
-            canonicalizer.apply(graph, context);
-
-            if (!containsLowerable(graph.getNewNodes(mark))) {
-                // No new lowerable nodes - done!
-                break;
+    /**
+     * Checks that lowering of a given node did not introduce any new {@link Lowerable} nodes that
+     * could be lowered in the current {@link LoweringPhase}. Such nodes must be recursively lowered
+     * as part of lowering {@code node}.
+     * 
+     * @param node a node that was just lowered
+     * @param preLoweringMark the graph mark before {@code node} was lowered
+     * @throws AssertionError if the check fails
+     */
+    private static boolean checkPostNodeLowering(Node node, LoweringToolImpl loweringTool, int preLoweringMark) {
+        StructuredGraph graph = (StructuredGraph) node.graph();
+        int postLoweringMark = graph.getMark();
+        NodeIterable<Node> newNodesAfterLowering = graph.getNewNodes(preLoweringMark);
+        for (Node n : newNodesAfterLowering) {
+            if (n instanceof Lowerable) {
+                ((Lowerable) n).lower(loweringTool);
+                int mark = graph.getMark();
+                assert postLoweringMark == mark : graph + ": lowering of " + node + " produced lowerable " + n + " that should have been recursively lowered as it introduces these new nodes: " +
+                                graph.getNewNodes(postLoweringMark).snapshot();
             }
-            assert graph.verify();
         }
+        return true;
     }
 
     private final class Round extends Phase {
@@ -175,7 +199,7 @@
         private final SchedulePhase schedule;
 
         private Round(int iteration, PhaseContext context) {
-            super(String.format("Lowering iteration %d", iteration));
+            super("LoweringIteration" + iteration);
             this.context = context;
             this.schedule = new SchedulePhase();
         }
@@ -210,7 +234,9 @@
 
             if (parentAnchor == null && OptEliminateGuards.getValue()) {
                 for (GuardNode guard : anchor.asNode().usages().filter(GuardNode.class)) {
-                    activeGuards.clear(guard);
+                    if (activeGuards.contains(guard)) {
+                        activeGuards.clear(guard);
+                    }
                 }
             }
         }
@@ -239,17 +265,23 @@
 
                 if (node instanceof Lowerable) {
                     assert checkUsagesAreScheduled(node);
-                    ((Lowerable) node).lower(loweringTool, loweringType);
+                    int preLoweringMark = node.graph().getMark();
+                    ((Lowerable) node).lower(loweringTool);
+                    assert checkPostNodeLowering(node, loweringTool, preLoweringMark);
                 }
 
                 if (!nextNode.isAlive()) {
-                    // can happen when the rest of the block is killed by lowering (e.g. by a
-                    // unconditional deopt)
+                    // can happen when the rest of the block is killed by lowering
+                    // (e.g. by an unconditional deopt)
                     break;
                 } else {
                     Node nextLastFixed = nextNode.predecessor();
                     if (!(nextLastFixed instanceof FixedWithNextNode)) {
                         // insert begin node, to have a valid last fixed for next lowerable node.
+                        // This is about lowering a FixedWithNextNode to a control split while this
+                        // FixedWithNextNode is followed by some kind of BeginNode.
+                        // For example the when a FixedGuard followed by a loop exit is lowered to a
+                        // control-split + deopt.
                         BeginNode begin = node.graph().add(new BeginNode());
                         nextLastFixed.replaceFirstSuccessor(nextNode, begin);
                         begin.setNext(nextNode);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -87,7 +87,7 @@
         }
         if (lastLocationAccess instanceof PhiNode) {
             PhiNode phi = (PhiNode) lastLocationAccess;
-            PhiNode newPhi = phi.graph().add(new PhiNode(n.kind(), phi.merge()));
+            PhiNode newPhi = phi.graph().addWithoutUnique(new PhiNode(n.kind(), phi.merge()));
             nodeMap.set(lastLocationAccess, newPhi);
             for (ValueNode value : phi.values()) {
                 newPhi.addInput(getValue(n, value, nodeMap));
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/SafepointInsertionPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2011, 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;
-
-import static com.oracle.graal.phases.GraalOptions.*;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.phases.*;
-
-/**
- * Adds safepoints to loops and return points.
- */
-public class SafepointInsertionPhase extends Phase {
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (GenLoopSafepoints.getValue()) {
-            for (LoopEndNode loopEndNode : graph.getNodes(LoopEndNode.class)) {
-                if (!loopEndNode.canSafepoint()) {
-                    continue;
-                }
-                SafepointNode safepointNode = graph.add(new SafepointNode());
-                graph.addBeforeFixed(loopEndNode, safepointNode);
-            }
-        }
-
-        if (GenSafepoints.getValue()) {
-            if (!OptEliminateSafepoints.getValue() || graph.getNodes(MethodCallTargetNode.class).isNotEmpty()) {
-                for (ReturnNode returnNode : graph.getNodes(ReturnNode.class)) {
-                    SafepointNode safepoint = graph.add(new SafepointNode());
-                    graph.addBeforeFixed(returnNode, safepoint);
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -42,8 +42,8 @@
 
 /**
  * This class is a phase that looks for opportunities for tail duplication. The static method
- * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List, PhaseContext)} can also be used
- * to drive tail duplication from other places, e.g., inlining.
+ * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List, PhaseContext, CanonicalizerPhase)}
+ * can also be used to drive tail duplication from other places, e.g., inlining.
  */
 public class TailDuplicationPhase extends BasePhase<PhaseContext> {
 
@@ -53,6 +53,8 @@
     private static final DebugMetric metricDuplicationConsidered = Debug.metric("DuplicationConsidered");
     private static final DebugMetric metricDuplicationPerformed = Debug.metric("DuplicationPerformed");
 
+    private final CanonicalizerPhase canonicalizer;
+
     /**
      * This interface is used by tail duplication to let clients decide if tail duplication should
      * be performed.
@@ -129,6 +131,10 @@
         }
     };
 
+    public TailDuplicationPhase(CanonicalizerPhase canonicalizer) {
+        this.canonicalizer = canonicalizer;
+    }
+
     @Override
     protected void run(StructuredGraph graph, PhaseContext phaseContext) {
         NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
@@ -137,7 +143,7 @@
         // duplication.
         for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) {
             if (!(merge instanceof LoopBeginNode) && nodeProbabilities.get(merge) >= TailDuplicationProbability.getValue()) {
-                tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext);
+                tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext, canonicalizer);
             }
         }
     }
@@ -159,7 +165,7 @@
      *            {@link PiNode} in the duplicated branch that corresponds to the entry.
      * @param phaseContext
      */
-    public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List<GuardedValueNode> replacements, PhaseContext phaseContext) {
+    public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List<GuardedValueNode> replacements, PhaseContext phaseContext, CanonicalizerPhase canonicalizer) {
         assert !(merge instanceof LoopBeginNode);
         assert replacements == null || replacements.size() == merge.forwardEndCount();
         FixedNode fixed = merge;
@@ -172,7 +178,7 @@
             metricDuplicationConsidered.increment();
             if (decision.doTransform(merge, fixedCount)) {
                 metricDuplicationPerformed.increment();
-                new DuplicationOperation(merge, replacements).duplicate(phaseContext);
+                new DuplicationOperation(merge, replacements, canonicalizer).duplicate(phaseContext);
                 return true;
             }
         }
@@ -190,6 +196,8 @@
         private final HashMap<ValueNode, PhiNode> bottomPhis = new HashMap<>();
         private final List<GuardedValueNode> replacements;
 
+        private final CanonicalizerPhase canonicalizer;
+
         /**
          * Initializes the tail duplication operation without actually performing any work.
          * 
@@ -197,10 +205,11 @@
          * @param replacements A list of replacement {@link PiNode}s, or null. If this is non-null,
          *            then the size of the list needs to match the number of end nodes at the merge.
          */
-        public DuplicationOperation(MergeNode merge, List<GuardedValueNode> replacements) {
+        public DuplicationOperation(MergeNode merge, List<GuardedValueNode> replacements, CanonicalizerPhase canonicalizer) {
             this.merge = merge;
             this.replacements = replacements;
             this.graph = merge.graph();
+            this.canonicalizer = canonicalizer;
         }
 
         /**
@@ -251,11 +260,11 @@
             for (final AbstractEndNode forwardEnd : merge.forwardEnds()) {
                 Map<Node, Node> duplicates;
                 if (replacements == null || replacements.get(endIndex) == null) {
-                    duplicates = graph.addDuplicates(duplicatedNodes, (DuplicationReplacement) null);
+                    duplicates = graph.addDuplicates(duplicatedNodes, graph, duplicatedNodes.size(), (DuplicationReplacement) null);
                 } else {
                     HashMap<Node, Node> replace = new HashMap<>();
                     replace.put(replacements.get(endIndex).object(), replacements.get(endIndex));
-                    duplicates = graph.addDuplicates(duplicatedNodes, replace);
+                    duplicates = graph.addDuplicates(duplicatedNodes, graph, duplicatedNodes.size(), replace);
                 }
                 for (Map.Entry<ValueNode, PhiNode> phi : bottomPhis.entrySet()) {
                     phi.getValue().initializeValueAt(merge.forwardEndIndex(forwardEnd), (ValueNode) duplicates.get(phi.getKey()));
@@ -289,7 +298,7 @@
                     phi.setMerge(mergeAfter);
                 }
             }
-            new CanonicalizerPhase.Instance(phaseContext.getRuntime(), phaseContext.getAssumptions(), !AOTCompilation.getValue(), graph.getNewNodes(startMark), null).apply(graph);
+            canonicalizer.applyIncremental(graph, phaseContext, startMark);
             Debug.dump(graph, "After tail duplication at %s", merge);
         }
 
@@ -300,7 +309,7 @@
          * @return The new {@link ValueAnchorNode} that was created.
          */
         private ValueAnchorNode addValueAnchor() {
-            ValueAnchorNode anchor = graph.add(new ValueAnchorNode());
+            ValueAnchorNode anchor = graph.add(new ValueAnchorNode(null));
             graph.addAfterFixed(merge, anchor);
             for (Node usage : merge.usages().snapshot()) {
                 if (usage instanceof PhiNode && ((PhiNode) usage).merge() == merge) {
@@ -467,7 +476,7 @@
                             // introduce a new phi
                             PhiNode newPhi = bottomPhis.get(node);
                             if (newPhi == null) {
-                                newPhi = graph.add(new PhiNode(node.kind(), newBottomMerge));
+                                newPhi = graph.addWithoutUnique(new PhiNode(node.kind(), newBottomMerge));
                                 bottomPhis.put(node, newPhi);
                                 newPhi.addInput(node);
                             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ValueAnchorCleanupPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ValueAnchorCleanupPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -73,14 +73,15 @@
         protected void node(FixedNode node) {
             if (node instanceof ValueAnchorNode) {
                 ValueAnchorNode anchor = (ValueAnchorNode) node;
-                for (ValueNode anchored : anchor.getAnchoredNodes().snapshot()) {
+                ValueNode anchored = anchor.getAnchoredNode();
+                if (anchored != null) {
                     if (state.anchoredValues.contains(anchored)) {
-                        anchor.removeAnchoredNode(anchored);
+                        anchor.removeAnchoredNode();
                     } else {
                         state.anchoredValues.add(anchored);
                     }
                 }
-                if (!anchor.isPermanent() && anchor.getAnchoredNodes().isEmpty() && anchor.usages().isEmpty()) {
+                if (anchor.getAnchoredNode() == null && anchor.usages().isEmpty()) {
                     node.graph().removeFixed(anchor);
                 }
             }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,10 @@
  */
 package com.oracle.graal.phases;
 
+import java.util.regex.*;
+
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -32,19 +35,35 @@
  */
 public abstract class BasePhase<C> {
 
-    private String name;
-    private static final DebugMetric metricPhaseRuns = Debug.metric("Runs");
-    protected static final DebugMetric METRIC_PROCESSED_NODES = Debug.metric("ProcessedNodes");
+    private final String name;
+
+    private final DebugTimer phaseTimer;
+    private final DebugMetric phaseMetric;
+
+    private static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+");
+
+    private static boolean checkName(String name) {
+        assert NAME_PATTERN.matcher(name).matches() : "illegal phase name: " + name;
+        return true;
+    }
 
     protected BasePhase() {
-        this.name = this.getClass().getSimpleName();
-        if (name.endsWith("Phase")) {
-            name = name.substring(0, name.length() - "Phase".length());
+        String nm = this.getClass().getSimpleName();
+        if (nm.endsWith("Phase")) {
+            name = nm.substring(0, nm.length() - "Phase".length());
+        } else {
+            name = nm;
         }
+        assert checkName(name);
+        phaseTimer = Debug.timer("PhaseTime_" + name);
+        phaseMetric = Debug.metric("PhaseCount_" + name);
     }
 
     protected BasePhase(String name) {
+        assert checkName(name);
         this.name = name;
+        phaseTimer = Debug.timer("PhaseTime_" + name);
+        phaseMetric = Debug.metric("PhaseCount_" + name);
     }
 
     protected String getDetailedName() {
@@ -56,17 +75,20 @@
     }
 
     public final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) {
-        Debug.scope(name, this, new Runnable() {
+        try (TimerCloseable a = phaseTimer.start()) {
+
+            Debug.scope(name, this, new Runnable() {
 
-            public void run() {
-                BasePhase.this.run(graph, context);
-                metricPhaseRuns.increment();
-                if (dumpGraph) {
-                    Debug.dump(graph, "After phase %s", name);
+                public void run() {
+                    BasePhase.this.run(graph, context);
+                    phaseMetric.increment();
+                    if (dumpGraph) {
+                        Debug.dump(graph, "After phase %s", name);
+                    }
+                    assert graph.verify();
                 }
-                assert graph.verify();
-            }
-        });
+            });
+        }
     }
 
     public final String getName() {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Wed Oct 02 13:26:31 2013 +0200
@@ -167,6 +167,8 @@
     @Option(help = "")
     public static final OptionValue<Boolean> PrintCompilation = new OptionValue<>(false);
     @Option(help = "")
+    public static final OptionValue<Boolean> PrintAfterCompilation = new OptionValue<>(false);
+    @Option(help = "")
     public static final OptionValue<Boolean> PrintProfilingInformation = new OptionValue<>(false);
     @Option(help = "")
     public static final OptionValue<Boolean> PrintIRWithLIR = new OptionValue<>(false);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Wed Oct 02 13:26:31 2013 +0200
@@ -126,4 +126,9 @@
     private static boolean checkDeoptimizations(ProfilingInfo profilingInfo, DeoptimizationReason reason) {
         return profilingInfo.getDeoptimizationCount(reason) < GraalOptions.DeoptsToDisableOptimisticOptimization.getValue();
     }
+
+    @Override
+    public String toString() {
+        return enabledOpts.toString();
+    }
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,6 +26,9 @@
 
 import com.oracle.graal.nodes.*;
 
+/**
+ * A compiler phase that can apply an ordered collection of phases to a graph.
+ */
 public class PhaseSuite<C> extends BasePhase<C> {
 
     private final List<BasePhase<? super C>> phases;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java	Wed Oct 02 13:26:31 2013 +0200
@@ -77,8 +77,8 @@
     private void adjustControlSplitProbabilities() {
         HashSet<ControlSplitNode> result = new HashSet<>();
         NodeBitMap visitedNodes = new NodeBitMap(graph);
-        for (DeoptimizeNode n : graph.getNodes(DeoptimizeNode.class)) {
-            if (n.action().doesInvalidateCompilation()) {
+        for (AbstractDeoptimizeNode n : graph.getNodes(AbstractDeoptimizeNode.class)) {
+            if (!(n instanceof DeoptimizeNode) || ((DeoptimizeNode) n).action().doesInvalidateCompilation()) {
                 findParentControlSplitNodes(result, n, visitedNodes);
             }
         }
@@ -90,7 +90,7 @@
         }
     }
 
-    private static void findParentControlSplitNodes(HashSet<ControlSplitNode> result, DeoptimizeNode n, NodeBitMap visitedNodes) {
+    private static void findParentControlSplitNodes(HashSet<ControlSplitNode> result, AbstractDeoptimizeNode n, NodeBitMap visitedNodes) {
         ArrayDeque<FixedNode> nodes = new ArrayDeque<>();
         nodes.push(n);
 
@@ -142,9 +142,9 @@
 
     private boolean verifyProbabilities() {
         if (doesNotAlwaysDeopt(graph)) {
-            for (DeoptimizeNode n : graph.getNodes(DeoptimizeNode.class)) {
-                if (n.action().doesInvalidateCompilation() && nodeProbabilities.get(n) > 0.01) {
-                    throw new AssertionError(String.format("%s with reason %s and probability %f in graph %s", n, n.reason(), nodeProbabilities.get(n), graph));
+            for (AbstractDeoptimizeNode n : graph.getNodes(AbstractDeoptimizeNode.class)) {
+                if (nodeProbabilities.get(n) > 0.01 && (!(n instanceof DeoptimizeNode) || ((DeoptimizeNode) n).action().doesInvalidateCompilation())) {
+                    throw new AssertionError(String.format("%s with probability %f in graph %s", n, nodeProbabilities.get(n), graph));
                 }
             }
         }
@@ -152,7 +152,7 @@
     }
 
     private static boolean doesNotAlwaysDeopt(StructuredGraph graph) {
-        return graph.getNodes(ReturnNode.class).iterator().hasNext();
+        return graph.getNodes().filter(ReturnNode.class).iterator().hasNext();
     }
 
     private void computeLoopFactors() {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Wed Oct 02 13:26:31 2013 +0200
@@ -44,6 +44,15 @@
         protected abstract StateT afterSplit(AbstractBeginNode node, StateT oldState);
 
         protected abstract Map<LoopExitNode, StateT> processLoop(LoopBeginNode loop, StateT initialState);
+
+        /**
+         * Determine whether iteration should continue in the current state.
+         * 
+         * @param currentState
+         */
+        protected boolean continueIteration(StateT currentState) {
+            return true;
+        }
     }
 
     private ReentrantNodeIterator() {
@@ -59,12 +68,14 @@
 
         LoopInfo<StateT> info = new LoopInfo<>();
         for (LoopEndNode end : loop.loopEnds()) {
-            assert blockEndStates.containsKey(end) : "no end state for " + end;
-            info.endStates.put(end, blockEndStates.get(end));
+            if (blockEndStates.containsKey(end)) {
+                info.endStates.put(end, blockEndStates.get(end));
+            }
         }
         for (LoopExitNode exit : loop.loopExits()) {
-            assert blockEndStates.containsKey(exit) : "no exit state for " + exit;
-            info.exitStates.put(exit, blockEndStates.get(exit));
+            if (blockEndStates.containsKey(exit)) {
+                info.exitStates.put(exit, blockEndStates.get(exit));
+            }
         }
         return info;
     }
@@ -83,64 +94,69 @@
                 } else {
                     FixedNode next = ((FixedWithNextNode) current).next();
                     state = closure.processNode(current, state);
-                    current = next;
+                    current = closure.continueIteration(state) ? next : null;
                 }
             }
 
             if (current != null) {
                 state = closure.processNode(current, state);
 
-                NodeClassIterator successors = current.successors().iterator();
-                if (!successors.hasNext()) {
-                    if (current instanceof LoopEndNode) {
-                        blockEndStates.put(current, state);
-                    } else if (current instanceof EndNode) {
-                        // add the end node and see if the merge is ready for processing
-                        MergeNode merge = ((EndNode) current).merge();
-                        if (merge instanceof LoopBeginNode) {
-                            Map<LoopExitNode, StateT> loopExitState = closure.processLoop((LoopBeginNode) merge, state);
-                            for (Map.Entry<LoopExitNode, StateT> entry : loopExitState.entrySet()) {
-                                blockEndStates.put(entry.getKey(), entry.getValue());
-                                nodeQueue.add(entry.getKey());
-                            }
-                        } else {
-                            assert !blockEndStates.containsKey(current);
+                if (closure.continueIteration(state)) {
+                    NodeClassIterator successors = current.successors().iterator();
+                    if (!successors.hasNext()) {
+                        if (current instanceof LoopEndNode) {
                             blockEndStates.put(current, state);
-                            boolean endsVisited = true;
-                            for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
-                                if (!blockEndStates.containsKey(forwardEnd)) {
-                                    endsVisited = false;
-                                    break;
+                        } else if (current instanceof EndNode) {
+                            // add the end node and see if the merge is ready for processing
+                            MergeNode merge = ((EndNode) current).merge();
+                            if (merge instanceof LoopBeginNode) {
+                                Map<LoopExitNode, StateT> loopExitState = closure.processLoop((LoopBeginNode) merge, state);
+                                for (Map.Entry<LoopExitNode, StateT> entry : loopExitState.entrySet()) {
+                                    blockEndStates.put(entry.getKey(), entry.getValue());
+                                    nodeQueue.add(entry.getKey());
+                                }
+                            } else {
+                                assert !blockEndStates.containsKey(current);
+                                blockEndStates.put(current, state);
+                                boolean endsVisited = true;
+                                for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
+                                    if (!blockEndStates.containsKey(forwardEnd)) {
+                                        endsVisited = false;
+                                        break;
+                                    }
+                                }
+                                if (endsVisited) {
+                                    ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
+                                    for (int i = 0; i < merge.forwardEndCount(); i++) {
+                                        AbstractEndNode forwardEnd = merge.forwardEndAt(i);
+                                        assert blockEndStates.containsKey(forwardEnd);
+                                        StateT other = blockEndStates.get(forwardEnd);
+                                        states.add(other);
+                                    }
+                                    state = closure.merge(merge, states);
+                                    current = closure.continueIteration(state) ? merge : null;
+                                    continue;
                                 }
                             }
-                            if (endsVisited) {
-                                ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
-                                for (int i = 0; i < merge.forwardEndCount(); i++) {
-                                    AbstractEndNode forwardEnd = merge.forwardEndAt(i);
-                                    assert blockEndStates.containsKey(forwardEnd);
-                                    StateT other = blockEndStates.get(forwardEnd);
-                                    states.add(other);
-                                }
-                                state = closure.merge(merge, states);
-                                current = merge;
-                                continue;
-                            }
                         }
-                    }
-                } else {
-                    FixedNode firstSuccessor = (FixedNode) successors.next();
-                    if (!successors.hasNext()) {
-                        current = firstSuccessor;
-                        continue;
                     } else {
-                        while (successors.hasNext()) {
-                            AbstractBeginNode successor = (AbstractBeginNode) successors.next();
-                            blockEndStates.put(successor, closure.afterSplit(successor, state));
-                            nodeQueue.add(successor);
+                        FixedNode firstSuccessor = (FixedNode) successors.next();
+                        if (!successors.hasNext()) {
+                            current = firstSuccessor;
+                            continue;
+                        } else {
+                            while (successors.hasNext()) {
+                                AbstractBeginNode successor = (AbstractBeginNode) successors.next();
+                                StateT successorState = closure.afterSplit(successor, state);
+                                if (closure.continueIteration(successorState)) {
+                                    blockEndStates.put(successor, successorState);
+                                    nodeQueue.add(successor);
+                                }
+                            }
+                            state = closure.afterSplit((AbstractBeginNode) firstSuccessor, state);
+                            current = closure.continueIteration(state) ? firstSuccessor : null;
+                            continue;
                         }
-                        state = closure.afterSplit((AbstractBeginNode) firstSuccessor, state);
-                        current = firstSuccessor;
-                        continue;
                     }
                 }
             }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.phases.schedule.*;
 
 /**
@@ -41,11 +42,12 @@
     private FixedWithNextNode reconnect;
     private ListIterator<ScheduledNode> iterator;
 
-    public void processNodes(List<ScheduledNode> nodes, FixedWithNextNode begin) {
-        assert begin != null;
-        lastFixed = begin;
+    public void processNodes(Block block, SchedulePhase shedule) {
+        lastFixed = block.getBeginNode();
+        assert lastFixed != null;
         reconnect = null;
-        iterator = nodes.listIterator();
+        iterator = shedule.nodesFor(block).listIterator();
+
         while (iterator.hasNext()) {
             Node node = iterator.next();
             if (!node.isAlive()) {
@@ -60,7 +62,10 @@
             }
             processNode(node);
         }
-        assert reconnect == null;
+        if (reconnect != null) {
+            assert block.getSuccessorCount() == 1;
+            reconnect.setNext(block.getFirstSuccessor().getBeginNode());
+        }
     }
 
     protected void insert(FixedNode start, FixedWithNextNode end) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,6 +36,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
@@ -785,7 +786,7 @@
                     if (!(usage instanceof FrameState)) {
                         throw new SchedulingError(usage.toString());
                     }
-                    if (!(unscheduledUsage instanceof StateSplit || unscheduledUsage instanceof DeoptimizingNode)) {
+                    if (!(unscheduledUsage instanceof NodeWithState)) {
                         throw new SchedulingError(unscheduledUsage.toString());
                     }
                     // Otherwise: Put the input into the same block as the usage.
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java	Wed Oct 02 13:26:31 2013 +0200
@@ -52,4 +52,8 @@
     public OptimisticOptimizations getOptimisticOptimizations() {
         return optimisticOpts;
     }
+
+    public HighTierContext replaceAssumptions(Assumptions newAssumptions) {
+        return new HighTierContext(getRuntime(), newAssumptions, getReplacements(), getGraphCache(), getPhasePlan(), getOptimisticOptimizations());
+    }
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Wed Oct 02 13:26:31 2013 +0200
@@ -39,7 +39,7 @@
 
         NodeBitMap visited = graph.createNodeBitMap();
 
-        for (ControlSinkNode node : graph.getNodes(ControlSinkNode.class)) {
+        for (ControlSinkNode node : graph.getNodes().filter(ControlSinkNode.class)) {
             result.visitForward(visited, node);
         }
         return result;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/Util.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/Util.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,9 +26,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 
 /**
  * The {@code Util} class contains a motley collection of utility methods used throughout the
@@ -319,14 +316,6 @@
         return (short) v;
     }
 
-    public static boolean isFixed(Node n) {
-        return n instanceof FixedNode;
-    }
-
-    public static boolean isFloating(Node n) {
-        return n instanceof FloatingNode;
-    }
-
     /**
      * Creates an array of integers of length "size", in which each number from 0 to (size - 1)
      * occurs exactly once. The integers are sorted using the given comparator. This can be used to
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java	Wed Oct 02 13:26:31 2013 +0200
@@ -73,7 +73,7 @@
             if (!isEqualsMethod(graph)) {
                 // bail out if we compare an object of type klass with == or != (except null checks)
                 assert !(checkUsage(cn.x(), cn.y(), context.getRuntime()) && checkUsage(cn.y(), cn.x(), context.getRuntime())) : "Verifcation of " + klass.getName() + " usage failed: Comparing " +
-                                cn.x() + " and" + cn.y() + " in " + graph.method() + " must use .equals() for object equality, not '==' or '!='";
+                                cn.x() + " and " + cn.y() + " in " + graph.method() + " must use .equals() for object equality, not '==' or '!='";
             }
         }
         return true;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Wed Oct 02 13:26:31 2013 +0200
@@ -66,6 +66,7 @@
     private static final int PROPERTY_TRUE = 0x05;
     private static final int PROPERTY_FALSE = 0x06;
     private static final int PROPERTY_ARRAY = 0x07;
+    private static final int PROPERTY_SUBGRAPH = 0x08;
 
     private static final int KLASS = 0x00;
     private static final int ENUM_KLASS = 0x01;
@@ -115,6 +116,17 @@
     }
 
     public void print(Graph graph, String title, SchedulePhase predefinedSchedule) throws IOException {
+        writeByte(BEGIN_GRAPH);
+        writePoolObject(title);
+        writeGraph(graph, predefinedSchedule);
+        flush();
+    }
+
+    private void writeGraph(Graph graph) throws IOException {
+        writeGraph(graph, null);
+    }
+
+    private void writeGraph(Graph graph, SchedulePhase predefinedSchedule) throws IOException {
         SchedulePhase schedule = predefinedSchedule;
         if (schedule == null) {
             try {
@@ -126,11 +138,8 @@
         ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG();
         BlockMap<List<ScheduledNode>> blockToNodes = schedule == null ? null : schedule.getBlockToNodesMap();
         Block[] blocks = cfg == null ? null : cfg.getBlocks();
-        writeByte(BEGIN_GRAPH);
-        writePoolObject(title);
         writeNodes(graph);
         writeBlocks(blocks, blockToNodes);
-        flush();
     }
 
     private void flush() throws IOException {
@@ -343,6 +352,9 @@
             } else {
                 writeByte(PROPERTY_FALSE);
             }
+        } else if (obj instanceof Graph) {
+            writeByte(PROPERTY_SUBGRAPH);
+            writeGraph((Graph) obj);
         } else if (obj != null && obj.getClass().isArray()) {
             Class<?> componentType = obj.getClass().getComponentType();
             if (componentType.isPrimitive()) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Wed Oct 02 13:26:31 2013 +0200
@@ -243,12 +243,6 @@
         out.println("HIR");
         out.disableIndentation();
 
-        if (block.getPredecessorCount() == 0) {
-            // Currently method parameters are not in the schedule, so print them separately here.
-            for (ValueNode param : block.getBeginNode().graph().getNodes(LocalNode.class)) {
-                printNode(param, false);
-            }
-        }
         if (block.getBeginNode() instanceof MergeNode) {
             // Currently phi functions are not in the schedule, so print them separately here.
             for (ValueNode phi : ((MergeNode) block.getBeginNode()).phis()) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,7 +34,10 @@
 public class DebugEnvironment {
 
     public static void initialize(PrintStream log) {
-        Debug.enable();
+        if (!Debug.isEnabled()) {
+            log.println("WARNING: Scope debugging needs to be enabled with -esa or -D" + Debug.Initialization.INITIALIZER_PROPERTY_NAME + "=true");
+            return;
+        }
         List<DebugDumpHandler> dumpHandlers = new ArrayList<>();
         dumpHandlers.add(new GraphPrinterDumpHandler());
         if (PrintCFG.getValue() || PrintBackendCFG.getValue()) {
--- a/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java	Wed Oct 02 13:26:31 2013 +0200
@@ -35,83 +35,167 @@
  */
 public class PTX extends Architecture {
 
-    public static final RegisterCategory CPU = new RegisterCategory("CPU");
-    public static final RegisterCategory FPU = new RegisterCategory("FPU");
+    public static final RegisterCategory REG    = new RegisterCategory("REG");
+    public static final RegisterCategory SREG   = new RegisterCategory("SREG");
+    public static final RegisterCategory PARAM  = new RegisterCategory("PARAM");
+
 
     // @formatter:off
 
     /*
      * Register State Space
      *
-     * Registers (.reg state space) are fast storage locations. The number of
-     * registers is limited, and will vary from platform to platform. When the
-     * limit is exceeded, register variables will be spilled to memory, causing
-     * changes in performance. For each architecture, there is a recommended
-     * maximum number of registers to use (see the "CUDA Programming Guide" for
-     * details).
+     * Registers (.reg state space) are fast storage locations. The
+     * number of GPU architectural registers is limited, and will vary
+     * from platform to platform. When the limit is exceeded, register
+     * variables will be spilled to memory, causing changes in
+     * performance. For each architecture, there is a recommended
+     * maximum number of registers to use (see the "CUDA Programming
+     * Guide" for details).
+     *
+     * TODD: XXX
+     *
+     * However, PTX supports virtual registers. So, the generated PTX
+     * code does not need to use a specified number of registers. Till
+     * we figure out how to model a virtual register set in Graal, we
+     * will pretend that we can use only 16 registers.
      */
 
-    // General purpose registers
-    public static final Register r0  = new Register(0,  0,  "r0",  CPU);
-    public static final Register r1  = new Register(1,  1,  "r1",  CPU);
-    public static final Register r2  = new Register(2,  2,  "r2",  CPU);
-    public static final Register r3  = new Register(3,  3,  "r3",  CPU);
-    public static final Register r4  = new Register(4,  4,  "r4",  CPU);
-    public static final Register r5  = new Register(5,  5,  "r5",  CPU);
-    public static final Register r6  = new Register(6,  6,  "r6",  CPU);
-    public static final Register r7  = new Register(7,  7,  "r7",  CPU);
+    public static final Register r0  = new Register(0,   0,  "r0",  REG);
+    public static final Register r1  = new Register(1,   1,  "r1",  REG);
+    public static final Register r2  = new Register(2,   2,  "r2",  REG);
+    public static final Register r3  = new Register(3,   3,  "r3",  REG);
+    public static final Register r4  = new Register(4,   4,  "r4",  REG);
+    public static final Register r5  = new Register(5,   5,  "r5",  REG);
+    public static final Register r6  = new Register(6,   6,  "r6",  REG);
+    public static final Register r7  = new Register(7,   7,  "r7",  REG);
 
-    public static final Register r8  = new Register(8,  8,  "r8",  CPU);
-    public static final Register r9  = new Register(9,  9,  "r9",  CPU);
-    public static final Register r10 = new Register(10, 10, "r10", CPU);
-    public static final Register r11 = new Register(11, 11, "r11", CPU);
-    public static final Register r12 = new Register(12, 12, "r12", CPU);
-    public static final Register r13 = new Register(13, 13, "r13", CPU);
-    public static final Register r14 = new Register(14, 14, "r14", CPU);
-    public static final Register r15 = new Register(15, 15, "r15", CPU);
+    public static final Register r8  = new Register(8,   8,  "r8",  REG);
+    public static final Register r9  = new Register(9,   9,  "r9",  REG);
+    public static final Register r10 = new Register(10, 10, "r10", REG);
+    public static final Register r11 = new Register(11, 11, "r11", REG);
+    public static final Register r12 = new Register(12, 12, "r12", REG);
+    public static final Register r13 = new Register(13, 13, "r13", REG);
+    public static final Register r14 = new Register(14, 14, "r14", REG);
+    public static final Register r15 = new Register(15, 15, "r15", REG);
 
     public static final Register[] gprRegisters = {
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
         r8,  r9,  r10, r11, r12, r13, r14, r15
     };
 
-    // Floating point registers
-    public static final Register f0  = new Register(16, 0,  "f0",  FPU);
-    public static final Register f1  = new Register(17, 1,  "f1",  FPU);
-    public static final Register f2  = new Register(18, 2,  "f2",  FPU);
-    public static final Register f3  = new Register(19, 3,  "f3",  FPU);
-    public static final Register f4  = new Register(20, 4,  "f4",  FPU);
-    public static final Register f5  = new Register(21, 5,  "f5",  FPU);
-    public static final Register f6  = new Register(22, 6,  "f6",  FPU);
-    public static final Register f7  = new Register(23, 7,  "f7",  FPU);
+    /* Parameter State Space
+     *
+     * The parameter (.param) state space is used (1) to pass input
+     * arguments from the host to the kernel, (2a) to declare formal
+     * input and return parameters for device functions called from
+     * within kernel execution, and (2b) to declare locally-scoped
+     * byte array variables that serve as function call arguments,
+     * typically for passing large structures by value to a function.
+     *
+     * TODO: XXX
+     * The parameters are virtual symbols - just like registers. Bit,
+     * Till we figure out how to model a virtual register set in Graal,
+     * we will pretend that we can use only 8 parameters.
+    */
+
+    public static final Register param0  = new Register(16, 16,  "param0",  PARAM);
+    public static final Register param1  = new Register(17, 17,  "param1",  PARAM);
+    public static final Register param2  = new Register(18, 18,  "param2",  PARAM);
+    public static final Register param3  = new Register(19, 19,  "param3",  PARAM);
+    public static final Register param4  = new Register(20, 20,  "param4",  PARAM);
+    public static final Register param5  = new Register(21, 21,  "param5",  PARAM);
+    public static final Register param6  = new Register(22, 22,  "param6",  PARAM);
+    public static final Register param7  = new Register(23, 23,  "param7",  PARAM);
+
+    public static final Register[] paramRegisters = {
+        param0,  param1,  param2,  param3,  param4,  param5,  param6,  param7
+    };
+
+    // Define a virtual register that holds return value
+    public static final Register retReg = new Register(24, 24, "retReg", REG);
+
+    // PTX ISA Manual: Section 9:. Special Registers
 
-    public static final Register f8  = new Register(24, 8,  "f8",  FPU);
-    public static final Register f9  = new Register(25, 9,  "f9",  FPU);
-    public static final Register f10 = new Register(26, 10, "f10", FPU);
-    public static final Register f11 = new Register(27, 11, "f11", FPU);
-    public static final Register f12 = new Register(28, 12, "f12", FPU);
-    public static final Register f13 = new Register(29, 13, "f13", FPU);
-    public static final Register f14 = new Register(30, 14, "f14", FPU);
-    public static final Register f15 = new Register(31, 15, "f15", FPU);
+    // PTX includes a number of predefined, read-only variables, which
+    // are visible as special registers and accessed through mov or
+    // cvt instructions.
+    // Thread identifier within a Co-operative Thread Array (CTA) - %tid
+    public static final Register tid  = new Register(100,  100,  "tid", SREG);
+    // Number of thread IDs per CTA - %ntid
+    public static final Register ntid    = new Register(101, 101, "ntid", SREG);
+    // Lane identifier
+    public static final Register laneid  = new Register(102, 102, "laneid", SREG);
+    // Warp identifier
+    public static final Register warpid   = new Register(103, 103, "warid", SREG);
+    // Number of warp IDs
+    public static final Register nwarpid   = new Register(104, 104, "nwarpid", SREG);
+    // CTA identifier
+    public static final Register ctaid   = new Register(105, 105, "ctaid", SREG);
+    // Number of CTA IDs per grid
+    public static final Register nctaid   = new Register(106, 106, "nctaid", SREG);
+    // Single Multiprocessor (SM) ID
+    public static final Register smid    = new Register(107, 107, "smid", SREG);
+    // Number of SM IDs
+    public static final Register nsmid   = new Register(108, 108, "nsmid", SREG);
+    // Grid ID
+    public static final Register gridid  = new Register(109, 109, "gridid", SREG);
+    // 32-bit mask with bit set in position equal to thread's lane number in the warp
+    public static final Register lanemask_eq  = new Register(110, 110, "lanemask_eq", SREG);
+    // 32-bit mask with bits set in positions less than or equal to thread's lane number in the warp
+    public static final Register lanemask_le  = new Register(111, 111, "lanemask_le", SREG);
+    // 32-bit mask with bits set in positions less than thread's lane number in the warp
+    public static final Register lanemask_lt  = new Register(112, 112, "lanemask_lt", SREG);
+    // 32-bit mask with bits set in positions greater than or equal to thread's lane number in the warp
+    public static final Register lanemask_ge  = new Register(113, 113, "lanemask_ge", SREG);
+    // 32-bit mask with bits set in positions greater than thread's lane number in the warp
+    public static final Register lanemask_gt  = new Register(114, 114, "lanemask_gt", SREG);
+    // A predefined, read-only 32-bit unsigned 32-bit unsigned cycle counter
+    public static final Register clock  = new Register(114, 114, "clock", SREG);
+    // A predefined, read-only 64-bit unsigned 32-bit unsigned cycle counter
+    public static final Register clock64  = new Register(115, 115, "clock64", SREG);
+    // Performance monitoring registers
+    public static final Register pm0  = new Register(116, 116,  "pm0", SREG);
+    public static final Register pm1  = new Register(117, 117,  "pm1", SREG);
+    public static final Register pm2  = new Register(118, 118,  "pm2", SREG);
+    public static final Register pm3  = new Register(119, 119,  "pm3", SREG);
+    public static final Register pm4  = new Register(120, 120,  "pm4", SREG);
+    public static final Register pm5  = new Register(121, 121,  "pm5", SREG);
+    public static final Register pm6  = new Register(122, 122,  "pm6", SREG);
+    public static final Register pm7  = new Register(123, 123,  "pm7", SREG);
+    // TODO: Add Driver-defined read-only %envreg<32>
+    //       and %globaltimer, %globaltimer_lo and %globaltimer_hi
 
-    public static final Register[] fpuRegisters = {
-        f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
-        f8,  f9,  f10, f11, f12, f13, f14, f15
+    public static final Register[] specialRegisters = {
+        tid, ntid, laneid, warpid, nwarpid, ctaid,
+        nctaid, smid, nsmid, gridid,
+        lanemask_eq, lanemask_le, lanemask_lt, lanemask_ge, lanemask_gt,
+        clock, clock64,
+        pm0, pm1, pm2, pm3, pm4, pm5, pm6, pm7
     };
 
     public static final Register[] allRegisters = {
-        // GPR
+        // Parameter State Space
+        param0, param1, param2, param3,
+        param4, param5, param6, param7,
+        // Register State Space
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
         r8,  r9,  r10, r11, r12, r13, r14, r15,
-        // FPU
-        f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
-        f8,  f9,  f10, f11, f12, f13, f14, f15
+        // return register
+        retReg,
+        // Special Register State Space - SREG
+        tid, ntid, laneid, warpid, nwarpid, ctaid,
+        nctaid, smid, nsmid, gridid,
+        lanemask_eq, lanemask_le, lanemask_lt, lanemask_ge, lanemask_gt,
+        clock, clock64,
+        pm0, pm1, pm2, pm3, pm4, pm5, pm6, pm7
     };
 
     // @formatter:on
 
     public PTX() {
-        super("PTX", 8, ByteOrder.LITTLE_ENDIAN, false, allRegisters, LOAD_STORE | STORE_STORE, 0, r15.encoding + 1, 8);
+        super("PTX", 8, ByteOrder.LITTLE_ENDIAN, false, allRegisters,
+              LOAD_STORE | STORE_STORE, 0, r15.encoding + 1, 8);
     }
 
     @Override
@@ -121,7 +205,7 @@
         }
 
         Kind kind = (Kind) platformKind;
-        if (category == CPU) {
+        if (category == REG) {
             switch (kind) {
                 case Boolean:
                 case Byte:
@@ -130,10 +214,6 @@
                 case Int:
                 case Long:
                 case Object:
-                    return true;
-            }
-        } else if (category == FPU) {
-            switch (kind) {
                 case Float:
                 case Double:
                     return true;
@@ -145,12 +225,12 @@
 
     @Override
     public PlatformKind getLargestStorableKind(RegisterCategory category) {
-        if (category == CPU) {
-            return Kind.Long;
-        } else if (category == FPU) {
+        if (category == REG) {
             return Kind.Double;
         } else {
             return Kind.Illegal;
         }
     }
+
+
 }
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,17 +22,17 @@
  */
 package com.oracle.graal.replacements.amd64;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.calc.ConvertNode.Op;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * This node has the semantics of the AMD64 conversions. It is used in the lowering of the
- * ConvertNode which, on AMD64 needs a AMD64ConvertNode plus some fixup code that handles the corner
- * cases that differ between AMD64 and Java.
- * 
+ * {@link ConvertNode} which, on AMD64 needs a {@link AMD64ConvertNode} plus some fixup code that
+ * handles the corner cases that differ between AMD64 and Java.
  */
 public class AMD64ConvertNode extends FloatingNode implements ArithmeticLIRLowerable {
 
@@ -45,6 +45,12 @@
         this.value = value;
     }
 
+    public Constant evalConst(Constant... inputs) {
+        // this node should never have been created if its input is constant
+        assert false;
+        return null;
+    }
+
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitConvert(opcode, gen.operand(value)));
     }
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Wed Oct 02 13:26:31 2013 +0200
@@ -172,15 +172,16 @@
             // Convert node are replaced by the placeholder which in turn is replaced by the
             // snippet.
 
-            LocalNode replacee = graph.add(new LocalNode(Integer.MAX_VALUE, convert.stamp()));
+            LocalNode replacee = graph.addWithoutUnique(new LocalNode(Integer.MAX_VALUE, convert.stamp()));
             convert.replaceAtUsages(replacee);
-            Arguments args = new Arguments(key);
+            Arguments args = new Arguments(key, graph.getGuardsStage());
             args.add("input", convert.value());
             args.add("result", convert.graph().unique(new AMD64ConvertNode(convert.opcode, convert.value())));
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.opcode, graph, convert, template, args);
             template.instantiate(runtime, replacee, DEFAULT_REPLACER, tool, args);
+            graph.removeFloating(convert);
         }
     }
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,7 +34,7 @@
 
     @Override
     protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) {
-        CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first();
+        CheckCastNode ccn = graph.getNodes().filter(CheckCastNode.class).first();
         if (ccn != null) {
             CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile, false));
             graph.replaceFixedWithFixed(ccn, ccnNew);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -49,7 +49,7 @@
     protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) {
         InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first();
         if (ion != null) {
-            InstanceOfNode ionNew = graph.add(new InstanceOfNode(ion.type(), ion.object(), profile));
+            InstanceOfNode ionNew = graph.unique(new InstanceOfNode(ion.type(), ion.object(), profile));
             graph.replaceFloating(ion, ionNew);
         }
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -53,7 +53,7 @@
                 Assumptions assumptions = new Assumptions(true);
                 HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, phasePlan, OptimisticOptimizations.ALL);
                 Debug.dump(graph, "Graph");
-                new InliningPhase().apply(graph, context);
+                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
                 Debug.dump(graph, "Graph");
                 new CanonicalizerPhase(true).apply(graph, context);
                 new DeadCodeEliminationPhase().apply(graph);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,390 @@
+/*
+ * 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.replacements.test;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
+import com.oracle.graal.word.*;
+
+/**
+ * Tests for the {@link Pointer} read and write operations.
+ */
+public class ObjectAccessTest extends GraalCompilerTest implements Snippets {
+
+    private static final LocationIdentity ID = new NamedLocationIdentity("ID");
+    private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object};
+    private final TargetDescription target;
+    private final ReplacementsImpl installer;
+
+    public ObjectAccessTest() {
+        target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget();
+        installer = new ReplacementsImpl(runtime, new Assumptions(false), target);
+    }
+
+    private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
+
+    @Override
+    protected StructuredGraph parse(Method m) {
+        ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m);
+        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get());
+    }
+
+    @Test
+    public void testRead1() {
+        for (Kind kind : KINDS) {
+            assertRead(parse("read" + kind.name() + "1"), kind, false, ID);
+        }
+    }
+
+    @Test
+    public void testRead2() {
+        for (Kind kind : KINDS) {
+            assertRead(parse("read" + kind.name() + "2"), kind, true, ID);
+        }
+    }
+
+    @Test
+    public void testRead3() {
+        for (Kind kind : KINDS) {
+            assertRead(parse("read" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+        }
+    }
+
+    @Test
+    public void testWrite1() {
+        for (Kind kind : KINDS) {
+            assertWrite(parse("write" + kind.name() + "1"), kind, false, ID);
+        }
+    }
+
+    @Test
+    public void testWrite2() {
+        for (Kind kind : KINDS) {
+            assertWrite(parse("write" + kind.name() + "2"), kind, true, ID);
+        }
+    }
+
+    @Test
+    public void testWrite3() {
+        for (Kind kind : KINDS) {
+            assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+        }
+    }
+
+    private static void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) {
+        ReadNode read = (ReadNode) graph.start().next();
+        Assert.assertEquals(kind.getStackKind(), read.kind());
+        Assert.assertEquals(graph.getLocal(0), read.object());
+
+        IndexedLocationNode location = (IndexedLocationNode) read.location();
+        Assert.assertEquals(kind, location.getValueKind());
+        Assert.assertEquals(locationIdentity, location.getLocationIdentity());
+        Assert.assertEquals(1, location.getIndexScaling());
+
+        if (indexConvert) {
+            ConvertNode convert = (ConvertNode) location.getIndex();
+            Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
+            Assert.assertEquals(graph.getLocal(1), convert.value());
+        } else {
+            Assert.assertEquals(graph.getLocal(1), location.getIndex());
+        }
+
+        ReturnNode ret = (ReturnNode) read.next();
+        Assert.assertEquals(read, ret.result());
+    }
+
+    private static void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) {
+        WriteNode write = (WriteNode) graph.start().next();
+        Assert.assertEquals(graph.getLocal(2), write.value());
+        Assert.assertEquals(graph.getLocal(0), write.object());
+        Assert.assertEquals(Kind.Void, write.kind());
+        Assert.assertEquals(FrameState.AFTER_BCI, write.stateAfter().bci);
+
+        IndexedLocationNode location = (IndexedLocationNode) write.location();
+        Assert.assertEquals(kind, location.getValueKind());
+        Assert.assertEquals(locationIdentity, location.getLocationIdentity());
+        Assert.assertEquals(1, location.getIndexScaling());
+
+        if (indexConvert) {
+            ConvertNode convert = (ConvertNode) location.getIndex();
+            Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
+            Assert.assertEquals(graph.getLocal(1), convert.value());
+        } else {
+            Assert.assertEquals(graph.getLocal(1), location.getIndex());
+        }
+
+        ReturnNode ret = (ReturnNode) write.next();
+        Assert.assertEquals(null, ret.result());
+    }
+
+    @Snippet
+    public static byte readByte1(Object o, int offset) {
+        return ObjectAccess.readByte(o, offset, ID);
+    }
+
+    @Snippet
+    public static byte readByte2(Object o, int offset) {
+        return ObjectAccess.readByte(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static byte readByte3(Object o, int offset) {
+        return ObjectAccess.readByte(o, offset);
+    }
+
+    @Snippet
+    public static void writeByte1(Object o, int offset, byte value) {
+        ObjectAccess.writeByte(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeByte2(Object o, int offset, byte value) {
+        ObjectAccess.writeByte(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeByte3(Object o, int offset, byte value) {
+        ObjectAccess.writeByte(o, offset, value);
+    }
+
+    @Snippet
+    public static char readChar1(Object o, int offset) {
+        return ObjectAccess.readChar(o, offset, ID);
+    }
+
+    @Snippet
+    public static char readChar2(Object o, int offset) {
+        return ObjectAccess.readChar(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static char readChar3(Object o, int offset) {
+        return ObjectAccess.readChar(o, offset);
+    }
+
+    @Snippet
+    public static void writeChar1(Object o, int offset, char value) {
+        ObjectAccess.writeChar(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeChar2(Object o, int offset, char value) {
+        ObjectAccess.writeChar(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeChar3(Object o, int offset, char value) {
+        ObjectAccess.writeChar(o, offset, value);
+    }
+
+    @Snippet
+    public static short readShort1(Object o, int offset) {
+        return ObjectAccess.readShort(o, offset, ID);
+    }
+
+    @Snippet
+    public static short readShort2(Object o, int offset) {
+        return ObjectAccess.readShort(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static short readShort3(Object o, int offset) {
+        return ObjectAccess.readShort(o, offset);
+    }
+
+    @Snippet
+    public static void writeShort1(Object o, int offset, short value) {
+        ObjectAccess.writeShort(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeShort2(Object o, int offset, short value) {
+        ObjectAccess.writeShort(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeShort3(Object o, int offset, short value) {
+        ObjectAccess.writeShort(o, offset, value);
+    }
+
+    @Snippet
+    public static int readInt1(Object o, int offset) {
+        return ObjectAccess.readInt(o, offset, ID);
+    }
+
+    @Snippet
+    public static int readInt2(Object o, int offset) {
+        return ObjectAccess.readInt(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static int readInt3(Object o, int offset) {
+        return ObjectAccess.readInt(o, offset);
+    }
+
+    @Snippet
+    public static void writeInt1(Object o, int offset, int value) {
+        ObjectAccess.writeInt(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeInt2(Object o, int offset, int value) {
+        ObjectAccess.writeInt(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeInt3(Object o, int offset, int value) {
+        ObjectAccess.writeInt(o, offset, value);
+    }
+
+    @Snippet
+    public static long readLong1(Object o, int offset) {
+        return ObjectAccess.readLong(o, offset, ID);
+    }
+
+    @Snippet
+    public static long readLong2(Object o, int offset) {
+        return ObjectAccess.readLong(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static long readLong3(Object o, int offset) {
+        return ObjectAccess.readLong(o, offset);
+    }
+
+    @Snippet
+    public static void writeLong1(Object o, int offset, long value) {
+        ObjectAccess.writeLong(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeLong2(Object o, int offset, long value) {
+        ObjectAccess.writeLong(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeLong3(Object o, int offset, long value) {
+        ObjectAccess.writeLong(o, offset, value);
+    }
+
+    @Snippet
+    public static float readFloat1(Object o, int offset) {
+        return ObjectAccess.readFloat(o, offset, ID);
+    }
+
+    @Snippet
+    public static float readFloat2(Object o, int offset) {
+        return ObjectAccess.readFloat(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static float readFloat3(Object o, int offset) {
+        return ObjectAccess.readFloat(o, offset);
+    }
+
+    @Snippet
+    public static void writeFloat1(Object o, int offset, float value) {
+        ObjectAccess.writeFloat(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeFloat2(Object o, int offset, float value) {
+        ObjectAccess.writeFloat(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeFloat3(Object o, int offset, float value) {
+        ObjectAccess.writeFloat(o, offset, value);
+    }
+
+    @Snippet
+    public static double readDouble1(Object o, int offset) {
+        return ObjectAccess.readDouble(o, offset, ID);
+    }
+
+    @Snippet
+    public static double readDouble2(Object o, int offset) {
+        return ObjectAccess.readDouble(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static double readDouble3(Object o, int offset) {
+        return ObjectAccess.readDouble(o, offset);
+    }
+
+    @Snippet
+    public static void writeDouble1(Object o, int offset, double value) {
+        ObjectAccess.writeDouble(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeDouble2(Object o, int offset, double value) {
+        ObjectAccess.writeDouble(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeDouble3(Object o, int offset, double value) {
+        ObjectAccess.writeDouble(o, offset, value);
+    }
+
+    @Snippet
+    public static Object readObject1(Object o, int offset) {
+        return ObjectAccess.readObject(o, offset, ID);
+    }
+
+    @Snippet
+    public static Object readObject2(Object o, int offset) {
+        return ObjectAccess.readObject(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static Object readObject3(Object o, int offset) {
+        return ObjectAccess.readObject(o, offset);
+    }
+
+    @Snippet
+    public static void writeObject1(Object o, int offset, Object value) {
+        ObjectAccess.writeObject(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeObject2(Object o, int offset, Object value) {
+        ObjectAccess.writeObject(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeObject3(Object o, int offset, Object value) {
+        ObjectAccess.writeObject(o, offset, value);
+    }
+}
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -33,9 +33,13 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.Snippet.*;
+import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
 import com.oracle.graal.word.*;
+import com.oracle.graal.word.nodes.*;
 
 /**
  * Tests for the {@link Pointer} read and write operations.
@@ -103,11 +107,13 @@
     }
 
     private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) {
-        ReadNode read = (ReadNode) graph.start().next();
+        WordCastNode cast = (WordCastNode) graph.start().next();
+
+        ReadNode read = (ReadNode) cast.next();
         Assert.assertEquals(kind.getStackKind(), read.kind());
 
-        UnsafeCastNode cast = (UnsafeCastNode) read.object();
-        Assert.assertEquals(graph.getLocal(0), cast.object());
+        Assert.assertEquals(cast, read.object());
+        Assert.assertEquals(graph.getLocal(0), cast.getInput());
         Assert.assertEquals(target.wordKind, cast.kind());
 
         IndexedLocationNode location = (IndexedLocationNode) read.location();
@@ -128,13 +134,15 @@
     }
 
     private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) {
-        WriteNode write = (WriteNode) graph.start().next();
+        WordCastNode cast = (WordCastNode) graph.start().next();
+
+        WriteNode write = (WriteNode) cast.next();
         Assert.assertEquals(graph.getLocal(2), write.value());
         Assert.assertEquals(Kind.Void, write.kind());
-        Assert.assertEquals(FrameState.INVALID_FRAMESTATE_BCI, write.stateAfter().bci);
+        Assert.assertEquals(FrameState.AFTER_BCI, write.stateAfter().bci);
 
-        UnsafeCastNode cast = (UnsafeCastNode) write.object();
-        Assert.assertEquals(graph.getLocal(0), cast.object());
+        Assert.assertEquals(cast, write.object());
+        Assert.assertEquals(graph.getLocal(0), cast.getInput());
         Assert.assertEquals(target.wordKind, cast.kind());
 
         IndexedLocationNode location = (IndexedLocationNode) write.location();
@@ -150,10 +158,7 @@
             Assert.assertEquals(graph.getLocal(1), location.getIndex());
         }
 
-        AbstractStateSplit stateSplit = (AbstractStateSplit) write.next();
-        Assert.assertEquals(FrameState.AFTER_BCI, stateSplit.stateAfter().bci);
-
-        ReturnNode ret = (ReturnNode) stateSplit.next();
+        ReturnNode ret = (ReturnNode) write.next();
         Assert.assertEquals(null, ret.result());
     }
 
@@ -397,4 +402,62 @@
         Word.fromObject(o).writeObject(offset, value);
     }
 
+    private void assertNumWordCasts(String snippetName, int expectedWordCasts) {
+        Assumptions assumptions = new Assumptions(true);
+        HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, null, OptimisticOptimizations.ALL);
+
+        StructuredGraph graph = parse(snippetName);
+        new CanonicalizerPhase(false).apply(graph, context);
+        Assert.assertEquals(expectedWordCasts, graph.getNodes().filter(WordCastNode.class).count());
+    }
+
+    @Test
+    public void testUnusedFromObject() {
+        assertNumWordCasts("unusedFromObject", 0);
+    }
+
+    @Snippet
+    public static void unusedFromObject(Object o) {
+        Word.fromObject(o);
+    }
+
+    @Test
+    public void testUnusedRawValue() {
+        assertNumWordCasts("unusedRawValue", 0);
+    }
+
+    @Snippet
+    public static void unusedRawValue(Object o) {
+        Word.fromObject(o).rawValue();
+    }
+
+    @Test
+    public void testUsedRawValue() {
+        assertNumWordCasts("usedRawValue", 1);
+    }
+
+    @Snippet
+    public static long usedRawValue(Object o) {
+        return Word.fromObject(o).rawValue();
+    }
+
+    @Test
+    public void testUnusedToObject() {
+        assertNumWordCasts("unusedToObject", 0);
+    }
+
+    @Snippet
+    public static void unusedToObject(Word w) {
+        w.toObject();
+    }
+
+    @Test
+    public void testUsedToObject() {
+        assertNumWordCasts("usedToObject", 1);
+    }
+
+    @Snippet
+    public static Object usedToObject(Word w) {
+        return w.toObject();
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Wed Oct 02 13:26:31 2013 +0200
@@ -79,49 +79,49 @@
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Boolean booleanValueOf(boolean value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Byte byteValueOf(byte value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Character charValueOf(char value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Character.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Character.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Double doubleValueOf(double value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Double.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Double.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Float floatValueOf(float value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Float.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Float.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Integer intValueOf(int value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Long longValueOf(long value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Long.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Long.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Short shortValueOf(short value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Short.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Short.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
@@ -220,7 +220,7 @@
             if (canonical != null && !AOTCompilation.getValue()) {
                 box.graph().replaceFloating(box, canonical);
             } else {
-                Arguments args = new Arguments(boxSnippets.get(box.getBoxingKind()));
+                Arguments args = new Arguments(boxSnippets.get(box.getBoxingKind()), box.graph().getGuardsStage());
                 args.add("value", box.getValue());
 
                 SnippetTemplate template = template(args);
@@ -231,7 +231,7 @@
         }
 
         public void lower(UnboxNode unbox, LoweringTool tool) {
-            Arguments args = new Arguments(unboxSnippets.get(unbox.getBoxingKind()));
+            Arguments args = new Arguments(unboxSnippets.get(unbox.getBoxingKind()), unbox.graph().getGuardsStage());
             args.add("value", unbox.getValue());
 
             SnippetTemplate template = template(args);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Wed Oct 02 13:26:31 2013 +0200
@@ -93,7 +93,7 @@
      */
     protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, Instantiation instantiation, Node usage, final StructuredGraph graph) {
         InstanceOfUsageReplacer replacer;
-        if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitBooleanNode || usage instanceof GuardingPiNode) {
+        if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitOrNode || usage instanceof GuardingPiNode) {
             replacer = new NonMaterializationUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, usage);
         } else {
             assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage;
@@ -206,7 +206,7 @@
         }
 
         @Override
-        public void replace(ValueNode oldNode, ValueNode newNode) {
+        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMapNode mmap) {
             assert newNode instanceof PhiNode;
             assert oldNode == instanceOf;
             newNode.inferStamp();
@@ -238,7 +238,7 @@
         }
 
         @Override
-        public void replace(ValueNode oldNode, ValueNode newNode) {
+        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMapNode mmap) {
             assert newNode instanceof PhiNode;
             assert oldNode == instanceOf;
             newNode.inferStamp();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,8 +36,8 @@
  * Substitutions for improving the performance of some critical methods in {@link NodeClass}
  * methods. These substitutions improve the performance by forcing the relevant methods to be
  * inlined (intrinsification being a special form of inlining) and removing a checked cast. The
- * latter cannot be done directly in Java code as {@link UnsafeCastNode} is not available to the
- * project containing {@link NodeClass}.
+ * latter cannot be done directly in Java code as {@link PiNode} is not available to the project
+ * containing {@link NodeClass}.
  */
 @ClassSubstitution(NodeClass.class)
 public class NodeClassSubstitutions {
@@ -64,12 +64,12 @@
 
     @MethodSubstitution
     private static Node getNode(Node node, long offset) {
-        return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), Node.class, false, false);
+        return PiNode.piCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), Node.class, false, false);
     }
 
     @MethodSubstitution
     private static NodeList getNodeList(Node node, long offset) {
-        return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), NodeList.class, false, false);
+        return PiNode.piCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), NodeList.class, false, false);
     }
 
     @MethodSubstitution
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -67,7 +67,7 @@
         }
     }
 
-    private boolean tryIntrinsify(MethodCallTargetNode methodCallTargetNode, List<Node> cleanUpReturnList) {
+    protected boolean tryIntrinsify(MethodCallTargetNode methodCallTargetNode, List<Node> cleanUpReturnList) {
         ResolvedJavaMethod target = methodCallTargetNode.targetMethod();
         NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class);
         ResolvedJavaType declaringClass = target.getDeclaringClass();
@@ -76,7 +76,6 @@
             assert Modifier.isStatic(target.getModifiers()) : "node intrinsic must be static: " + target;
 
             ResolvedJavaType[] parameterTypes = MetaUtil.resolveJavaTypes(MetaUtil.signatureToTypes(target), declaringClass);
-            ResolvedJavaType returnType = target.getSignature().getReturnType(declaringClass).resolve(declaringClass);
 
             // Prepare the arguments for the reflective constructor call on the node class.
             Constant[] nodeConstructorArguments = prepareArguments(methodCallTargetNode, parameterTypes, target, false);
@@ -86,15 +85,15 @@
 
             // Create the new node instance.
             ResolvedJavaType c = getNodeClass(target, intrinsic);
-            Node newInstance = createNodeInstance(c, parameterTypes, returnType, intrinsic.setStampFromReturnType(), nodeConstructorArguments);
+            Node newInstance = createNodeInstance(c, parameterTypes, methodCallTargetNode.invoke().asNode().stamp(), intrinsic.setStampFromReturnType(), nodeConstructorArguments);
 
             // Replace the invoke with the new node.
-            methodCallTargetNode.graph().add(newInstance);
+            newInstance = methodCallTargetNode.graph().addOrUnique(newInstance);
             methodCallTargetNode.invoke().intrinsify(newInstance);
 
             // Clean up checkcast instructions inserted by javac if the return type is generic.
             cleanUpReturnList.add(newInstance);
-        } else if (target.getAnnotation(Fold.class) != null) {
+        } else if (isFoldable(target)) {
             ResolvedJavaType[] parameterTypes = MetaUtil.resolveJavaTypes(MetaUtil.signatureToTypes(target), declaringClass);
 
             // Prepare the arguments for the reflective method call
@@ -128,6 +127,13 @@
     }
 
     /**
+     * Permits a subclass to override the default definition of "foldable".
+     */
+    protected boolean isFoldable(ResolvedJavaMethod method) {
+        return method.getAnnotation(Fold.class) != null;
+    }
+
+    /**
      * Converts the arguments of an invoke node to object values suitable for use as the arguments
      * to a reflective invocation of a Java constructor or method.
      * 
@@ -187,7 +193,7 @@
         return result;
     }
 
-    private Node createNodeInstance(ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, ResolvedJavaType returnType, boolean setStampFromReturnType, Constant[] nodeConstructorArguments) {
+    private Node createNodeInstance(ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, Stamp invokeStamp, boolean setStampFromReturnType, Constant[] nodeConstructorArguments) {
         ResolvedJavaMethod constructor = null;
         Constant[] arguments = null;
 
@@ -211,11 +217,7 @@
             ValueNode intrinsicNode = (ValueNode) constructor.newInstance(arguments).asObject();
 
             if (setStampFromReturnType) {
-                if (returnType.getKind() == Kind.Object) {
-                    intrinsicNode.setStamp(StampFactory.declared(returnType));
-                } else {
-                    intrinsicNode.setStamp(StampFactory.forKind(returnType.getKind()));
-                }
+                intrinsicNode.setStamp(invokeStamp);
             }
             return intrinsicNode;
         } catch (Exception e) {
@@ -300,7 +302,7 @@
     private static void checkCheckCastUsage(StructuredGraph graph, Node intrinsifiedNode, Node input, Node usage) {
         if (usage instanceof ValueAnchorNode) {
             ValueAnchorNode valueAnchorNode = (ValueAnchorNode) usage;
-            valueAnchorNode.removeAnchoredNode((ValueNode) input);
+            valueAnchorNode.removeAnchoredNode();
             Debug.log("%s: Removed a ValueAnchor input", Debug.contextSnapshot(JavaMethod.class));
         } else if (usage instanceof UnboxNode) {
             UnboxNode unbox = (UnboxNode) usage;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Oct 02 13:26:31 2013 +0200
@@ -44,6 +44,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.Snippet.DefaultSnippetInliningPolicy;
 import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
 import com.oracle.graal.word.phases.*;
@@ -291,11 +292,8 @@
 
             if (original == null) {
                 new SnippetFrameStateCleanupPhase().apply(graph);
-                new DeadCodeEliminationPhase().apply(graph);
-                new InsertStateAfterPlaceholderPhase().apply(graph);
-            } else {
-                new DeadCodeEliminationPhase().apply(graph);
             }
+            new DeadCodeEliminationPhase().apply(graph);
         }
 
         private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) {
@@ -324,30 +322,32 @@
 
                 @Override
                 public void run() {
-                    GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault();
-                    GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE);
-                    graphBuilder.apply(graph);
+                    new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
+                    new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph);
+                    new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
 
-                    new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph);
                     if (OptCanonicalizer.getValue()) {
-                        new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
-                        new CanonicalizerPhase.Instance(runtime, assumptions, true).apply(graph);
+                        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime, assumptions, ReplacementsImpl.this));
                     }
                 }
             });
             return graph;
         }
 
+        protected Object beforeInline(@SuppressWarnings("unused") MethodCallTargetNode callTarget, @SuppressWarnings("unused") StructuredGraph callee) {
+            return null;
+        }
+
         /**
          * Called after a graph is inlined.
          * 
          * @param caller the graph into which {@code callee} was inlined
          * @param callee the graph that was inlined into {@code caller}
+         * @param beforeInlineData value returned by {@link #beforeInline}.
          */
-        protected void afterInline(StructuredGraph caller, StructuredGraph callee) {
+        protected void afterInline(StructuredGraph caller, StructuredGraph callee, Object beforeInlineData) {
             if (OptCanonicalizer.getValue()) {
-                new WordTypeRewriterPhase(runtime, target.wordKind).apply(caller);
-                new CanonicalizerPhase.Instance(runtime, assumptions, true).apply(caller);
+                new CanonicalizerPhase(true).apply(caller, new PhaseContext(runtime, assumptions, ReplacementsImpl.this));
             }
         }
 
@@ -356,12 +356,9 @@
          */
         protected void afterInlining(StructuredGraph graph) {
             new NodeIntrinsificationPhase(runtime).apply(graph);
-
-            new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
-
             new DeadCodeEliminationPhase().apply(graph);
             if (OptCanonicalizer.getValue()) {
-                new CanonicalizerPhase.Instance(runtime, assumptions, true).apply(graph);
+                new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime, assumptions, ReplacementsImpl.this));
             }
         }
 
@@ -377,10 +374,13 @@
                         if (callee == method) {
                             final StructuredGraph originalGraph = new StructuredGraph(original);
                             new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph);
+                            new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph);
+                            new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
+
                             InliningUtil.inline(callTarget.invoke(), originalGraph, true);
 
                             Debug.dump(graph, "after inlining %s", callee);
-                            afterInline(graph, originalGraph);
+                            afterInline(graph, originalGraph, null);
                             substituteCallsOriginal = true;
                         } else {
                             StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(ReplacementsImpl.this, callee);
@@ -397,9 +397,10 @@
                                     }
                                     targetGraph = parseGraph(callee, policy);
                                 }
+                                Object beforeInlineData = beforeInline(callTarget, targetGraph);
                                 InliningUtil.inline(callTarget.invoke(), targetGraph, true);
                                 Debug.dump(graph, "after inlining %s", callee);
-                                afterInline(graph, targetGraph);
+                                afterInline(graph, targetGraph, beforeInlineData);
                             }
                         }
                     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -45,24 +45,24 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), false, null);
+        ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), null, null);
     }
 
-    /**
-     * A proper (loop-aware) iteration over the graph is used to detect loops that contain invalid
-     * frame states, so that they can be marked with an invalid frame state.
-     */
-    private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure<Boolean> {
+    private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure<StateSplit> {
 
         @Override
-        protected Boolean processNode(FixedNode node, Boolean currentState) {
+        protected StateSplit processNode(FixedNode node, StateSplit currentState) {
+            StateSplit state = currentState;
             if (node instanceof StateSplit) {
                 StateSplit stateSplit = (StateSplit) node;
                 FrameState frameState = stateSplit.stateAfter();
                 if (frameState != null) {
-                    if (stateSplit.hasSideEffect()) {
-                        stateSplit.setStateAfter(node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI)));
-                        return true;
+                    // the stateSplit == currentState case comes from merge handling
+                    if (stateSplit.hasSideEffect() || stateSplit == currentState) {
+                        stateSplit.setStateAfter(createInvalidFrameState(node));
+                        state = stateSplit;
+                    } else if (hasInvalidState(state)) {
+                        stateSplit.setStateAfter(createInvalidFrameState(node));
                     } else {
                         stateSplit.setStateAfter(null);
                     }
@@ -71,41 +71,57 @@
                     }
                 }
             }
-            return currentState;
+            if (node instanceof ControlSinkNode && state != null) {
+                state.setStateAfter(node.graph().add(new FrameState(FrameState.AFTER_BCI)));
+            }
+            return state;
         }
 
         @Override
-        protected Boolean merge(MergeNode merge, List<Boolean> states) {
-            for (boolean state : states) {
-                if (state) {
-                    return true;
+        protected StateSplit merge(MergeNode merge, List<StateSplit> states) {
+            boolean invalid = false;
+            for (StateSplit state : states) {
+                if (state != null && state.stateAfter() != null && state.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) {
+                    invalid = true;
+                    state.setStateAfter(merge.graph().add(new FrameState(FrameState.AFTER_BCI)));
                 }
             }
-            return false;
+            if (invalid) {
+                // at the next processNode call, stateSplit == currentState == merge
+                return merge;
+            } else {
+                return null;
+            }
         }
 
         @Override
-        protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) {
+        protected StateSplit afterSplit(AbstractBeginNode node, StateSplit oldState) {
             return oldState;
         }
 
         @Override
-        protected Map<LoopExitNode, Boolean> processLoop(LoopBeginNode loop, Boolean initialState) {
-            LoopInfo<Boolean> info = ReentrantNodeIterator.processLoop(this, loop, false);
-            boolean containsFrameState = false;
-            for (Boolean state : info.endStates.values()) {
-                containsFrameState |= state;
-            }
-            if (containsFrameState) {
-                loop.setStateAfter(loop.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI)));
-            }
-            if (containsFrameState || initialState) {
-                for (Map.Entry<?, Boolean> entry : info.exitStates.entrySet()) {
-                    entry.setValue(true);
+        protected Map<LoopExitNode, StateSplit> processLoop(LoopBeginNode loop, StateSplit initialState) {
+            LoopInfo<StateSplit> info = ReentrantNodeIterator.processLoop(this, loop, initialState);
+            if (!hasInvalidState(initialState)) {
+                boolean isNowInvalid = false;
+                for (StateSplit endState : info.endStates.values()) {
+                    isNowInvalid |= hasInvalidState(endState);
+                }
+                if (isNowInvalid) {
+                    loop.setStateAfter(createInvalidFrameState(loop));
+                    info = ReentrantNodeIterator.processLoop(this, loop, loop);
                 }
             }
             return info.exitStates;
         }
 
+        private static boolean hasInvalidState(StateSplit state) {
+            assert state == null || (state.stateAfter() != null && state.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) : state + " " + state.stateAfter();
+            return state != null;
+        }
+
+        private static FrameState createInvalidFrameState(FixedNode node) {
+            return node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI));
+        }
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.replacements;
 
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
@@ -32,8 +34,10 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
@@ -41,11 +45,12 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.FloatingReadPhase.MemoryMapImpl;
+import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
 import com.oracle.graal.replacements.Snippet.VarargsParameter;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
-import com.oracle.graal.word.phases.*;
 
 /**
  * A snippet template is a graph created by parsing a snippet method and then specialized by binding
@@ -58,7 +63,7 @@
     /**
      * Holds the {@link ResolvedJavaMethod} of the snippet, together with some information about the
      * method that needs to be computed only once. The {@link SnippetInfo} should be created once
-     * per snippet an then cached.
+     * per snippet and then cached.
      */
     public static class SnippetInfo {
 
@@ -149,9 +154,9 @@
 
         protected int nextParamIdx;
 
-        public Arguments(SnippetInfo info) {
+        public Arguments(SnippetInfo info, GuardsStage guardsStage) {
             this.info = info;
-            this.cacheKey = new CacheKey(info);
+            this.cacheKey = new CacheKey(info, guardsStage);
             this.values = new Object[info.getParameterCount()];
         }
 
@@ -268,10 +273,12 @@
 
         private final ResolvedJavaMethod method;
         private final Object[] values;
+        private final GuardsStage guardsStage;
         private int hash;
 
-        protected CacheKey(SnippetInfo info) {
+        protected CacheKey(SnippetInfo info, GuardsStage guardsStage) {
             this.method = info.method;
+            this.guardsStage = guardsStage;
             this.values = new Object[info.getParameterCount()];
             this.hash = info.method.hashCode();
         }
@@ -290,6 +297,9 @@
             if (method != other.method) {
                 return false;
             }
+            if (guardsStage != other.guardsStage) {
+                return false;
+            }
             for (int i = 0; i < values.length; i++) {
                 if (values[i] != null && !values[i].equals(other.values[i])) {
                     return false;
@@ -351,7 +361,7 @@
 
                         @Override
                         public SnippetTemplate call() throws Exception {
-                            return new SnippetTemplate(runtime, replacements, target, args);
+                            return new SnippetTemplate(runtime, replacements, args);
                         }
                     });
                     templates.put(args.cacheKey, template);
@@ -382,14 +392,16 @@
     /**
      * Creates a snippet template.
      */
-    protected SnippetTemplate(MetaAccessProvider runtime, Replacements replacements, TargetDescription target, Arguments args) {
+    protected SnippetTemplate(final MetaAccessProvider runtime, final Replacements replacements, Arguments args) {
         StructuredGraph snippetGraph = replacements.getSnippet(args.info.method);
 
         ResolvedJavaMethod method = snippetGraph.method();
         Signature signature = method.getSignature();
 
+        PhaseContext context = new PhaseContext(runtime, replacements.getAssumptions(), replacements);
+
         // Copy snippet graph, replacing constant parameters with given arguments
-        StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method());
+        final StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method());
         IdentityHashMap<Node, Node> nodeReplacements = new IdentityHashMap<>();
         nodeReplacements.put(snippetGraph.start(), snippetCopy.start());
 
@@ -417,15 +429,13 @@
                 placeholders[i] = placeholder;
             }
         }
-        snippetCopy.addDuplicates(snippetGraph.getNodes(), nodeReplacements);
+        snippetCopy.addDuplicates(snippetGraph.getNodes(), snippetGraph, snippetGraph.getNodeCount(), nodeReplacements);
 
         Debug.dump(snippetCopy, "Before specialization");
         if (!nodeReplacements.isEmpty()) {
             // Do deferred intrinsification of node intrinsics
             new NodeIntrinsificationPhase(runtime).apply(snippetCopy);
-            new WordTypeRewriterPhase(runtime, target.wordKind).apply(snippetCopy);
-
-            new CanonicalizerPhase.Instance(runtime, replacements.getAssumptions(), true, 0, null).apply(snippetCopy);
+            new CanonicalizerPhase(true).apply(snippetCopy, context);
         }
         NodeIntrinsificationVerificationPhase.verify(snippetCopy);
 
@@ -481,8 +491,8 @@
                 if (loopBegin != null) {
                     LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin);
                     int mark = snippetCopy.getMark();
-                    LoopTransformations.fullUnroll(loop, runtime, replacements.getAssumptions(), true);
-                    new CanonicalizerPhase.Instance(runtime, replacements.getAssumptions(), true, mark, null).apply(snippetCopy);
+                    LoopTransformations.fullUnroll(loop, context, new CanonicalizerPhase(true));
+                    new CanonicalizerPhase(true).applyIncremental(snippetCopy, context, mark);
                 }
                 FixedNode explodeLoopNext = explodeLoop.next();
                 explodeLoop.clearSuccessors();
@@ -493,7 +503,17 @@
             }
         } while (exploded);
 
-        // Remove all frame states from inlined snippet graph. Snippets must be atomic (i.e. free
+        // Perform lowering on the snippet
+        snippetCopy.setGuardsStage(args.cacheKey.guardsStage);
+        Debug.scope("LoweringSnippetTemplate", snippetCopy, new Runnable() {
+
+            public void run() {
+                PhaseContext c = new PhaseContext(runtime, new Assumptions(false), replacements);
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(snippetCopy, c);
+            }
+        });
+
+        // Remove all frame states from snippet graph. Snippets must be atomic (i.e. free
         // of side-effects that prevent deoptimizing to a point before the snippet).
         ArrayList<StateSplit> curSideEffectNodes = new ArrayList<>();
         ArrayList<DeoptimizingNode> curDeoptNodes = new ArrayList<>();
@@ -524,11 +544,15 @@
 
         assert checkAllVarargPlaceholdersAreDeleted(parameterCount, placeholders);
 
+        new FloatingReadPhase(FloatingReadPhase.ExecutionMode.ANALYSIS_ONLY).apply(snippetCopy);
+        this.memoryMap = null;
+
         this.snippet = snippetCopy;
         ReturnNode retNode = null;
         StartNode entryPointNode = snippet.start();
-
         nodes = new ArrayList<>(snippet.getNodeCount());
+        boolean seenReturn = false;
+        boolean containsMemoryMap = false;
         for (Node node : snippet.getNodes()) {
             if (node == entryPointNode || node == entryPointNode.stateAfter()) {
                 // Do nothing.
@@ -536,9 +560,20 @@
                 nodes.add(node);
                 if (node instanceof ReturnNode) {
                     retNode = (ReturnNode) node;
+                    NodeIterable<MemoryMapNode> memstates = retNode.inputs().filter(MemoryMapNode.class);
+                    assert memstates.count() == 1;
+                    memoryMap = memstates.first();
+                    retNode.replaceFirstInput(memoryMap, null);
+                    memoryMap.safeDelete();
+
+                    assert !seenReturn : "can handle only one ReturnNode";
+                    seenReturn = true;
+                } else if (node instanceof MemoryMapNode) {
+                    containsMemoryMap = true;
                 }
             }
         }
+        assert !containsMemoryMap;
 
         this.sideEffectNodes = curSideEffectNodes;
         this.deoptNodes = curDeoptNodes;
@@ -622,6 +657,11 @@
     private final ArrayList<Node> nodes;
 
     /**
+     * map of killing locations to memory checkpoints (nodes).
+     */
+    private MemoryMapNode memoryMap;
+
+    /**
      * Gets the instantiation-time bindings to this template's parameters.
      * 
      * @return the map that will be used to bind arguments to parameters when inlining this template
@@ -713,7 +753,7 @@
         /**
          * Replaces all usages of {@code oldNode} with direct or indirect usages of {@code newNode}.
          */
-        void replace(ValueNode oldNode, ValueNode newNode);
+        void replace(ValueNode oldNode, ValueNode newNode, MemoryMapNode mmap);
     }
 
     /**
@@ -723,11 +763,96 @@
     public static final UsageReplacer DEFAULT_REPLACER = new UsageReplacer() {
 
         @Override
-        public void replace(ValueNode oldNode, ValueNode newNode) {
+        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMapNode mmap) {
             oldNode.replaceAtUsages(newNode);
+            if (mmap == null || newNode == null) {
+                return;
+            }
+            for (Node usage : newNode.usages().snapshot()) {
+                if (usage instanceof FloatingReadNode && ((FloatingReadNode) usage).lastLocationAccess() == newNode) {
+                    assert newNode.graph().isAfterFloatingReadPhase();
+
+                    // lastLocationAccess points into the snippet graph. find a proper
+                    // MemoryCheckPoint inside the snippet graph
+                    FloatingReadNode read = (FloatingReadNode) usage;
+                    Node lastAccess = mmap.getLastLocationAccess(read.location().getLocationIdentity());
+
+                    assert lastAccess != null : "no mapping found for lowerable node " + oldNode + ". (No node in the snippet kill the same location as the lowerable node?)";
+                    read.setLastLocationAccess(lastAccess);
+                }
+            }
         }
     };
 
+    private boolean checkSnippetKills(ScheduledNode replacee) {
+        if (!replacee.graph().isAfterFloatingReadPhase()) {
+            // 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
+            return true;
+        }
+
+        Set<LocationIdentity> kills = new HashSet<>(((MemoryMapImpl) memoryMap).getLocations());
+
+        if (replacee instanceof MemoryCheckpoint.Single) {
+            // check if some node in snippet graph also kills the same location
+            LocationIdentity locationIdentity = ((MemoryCheckpoint.Single) replacee).getLocationIdentity();
+            if (locationIdentity == ANY_LOCATION) {
+                assert !(memoryMap.getLastLocationAccess(ANY_LOCATION) instanceof StartNode);
+            }
+            assert kills.contains(locationIdentity) : replacee + " kills " + locationIdentity + ", but snippet doesn't contain a kill to this location";
+            return true;
+        }
+        assert !(replacee instanceof MemoryCheckpoint.Multi) : replacee + " multi not supported (yet)";
+
+        Debug.log("WARNING: %s is not a MemoryCheckpoint, but the snippet graph contains kills (%s). You might want %s to be a MemoryCheckpoint", replacee, kills, replacee);
+
+        // remove ANY_LOCATION if it's just a kill by the start node
+        if (memoryMap.getLastLocationAccess(ANY_LOCATION) instanceof StartNode) {
+            kills.remove(ANY_LOCATION);
+        }
+
+        // node can only lower to a ANY_LOCATION kill if the replacee also kills ANY_LOCATION
+        assert !kills.contains(ANY_LOCATION) : "snippet graph contains a kill to ANY_LOCATION, but replacee (" + replacee + ") doesn't kill ANY_LOCATION.  kills: " + kills;
+
+        /*
+         * kills to other locations than ANY_LOCATION can be still inserted if there aren't any
+         * floating reads accessing this locations. Example: In HotSpot, InstanceOfNode is lowered
+         * to a snippet containing a write to SECONDARY_SUPER_CACHE_LOCATION. This is runtime
+         * specific, so the runtime independent InstanceOfNode can not kill this location. However,
+         * if no FloatingReadNode is reading from this location, the kill to this location is fine.
+         */
+        for (FloatingReadNode frn : replacee.graph().getNodes(FloatingReadNode.class)) {
+            assert !(kills.contains(frn.location().getLocationIdentity())) : frn + " reads from " + frn.location().getLocationIdentity() + " but " + replacee + " does not kill this location";
+        }
+        return true;
+    }
+
+    private class DuplicateMapper extends MemoryMapNode {
+
+        Map<Node, Node> duplicates;
+        StartNode replaceeStart;
+
+        public DuplicateMapper(Map<Node, Node> duplicates, StartNode replaceeStart) {
+            this.duplicates = duplicates;
+            this.replaceeStart = replaceeStart;
+        }
+
+        @Override
+        public Node getLastLocationAccess(LocationIdentity locationIdentity) {
+            assert memoryMap != null : "no memory map stored for this snippet graph (snippet doesn't have a ReturnNode?)";
+            Node lastLocationAccess = memoryMap.getLastLocationAccess(locationIdentity);
+            assert lastLocationAccess != null;
+            if (lastLocationAccess instanceof StartNode) {
+                return replaceeStart;
+            } else {
+                return duplicates.get(lastLocationAccess);
+            }
+        }
+    }
+
     /**
      * Replaces a given fixed node with this specialized snippet.
      * 
@@ -738,17 +863,17 @@
      * @return the map of duplicated nodes (original -> duplicate)
      */
     public Map<Node, Node> instantiate(MetaAccessProvider runtime, FixedNode replacee, UsageReplacer replacer, Arguments args) {
+        assert checkSnippetKills(replacee);
         try (TimerCloseable a = instantiationTimer.start()) {
             instantiationCounter.increment();
             // Inline the snippet nodes, replacing parameters with the given args in the process
-            String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}";
-            StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method());
             StartNode entryPointNode = snippet.start();
             FixedNode firstCFGNode = entryPointNode.next();
             StructuredGraph replaceeGraph = replacee.graph();
             IdentityHashMap<Node, Node> replacements = bind(replaceeGraph, runtime, args);
-            Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, replacements);
-            Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method());
+            replacements.put(entryPointNode, replaceeGraph.start());
+            Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements);
+            Debug.dump(replaceeGraph, "After inlining snippet %s", snippet.method());
 
             // Re-wire the control flow graph around the replacee
             FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
@@ -788,16 +913,16 @@
             if (returnNode != null) {
                 if (returnNode.result() instanceof LocalNode) {
                     returnValue = (ValueNode) replacements.get(returnNode.result());
-                } else {
+                } else if (returnNode.result() != null) {
                     returnValue = (ValueNode) duplicates.get(returnNode.result());
                 }
                 Node returnDuplicate = duplicates.get(returnNode);
+                MemoryMapNode mmap = new DuplicateMapper(duplicates, replaceeGraph.start());
                 if (returnValue == null && replacee.usages().isNotEmpty() && replacee instanceof MemoryCheckpoint) {
-                    replacer.replace(replacee, (ValueNode) returnDuplicate.predecessor());
+                    replacer.replace(replacee, (ValueNode) returnDuplicate.predecessor(), mmap);
                 } else {
                     assert returnValue != null || replacee.usages().isEmpty() : this + " " + returnValue + " " + returnNode + " " + replacee.usages();
-                    replacer.replace(replacee, returnValue);
-
+                    replacer.replace(replacee, returnValue, mmap);
                 }
                 if (returnDuplicate.isAlive()) {
                     returnDuplicate.clearInputs();
@@ -831,6 +956,7 @@
      * @param args the arguments to be bound to the flattened positional parameters of the snippet
      */
     public void instantiate(MetaAccessProvider runtime, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, Arguments args) {
+        assert checkSnippetKills(replacee);
         try (TimerCloseable a = instantiationTimer.start()) {
             instantiationCounter.increment();
 
@@ -841,7 +967,8 @@
             FixedNode firstCFGNode = entryPointNode.next();
             StructuredGraph replaceeGraph = replacee.graph();
             IdentityHashMap<Node, Node> replacements = bind(replaceeGraph, runtime, args);
-            Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, replacements);
+            replacements.put(entryPointNode, replaceeGraph.start());
+            Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements);
             Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method());
 
             FixedWithNextNode lastFixedNode = tool.lastFixedNode();
@@ -872,7 +999,7 @@
                 returnValue = (ValueNode) duplicates.get(returnNode.result());
             }
             assert returnValue != null || replacee.usages().isEmpty();
-            replacer.replace(replacee, returnValue);
+            replacer.replace(replacee, returnValue, new DuplicateMapper(duplicates, replaceeGraph.start()));
 
             Node returnDuplicate = duplicates.get(returnNode);
             if (returnDuplicate.isAlive()) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -64,7 +64,7 @@
     public static native void storeInt(Object obj, @ConstantNodeParameter int displacement, long offset, int value);
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, value.kind(), displacement, offset, graph(), 1);
         WriteNode write = graph().add(new WriteNode(object, value, location, BarrierType.NONE, value.kind() == Kind.Object));
         graph().replaceFixedWithFixed(this, write);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,9 +22,12 @@
  */
 package com.oracle.graal.replacements.nodes;
 
+import static java.lang.reflect.Modifier.*;
+
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -32,6 +35,7 @@
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 public class MacroNode extends AbstractStateSplit implements Lowerable, MemoryCheckpoint.Single {
 
@@ -63,35 +67,68 @@
     }
 
     /**
-     * Gets a snippet to be used for lowering this macro node.
+     * Gets a snippet to be used for lowering this macro node. The returned graph (if non-null) must
+     * have been {@linkplain #lowerReplacement(StructuredGraph, LoweringTool) lowered}.
      */
     @SuppressWarnings("unused")
-    protected StructuredGraph getSnippetGraph(LoweringTool tool) {
+    protected StructuredGraph getLoweredSnippetGraph(LoweringTool tool) {
         return null;
     }
 
     /**
      * Gets a normal method substitution to be used for lowering this macro node. This is only
-     * called if {@link #getSnippetGraph(LoweringTool)} return nulls.
+     * called if {@link #getLoweredSnippetGraph(LoweringTool)} returns null. The returned graph (if
+     * non-null) must have been {@linkplain #lowerReplacement(StructuredGraph, LoweringTool)
+     * lowered}.
      */
-    protected StructuredGraph getSubstitutionGraph(LoweringTool tool) {
-        return tool.getReplacements().getMethodSubstitution(getTargetMethod());
+    protected StructuredGraph getLoweredSubstitutionGraph(LoweringTool tool) {
+        StructuredGraph methodSubstitution = tool.getReplacements().getMethodSubstitution(getTargetMethod());
+        if (methodSubstitution != null) {
+            return lowerReplacement(methodSubstitution.copy(), tool);
+        }
+        return null;
+    }
+
+    /**
+     * Applies {@linkplain LoweringPhase lowering} to a replacement graph.
+     * 
+     * @param replacementGraph a replacement (i.e., snippet or method substitution) graph
+     */
+    protected StructuredGraph lowerReplacement(final StructuredGraph replacementGraph, LoweringTool tool) {
+        replacementGraph.setGuardsStage(graph().getGuardsStage());
+        final PhaseContext c = new PhaseContext(tool.getRuntime(), tool.assumptions(), tool.getReplacements());
+        Debug.scope("LoweringReplacement", replacementGraph, new Runnable() {
+
+            public void run() {
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(replacementGraph, c);
+            }
+        });
+        return replacementGraph;
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        boolean nullCheck = false;
-        StructuredGraph replacementGraph = getSnippetGraph(tool);
+    public void lower(LoweringTool tool) {
+        StructuredGraph replacementGraph = getLoweredSnippetGraph(tool);
         if (replacementGraph == null) {
-            replacementGraph = getSubstitutionGraph(tool);
-            nullCheck = true;
+            replacementGraph = getLoweredSubstitutionGraph(tool);
         }
 
         InvokeNode invoke = replaceWithInvoke();
         assert invoke.verify();
 
         if (replacementGraph != null) {
-            InliningUtil.inline(invoke, replacementGraph, nullCheck);
+            // Pull out the receiver null check so that a replaced
+            // receiver can be lowered if necessary
+            if (!isStatic(targetMethod.getModifiers())) {
+                ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
+                if (nonNullReceiver instanceof Lowerable) {
+                    ((Lowerable) nonNullReceiver).lower(tool);
+                }
+            }
+            InliningUtil.inline(invoke, replacementGraph, false);
+            Debug.dump(graph(), "After inlining replacement %s", replacementGraph);
+        } else {
+            invoke.lower(tool);
         }
     }
 
@@ -110,17 +147,16 @@
     }
 
     protected void replaceSnippetInvokes(StructuredGraph snippetGraph) {
-        for (InvokeNode invoke : snippetGraph.getNodes(InvokeNode.class)) {
-            if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() != getTargetMethod()) {
+        for (MethodCallTargetNode call : snippetGraph.getNodes(MethodCallTargetNode.class)) {
+            Invoke invoke = call.invoke();
+            if (call.targetMethod() != getTargetMethod()) {
                 throw new GraalInternalError("unexpected invoke %s in snippet", getClass().getSimpleName());
             }
-            if (invoke.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) {
-                InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), getBci()));
-                newInvoke.setStateAfter(snippetGraph.add(new FrameState(FrameState.AFTER_BCI)));
-                snippetGraph.replaceFixedWithFixed(invoke, newInvoke);
-            } else {
-                assert invoke.stateAfter().bci == FrameState.AFTER_BCI : invoke;
-            }
+            assert invoke.stateAfter().bci == FrameState.AFTER_BCI;
+            // Here we need to fix the bci of the invoke
+            InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), getBci()));
+            newInvoke.setStateAfter(invoke.stateAfter());
+            snippetGraph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke);
         }
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -85,28 +85,15 @@
         gen.setResult(this, result);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 1;
+        return Constant.forDouble(compute(inputs[0].asDouble(), operation()));
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x().isConstant()) {
-            double value = x().asConstant().asDouble();
-            switch (operation()) {
-                case ABS:
-                    return ConstantNode.forDouble(Math.abs(value), graph());
-                case SQRT:
-                    return ConstantNode.forDouble(Math.sqrt(value), graph());
-                case LOG:
-                    return ConstantNode.forDouble(Math.log(value), graph());
-                case LOG10:
-                    return ConstantNode.forDouble(Math.log10(value), graph());
-                case SIN:
-                    return ConstantNode.forDouble(Math.sin(value), graph());
-                case COS:
-                    return ConstantNode.forDouble(Math.cos(value), graph());
-                case TAN:
-                    return ConstantNode.forDouble(Math.tan(value), graph());
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant()), graph());
         }
         return this;
     }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,7 +36,6 @@
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.phases.common.*;
@@ -118,7 +117,7 @@
                             if (ex.counted().isConstantMaxTripCount()) {
                                 long constant = ex.counted().constantMaxTripCount();
                                 if (constant <= UNROLL_LIMIT) {
-                                    LoopTransformations.fullUnroll(ex, runtime, assumptions, canonicalizeReads);
+                                    LoopTransformations.fullUnroll(ex, context, canonicalizer);
                                     Debug.dump(resultGraph, "After loop unrolling %d times", constant);
 
                                     canonicalizer.apply(resultGraph, context);
@@ -131,7 +130,7 @@
                 }
 
                 new DeadCodeEliminationPhase().apply(resultGraph);
-                new PartialEscapePhase(true).apply(resultGraph, context);
+                new PartialEscapePhase(true, canonicalizer).apply(resultGraph, context);
 
                 if (TruffleInlinePrinter.getValue()) {
                     InlinePrinterProcessor.printTree();
@@ -161,7 +160,7 @@
             frameState.replaceAtUsages(null);
             frameState.safeDelete();
         }
-        new CanonicalizerPhase.Instance(runtime, new Assumptions(false), true).apply(graph);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime, new Assumptions(false), replacements));
         new DeadCodeEliminationPhase().apply(graph);
     }
 
@@ -169,34 +168,36 @@
 
         StructuredGraph graphResult = Debug.scope("Truffle", new DebugDumpScope("Comparison: " + methodName), new Callable<StructuredGraph>() {
 
+            @SuppressWarnings("deprecation")
             public StructuredGraph call() {
                 Assumptions assumptions = new Assumptions(false);
                 StructuredGraph graph = parse(methodName);
-                CanonicalizerPhase.Instance canonicalizerPhase = new CanonicalizerPhase.Instance(runtime, assumptions, true);
-                canonicalizerPhase.apply(graph);
+                PhaseContext context = new PhaseContext(runtime, assumptions, replacements);
+                CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+                canonicalizer.apply(graph, context);
 
                 // Additional inlining.
                 final PhasePlan plan = new PhasePlan();
                 GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), TruffleCompilerImpl.Optimizations);
                 plan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
-                plan.addPhase(PhasePosition.AFTER_PARSING, canonicalizerPhase);
+                canonicalizer.addToPhasePlan(plan, context);
                 plan.addPhase(PhasePosition.AFTER_PARSING, new DeadCodeEliminationPhase());
 
                 new ConvertDeoptimizeToGuardPhase().apply(graph);
-                canonicalizerPhase.apply(graph);
+                canonicalizer.apply(graph, context);
                 new DeadCodeEliminationPhase().apply(graph);
 
-                HighTierContext context = new HighTierContext(runtime, assumptions, replacements, null, plan, OptimisticOptimizations.NONE);
-                InliningPhase inliningPhase = new InliningPhase();
-                inliningPhase.apply(graph, context);
+                HighTierContext highTierContext = new HighTierContext(runtime, assumptions, replacements, null, plan, OptimisticOptimizations.NONE);
+                InliningPhase inliningPhase = new InliningPhase(canonicalizer);
+                inliningPhase.apply(graph, highTierContext);
                 removeFrameStates(graph);
 
                 new ConvertDeoptimizeToGuardPhase().apply(graph);
-                canonicalizerPhase.apply(graph);
+                canonicalizer.apply(graph, context);
                 new DeadCodeEliminationPhase().apply(graph);
 
-                new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context);
-                canonicalizerPhase.apply(graph);
+                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, context);
+                canonicalizer.apply(graph, context);
                 new DeadCodeEliminationPhase().apply(graph);
                 return graph;
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationPolicy.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,109 @@
+/*
+ * 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 static com.oracle.graal.truffle.TruffleCompilerOptions.*;
+
+public class CompilationPolicy {
+
+    private int invokeCounter;
+    private int originalInvokeCounter;
+    private int loopAndInvokeCounter;
+    private long prevTimestamp;
+
+    private final int initialInvokeCounter;
+    private final int compilationThreshold;
+
+    public CompilationPolicy(final int compilationThreshold, final int initialInvokeCounter) {
+        this.invokeCounter = initialInvokeCounter;
+        this.loopAndInvokeCounter = compilationThreshold;
+        this.originalInvokeCounter = compilationThreshold;
+        this.prevTimestamp = System.currentTimeMillis();
+
+        this.compilationThreshold = compilationThreshold;
+        this.initialInvokeCounter = initialInvokeCounter;
+    }
+
+    public int getInvokeCounter() {
+        return invokeCounter;
+    }
+
+    public int getOriginalInvokeCounter() {
+        return originalInvokeCounter;
+    }
+
+    public int getLoopAndInvokeCounter() {
+        return loopAndInvokeCounter;
+    }
+
+    public void compilationInvalidated() {
+        int invalidationReprofileCount = TruffleInvalidationReprofileCount.getValue();
+        invokeCounter = invalidationReprofileCount;
+        if (TruffleFunctionInlining.getValue()) {
+            originalInvokeCounter += invalidationReprofileCount;
+        }
+    }
+
+    public void countInterpreterCall() {
+        invokeCounter--;
+        loopAndInvokeCounter--;
+    }
+
+    public void inlined(int minInvokesAfterInlining) {
+        invokeCounter = minInvokesAfterInlining;
+        int inliningReprofileCount = TruffleInliningReprofileCount.getValue();
+        loopAndInvokeCounter = inliningReprofileCount;
+        originalInvokeCounter = inliningReprofileCount;
+    }
+
+    public void reportLoopCount(int count) {
+        loopAndInvokeCounter = Math.max(0, loopAndInvokeCounter - count);
+    }
+
+    public void nodeReplaced() {
+        // delay compilation until tree is deemed stable enough
+        int replaceBackoff = TruffleReplaceReprofileCount.getValue();
+        if (loopAndInvokeCounter < replaceBackoff) {
+            loopAndInvokeCounter = replaceBackoff;
+        }
+    }
+
+    public boolean compileOrInline() {
+        if (invokeCounter <= 0 && loopAndInvokeCounter <= 0) {
+            if (TruffleUseTimeForCompilationDecision.getValue()) {
+                long timestamp = System.currentTimeMillis();
+                if ((timestamp - prevTimestamp) < TruffleCompilationDecisionTime.getValue()) {
+                    return true;
+                }
+                this.invokeCounter = initialInvokeCounter;
+                this.loopAndInvokeCounter = compilationThreshold;
+                this.originalInvokeCounter = compilationThreshold;
+                this.prevTimestamp = timestamp;
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Wed Oct 02 13:26:31 2013 +0200
@@ -50,6 +50,7 @@
         this.caller = caller;
         this.arguments = arguments;
         this.locals = new Object[descriptor.getSize()];
+        Arrays.fill(locals, descriptor.getTypeConversion().getDefaultValue());
         this.primitiveLocals = new long[descriptor.getSize()];
         this.tags = new byte[descriptor.getSize()];
     }
@@ -90,8 +91,8 @@
     }
 
     @Override
-    public void setObject(FrameSlot slot, Object value) throws FrameSlotTypeException {
-        verifySet(slot, FrameSlotKind.Object);
+    public void setObject(FrameSlot slot, Object value) {
+        verifySetObject(slot);
         setObjectUnsafe(slot, value);
     }
 
@@ -242,43 +243,50 @@
         tags[slotIndex] = (byte) accessKind.ordinal();
     }
 
-    private void verifyGet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException {
-        FrameSlotKind slotKind = slot.getKind();
-        if (slotKind != accessKind) {
+    private void verifySetObject(FrameSlot slot) {
+        if (slot.getKind() != FrameSlotKind.Object) {
             CompilerDirectives.transferToInterpreter();
-            if (slotKind == FrameSlotKind.Illegal && accessKind == FrameSlotKind.Object) {
-                slot.setKind(FrameSlotKind.Object);
-                this.setObject(slot, descriptor.getTypeConversion().getDefaultValue());
-            } else {
-                throw new FrameSlotTypeException();
-            }
+            slot.setKind(FrameSlotKind.Object);
         }
         int slotIndex = slot.getIndex();
         if (slotIndex >= tags.length) {
             CompilerDirectives.transferToInterpreter();
             resize();
         }
-        if (tags[slotIndex] != accessKind.ordinal()) {
+        tags[slotIndex] = (byte) FrameSlotKind.Object.ordinal();
+    }
+
+    private void verifyGet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException {
+        int slotIndex = slot.getIndex();
+        if (slotIndex >= tags.length) {
             CompilerDirectives.transferToInterpreter();
-            descriptor.getTypeConversion().updateFrameSlot(this, slot, getValue(slot));
-            if (tags[slotIndex] != accessKind.ordinal()) {
-                throw new FrameSlotTypeException();
+            resize();
+        }
+        byte tag = tags[slotIndex];
+        if (accessKind == FrameSlotKind.Object ? (tag & 0xfe) != 0 : tag != accessKind.ordinal()) {
+            CompilerDirectives.transferToInterpreter();
+            if (slot.getKind() == accessKind || tag == 0) {
+                descriptor.getTypeConversion().updateFrameSlot(this, slot, getValue(slot));
+                if (tags[slotIndex] == accessKind.ordinal()) {
+                    return;
+                }
             }
+            throw new FrameSlotTypeException();
         }
     }
 
     @Override
     public Object getValue(FrameSlot slot) {
-        int index = slot.getIndex();
-        if (index >= tags.length) {
-            assert index >= 0 && index < descriptor.getSize();
-            return descriptor.getTypeConversion().getDefaultValue();
+        int slotIndex = slot.getIndex();
+        if (slotIndex >= tags.length) {
+            CompilerDirectives.transferToInterpreter();
+            resize();
         }
-        byte tag = tags[index];
-        if (tag == FrameSlotKind.Illegal.ordinal()) {
-            return descriptor.getTypeConversion().getDefaultValue();
-        } else if (tag == FrameSlotKind.Boolean.ordinal()) {
+        byte tag = tags[slotIndex];
+        if (tag == FrameSlotKind.Boolean.ordinal()) {
             return getBooleanUnsafe(slot);
+        } else if (tag == FrameSlotKind.Byte.ordinal()) {
+            return getByteUnsafe(slot);
         } else if (tag == FrameSlotKind.Int.ordinal()) {
             return getIntUnsafe(slot);
         } else if (tag == FrameSlotKind.Double.ordinal()) {
@@ -288,14 +296,17 @@
         } else if (tag == FrameSlotKind.Float.ordinal()) {
             return getFloatUnsafe(slot);
         } else {
+            assert tag == FrameSlotKind.Object.ordinal() || tag == FrameSlotKind.Illegal.ordinal();
             return getObjectUnsafe(slot);
         }
     }
 
     private void resize() {
+        int oldSize = tags.length;
         int newSize = descriptor.getSize();
-        if (newSize > tags.length) {
+        if (newSize > oldSize) {
             locals = Arrays.copyOf(locals, newSize);
+            Arrays.fill(locals, oldSize, newSize, descriptor.getTypeConversion().getDefaultValue());
             primitiveLocals = Arrays.copyOf(primitiveLocals, newSize);
             tags = Arrays.copyOf(tags, newSize);
         }
@@ -303,14 +314,11 @@
 
     @Override
     public boolean isInitialized(FrameSlot slot) {
-        try {
-            return tags[slot.getIndex()] != 0;
-        } catch (ArrayIndexOutOfBoundsException ex) {
+        int slotIndex = slot.getIndex();
+        if (slotIndex >= tags.length) {
             CompilerDirectives.transferToInterpreter();
-            if (slot.getIndex() >= 0 && slot.getIndex() < descriptor.getSize()) {
-                return false;
-            }
-            throw ex;
+            resize();
         }
+        return tags[slotIndex] != 0;
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Wed Oct 02 13:26:31 2013 +0200
@@ -65,7 +65,7 @@
         if (truffleCompiler == null) {
             truffleCompiler = new TruffleCompilerImpl();
         }
-        return new OptimizedCallTarget(rootNode, frameDescriptor, truffleCompiler, TruffleCompilationThreshold.getValue());
+        return new OptimizedCallTarget(rootNode, frameDescriptor, truffleCompiler, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue());
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Wed Oct 02 13:26:31 2013 +0200
@@ -43,12 +43,10 @@
     private static final PrintStream OUT = TTY.out().out();
     private static final int MIN_INVOKES_AFTER_INLINING = 2;
 
-    protected OptimizedCallTarget(RootNode rootNode, FrameDescriptor descriptor, TruffleCompiler compiler, int compilationThreshold) {
+    protected OptimizedCallTarget(RootNode rootNode, FrameDescriptor descriptor, TruffleCompiler compiler, int invokeCounter, int compilationThreshold) {
         super(rootNode, descriptor);
         this.compiler = compiler;
-        this.invokeCounter = compilationThreshold >> 7;
-        this.loopAndInvokeCounter = compilationThreshold;
-        this.originalInvokeCounter = compilationThreshold;
+        this.compilationPolicy = new CompilationPolicy(compilationThreshold, invokeCounter);
         this.rootNode.setCallTarget(this);
 
         if (TruffleCallTargetProfiling.getValue()) {
@@ -58,10 +56,8 @@
 
     private HotSpotNmethod compiledMethod;
     private final TruffleCompiler compiler;
+    private final CompilationPolicy compilationPolicy;
 
-    private int invokeCounter;
-    private int originalInvokeCounter;
-    private int loopAndInvokeCounter;
     private boolean disableCompilation;
 
     private int callCount;
@@ -76,6 +72,10 @@
 
     @Override
     public Object call(PackedFrame caller, Arguments args) {
+        return callHelper(caller, args);
+    }
+
+    private Object callHelper(PackedFrame caller, Arguments args) {
         if (TruffleCallTargetProfiling.getValue()) {
             callCount++;
         }
@@ -93,12 +93,8 @@
     private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) {
         CompilerAsserts.neverPartOfCompilation();
         compiledMethod = null;
-        int invalidationReprofileCount = TruffleInvalidationReprofileCount.getValue();
-        invokeCounter = invalidationReprofileCount;
         invalidationCount++;
-        if (TruffleFunctionInlining.getValue()) {
-            originalInvokeCounter += invalidationReprofileCount;
-        }
+        compilationPolicy.compilationInvalidated();
         if (TraceTruffleCompilation.getValue()) {
             OUT.printf("[truffle] invalidated %-48s |Alive %5.0fms |Inv# %d                                     |Replace# %d\n", rootNode, (System.nanoTime() - timeCompilationFinished) / 1e6,
                             invalidationCount, replaceCount);
@@ -108,9 +104,8 @@
 
     private Object interpreterCall(PackedFrame caller, Arguments args) {
         CompilerAsserts.neverPartOfCompilation();
-        invokeCounter--;
-        loopAndInvokeCounter--;
-        if (disableCompilation || loopAndInvokeCounter > 0 || invokeCounter > 0) {
+        compilationPolicy.countInterpreterCall();
+        if (disableCompilation || !compilationPolicy.compileOrInline()) {
             return executeHelper(caller, args);
         } else {
             compileOrInline();
@@ -120,10 +115,7 @@
 
     private void compileOrInline() {
         if (TruffleFunctionInlining.getValue() && inline()) {
-            invokeCounter = MIN_INVOKES_AFTER_INLINING;
-            int inliningReprofileCount = TruffleInliningReprofileCount.getValue();
-            loopAndInvokeCounter = inliningReprofileCount;
-            originalInvokeCounter = inliningReprofileCount;
+            compilationPolicy.inlined(MIN_INVOKES_AFTER_INLINING);
         } else {
             compile();
         }
@@ -185,18 +177,13 @@
 
     @Override
     public void reportLoopCount(int count) {
-        loopAndInvokeCounter -= count;
+        compilationPolicy.reportLoopCount(count);
     }
 
     @Override
     public void nodeReplaced() {
         replaceCount++;
-
-        // delay compilation until tree is deemed stable enough
-        int replaceBackoff = TruffleReplaceReprofileCount.getValue();
-        if (loopAndInvokeCounter < replaceBackoff) {
-            loopAndInvokeCounter = replaceBackoff;
-        }
+        compilationPolicy.nodeReplaced();
     }
 
     private static class InliningHelper {
@@ -276,7 +263,7 @@
 
             public InliningPolicy(OptimizedCallTarget caller) {
                 this.callerNodeCount = NodeUtil.countNodes(caller.getRootNode());
-                this.callerInvocationCount = caller.originalInvokeCounter;
+                this.callerInvocationCount = caller.compilationPolicy.getOriginalInvokeCounter();
             }
 
             public boolean continueInlining() {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,11 +26,13 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
 
+import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.hotspot.*;
@@ -44,7 +46,6 @@
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
 import com.oracle.graal.phases.tiers.*;
@@ -65,9 +66,8 @@
 public class PartialEvaluator {
 
     private final MetaAccessProvider metaAccessProvider;
-    private final ResolvedJavaType nodeClass;
     private final ResolvedJavaMethod executeHelperMethod;
-    private final CustomCanonicalizer customCanonicalizer;
+    private final CanonicalizerPhase canonicalizer;
     private final ResolvedJavaType[] skippedExceptionTypes;
     private final Replacements replacements;
     private Set<Constant> constantReceivers;
@@ -76,8 +76,8 @@
 
     public PartialEvaluator(MetaAccessProvider metaAccessProvider, Replacements replacements, TruffleCache truffleCache) {
         this.metaAccessProvider = metaAccessProvider;
-        this.nodeClass = metaAccessProvider.lookupJavaType(com.oracle.truffle.api.nodes.Node.class);
-        this.customCanonicalizer = new PartialEvaluatorCanonicalizer(metaAccessProvider, nodeClass);
+        CustomCanonicalizer customCanonicalizer = new PartialEvaluatorCanonicalizer(metaAccessProvider);
+        this.canonicalizer = new CanonicalizerPhase(!AOTCompilation.getValue(), customCanonicalizer);
         this.skippedExceptionTypes = TruffleCompilerImpl.getSkippedExceptionTypes(metaAccessProvider);
         this.replacements = replacements;
         this.cache = HotSpotGraalRuntime.graalRuntime().getCache();
@@ -122,8 +122,8 @@
                 thisNode.replaceAndDelete(ConstantNode.forObject(node, metaAccessProvider, graph));
 
                 // Canonicalize / constant propagate.
-                CanonicalizerPhase.Instance canonicalizerPhase = new CanonicalizerPhase.Instance(metaAccessProvider, assumptions, !AOTCompilation.getValue(), null, customCanonicalizer);
-                canonicalizerPhase.apply(graph);
+                PhaseContext baseContext = new PhaseContext(metaAccessProvider, assumptions, replacements);
+                canonicalizer.apply(graph, baseContext);
 
                 // Intrinsify methods.
                 new ReplaceIntrinsicsPhase(replacements).apply(graph);
@@ -136,7 +136,9 @@
                 Debug.dump(graph, "Before inlining");
 
                 // Make sure frame does not escape.
-                expandTree(config, graph, newFrameNode, assumptions);
+                expandTree(graph, assumptions);
+
+                new VerifyFrameDoesNotEscapePhase().apply(graph, false);
 
                 if (TruffleInlinePrinter.getValue()) {
                     InlinePrinterProcessor.printTree();
@@ -148,29 +150,13 @@
                     for (Constant c : constantReceivers) {
                         histogram.add(c.asObject().getClass().getSimpleName());
                     }
-                    histogram.print(TTY.out().out());
+                    new DebugHistogramAsciiPrinter(TTY.out().out()).print(histogram);
                 }
 
                 // Additional inlining.
                 final PhasePlan plan = new PhasePlan();
-                GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(metaAccessProvider, config, TruffleCompilerImpl.Optimizations);
-                plan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
-                plan.addPhase(PhasePosition.AFTER_PARSING, canonicalizerPhase);
-                plan.addPhase(PhasePosition.AFTER_PARSING, new ReplaceIntrinsicsPhase(replacements));
-
-                new ConvertDeoptimizeToGuardPhase().apply(graph);
-                canonicalizerPhase.apply(graph);
-                new DeadCodeEliminationPhase().apply(graph);
-
+                canonicalizer.apply(graph, baseContext);
                 HighTierContext context = new HighTierContext(metaAccessProvider, assumptions, replacements, cache, plan, OptimisticOptimizations.NONE);
-                InliningPhase inliningPhase = new InliningPhase(customCanonicalizer);
-                inliningPhase.apply(graph, context);
-
-                // Convert deopt to guards.
-                new ConvertDeoptimizeToGuardPhase().apply(graph);
-
-                // Canonicalize / constant propagate.
-                canonicalizerPhase.apply(graph);
 
                 for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) {
                     Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage());
@@ -178,8 +164,7 @@
                 }
 
                 // EA frame and clean up.
-                new VerifyFrameDoesNotEscapePhase().apply(graph, false);
-                new PartialEscapePhase(false).apply(graph, context);
+                new PartialEscapePhase(false, canonicalizer).apply(graph, context);
                 new VerifyNoIntrinsicsLeftPhase().apply(graph, false);
                 for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) {
                     materializeNode.replaceAtUsages(materializeNode.getFrame());
@@ -197,55 +182,53 @@
                         }
                     }
                 }
-
-                // Convert deopt to guards.
-                new ConvertDeoptimizeToGuardPhase().apply(graph);
-
-                // Canonicalize / constant propagate.
-                canonicalizerPhase.apply(graph);
             }
         });
 
         return graph;
     }
 
-    private void expandTree(GraphBuilderConfiguration config, StructuredGraph graph, NewFrameNode newFrameNode, Assumptions assumptions) {
+    private void expandTree(StructuredGraph graph, Assumptions assumptions) {
+        PhaseContext context = new PhaseContext(metaAccessProvider, assumptions, replacements);
         boolean changed;
         do {
             changed = false;
-            for (Node usage : newFrameNode.usages().snapshot()) {
-                if (usage instanceof MethodCallTargetNode && !usage.isDeleted()) {
-                    MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) usage;
-                    InvokeKind kind = methodCallTargetNode.invokeKind();
-                    if (kind == InvokeKind.Special || kind == InvokeKind.Static) {
-                        if (TruffleInlinePrinter.getValue()) {
-                            InlinePrinterProcessor.addInlining(MethodHolder.getNewTruffleExecuteMethod(methodCallTargetNode));
+            for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class)) {
+                InvokeKind kind = methodCallTargetNode.invokeKind();
+                if (kind == InvokeKind.Static || (kind == InvokeKind.Special && (methodCallTargetNode.receiver().isConstant() || methodCallTargetNode.receiver() instanceof NewFrameNode))) {
+                    if (TruffleInlinePrinter.getValue()) {
+                        InlinePrinterProcessor.addInlining(MethodHolder.getNewTruffleExecuteMethod(methodCallTargetNode));
+                    }
+                    if (TraceTruffleCompilationDetails.getValue() && kind == InvokeKind.Special) {
+                        ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first();
+                        constantReceivers.add(constantNode.asConstant());
+                    }
+                    StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
+
+                    if (inlineGraph == null) {
+                        Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod());
+                        if (macroSubstitution != null) {
+                            InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), methodCallTargetNode.graph(), macroSubstitution);
+                            changed = true;
+                            continue;
                         }
-                        if (TraceTruffleCompilationDetails.getValue() && kind == InvokeKind.Special && methodCallTargetNode.arguments().first() instanceof ConstantNode) {
-                            ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first();
-                            constantReceivers.add(constantNode.asConstant());
-                        }
-                        StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
-                        NewFrameNode otherNewFrame = null;
-                        if (inlineGraph == null) {
-                            inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, !AOTCompilation.getValue());
-                            otherNewFrame = inlineGraph.getNodes(NewFrameNode.class).first();
-                        }
+                    }
 
+                    if (inlineGraph == null && !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) &&
+                                    methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null) {
+                        inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, context);
+                    }
+
+                    if (inlineGraph != null) {
                         int nodeCountBefore = graph.getNodeCount();
-                        Map<Node, Node> mapping = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false);
+                        int mark = graph.getMark();
+                        InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false);
                         if (Debug.isDumpEnabled()) {
                             int nodeCountAfter = graph.getNodeCount();
                             Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter);
                         }
+                        canonicalizer.applyIncremental(graph, context, mark);
                         changed = true;
-
-                        if (otherNewFrame != null) {
-                            otherNewFrame = (NewFrameNode) mapping.get(otherNewFrame);
-                            if (otherNewFrame.isAlive() && otherNewFrame.usages().isNotEmpty()) {
-                                expandTree(config, graph, otherNewFrame, assumptions);
-                            }
-                        }
                     }
                 }
 
@@ -253,64 +236,68 @@
                     throw new BailoutException("Truffle compilation is exceeding maximum node count: " + graph.getNodeCount());
                 }
             }
-        } while (changed && newFrameNode.isAlive() && newFrameNode.usages().isNotEmpty());
+        } while (changed);
     }
 
-    private StructuredGraph parseGraph(final ResolvedJavaMethod targetMethod, final NodeInputList<ValueNode> arguments, final Assumptions assumptions, final boolean canonicalizeReads) {
-
-        final StructuredGraph graph = truffleCache.lookup(targetMethod, arguments, assumptions);
-        Debug.scope("parseGraph", targetMethod, new Runnable() {
+    private StructuredGraph parseGraph(final ResolvedJavaMethod targetMethod, final NodeInputList<ValueNode> arguments, final Assumptions assumptions, final PhaseContext context) {
 
-            @Override
-            public void run() {
-
-                // Canonicalize / constant propagate.
-                new CanonicalizerPhase.Instance(metaAccessProvider, assumptions, canonicalizeReads, null, customCanonicalizer).apply(graph);
+        StructuredGraph graph = truffleCache.lookup(targetMethod, arguments, assumptions, canonicalizer);
 
-                // Intrinsify methods.
-                new ReplaceIntrinsicsPhase(replacements).apply(graph);
+        if (targetMethod.getAnnotation(ExplodeLoop.class) != null) {
+            assert graph.hasLoops();
+            final StructuredGraph graphCopy = graph.copy();
+            final List<Node> modifiedNodes = new ArrayList<>();
+            for (LocalNode local : graphCopy.getNodes(LocalNode.class)) {
+                ValueNode arg = arguments.get(local.index());
+                if (arg.isConstant()) {
+                    Constant constant = arg.asConstant();
+                    ConstantNode constantNode = ConstantNode.forConstant(constant, metaAccessProvider, graphCopy);
+                    local.replaceAndDelete(constantNode);
+                    for (Node usage : constantNode.usages()) {
+                        if (usage instanceof Canonicalizable) {
+                            modifiedNodes.add(usage);
+                        }
+                    }
+                }
+            }
+            Debug.scope("TruffleUnrollLoop", targetMethod, new Runnable() {
 
-                // Inline trivial getter methods
-                new InlineTrivialGettersPhase(metaAccessProvider, assumptions, customCanonicalizer).apply(graph);
+                @Override
+                public void run() {
 
-                // Convert deopt to guards.
-                new ConvertDeoptimizeToGuardPhase().apply(graph);
-
-                if (graph.hasLoops()) {
+                    canonicalizer.applyIncremental(graphCopy, context, modifiedNodes);
                     boolean unrolled;
                     do {
                         unrolled = false;
-                        LoopsData loopsData = new LoopsData(graph);
+                        LoopsData loopsData = new LoopsData(graphCopy);
                         loopsData.detectedCountedLoops();
                         for (LoopEx ex : innerLoopsFirst(loopsData.countedLoops())) {
                             if (ex.counted().isConstantMaxTripCount()) {
                                 long constant = ex.counted().constantMaxTripCount();
-                                if (constant <= TruffleConstantUnrollLimit.getValue() || targetMethod.getAnnotation(ExplodeLoop.class) != null) {
-                                    LoopTransformations.fullUnroll(ex, metaAccessProvider, assumptions, canonicalizeReads);
-                                    Debug.dump(graph, "After loop unrolling %d times", constant);
-                                    new CanonicalizerPhase.Instance(metaAccessProvider, assumptions, canonicalizeReads, null, customCanonicalizer).apply(graph);
-                                    unrolled = true;
-                                    break;
-                                }
+                                LoopTransformations.fullUnroll(ex, context, canonicalizer);
+                                Debug.dump(graphCopy, "After loop unrolling %d times", constant);
+                                unrolled = true;
+                                break;
                             }
                         }
                     } while (unrolled);
                 }
-            }
 
-            private List<LoopEx> innerLoopsFirst(Collection<LoopEx> loops) {
-                ArrayList<LoopEx> sortedLoops = new ArrayList<>(loops);
-                Collections.sort(sortedLoops, new Comparator<LoopEx>() {
+                private List<LoopEx> innerLoopsFirst(Collection<LoopEx> loops) {
+                    ArrayList<LoopEx> sortedLoops = new ArrayList<>(loops);
+                    Collections.sort(sortedLoops, new Comparator<LoopEx>() {
 
-                    @Override
-                    public int compare(LoopEx o1, LoopEx o2) {
-                        return o2.lirLoop().depth - o1.lirLoop().depth;
-                    }
-                });
-                return sortedLoops;
-            }
-        });
-
-        return graph;
+                        @Override
+                        public int compare(LoopEx o1, LoopEx o2) {
+                            return o2.lirLoop().depth - o1.lirLoop().depth;
+                        }
+                    });
+                    return sortedLoops;
+                }
+            });
+            return graphCopy;
+        } else {
+            return graph;
+        }
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,10 +24,11 @@
 
 import java.lang.reflect.*;
 
+import sun.misc.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.Node.Child;
@@ -35,40 +36,43 @@
 final class PartialEvaluatorCanonicalizer implements CanonicalizerPhase.CustomCanonicalizer {
 
     private final MetaAccessProvider metaAccessProvider;
-    private final ResolvedJavaType nodeClass;
 
-    PartialEvaluatorCanonicalizer(MetaAccessProvider metaAccessProvider, ResolvedJavaType nodeClass) {
+    PartialEvaluatorCanonicalizer(MetaAccessProvider metaAccessProvider) {
         this.metaAccessProvider = metaAccessProvider;
-        this.nodeClass = nodeClass;
     }
 
     @Override
     public ValueNode canonicalize(ValueNode node) {
         if (node instanceof LoadFieldNode) {
             LoadFieldNode loadFieldNode = (LoadFieldNode) node;
-            if (!loadFieldNode.isStatic() &&
-                            loadFieldNode.object().isConstant() &&
-                            !loadFieldNode.object().isNullConstant() &&
-                            ((loadFieldNode.kind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) || Modifier.isFinal(loadFieldNode.field().getModifiers()) || loadFieldNode.field().getAnnotation(
-                                            CompilerDirectives.CompilationFinal.class) != null)) {
-                Constant constant = loadFieldNode.field().readValue(loadFieldNode.object().asConstant());
-                return ConstantNode.forConstant(constant, metaAccessProvider, node.graph());
+            if (!loadFieldNode.isStatic() && loadFieldNode.object().isConstant() && !loadFieldNode.object().isNullConstant()) {
+                if (Modifier.isFinal(loadFieldNode.field().getModifiers()) || (loadFieldNode.kind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) ||
+                                loadFieldNode.field().getAnnotation(CompilerDirectives.CompilationFinal.class) != null) {
+                    Constant constant = loadFieldNode.field().readValue(loadFieldNode.object().asConstant());
+                    assert verifyFieldValue(loadFieldNode.field(), constant);
+                    return ConstantNode.forConstant(constant, metaAccessProvider, node.graph());
+                }
             }
         } else if (node instanceof LoadIndexedNode) {
             LoadIndexedNode loadIndexedNode = (LoadIndexedNode) node;
-            Stamp stamp = loadIndexedNode.array().stamp();
-            if (stamp.kind() == Kind.Object && loadIndexedNode.array().isConstant() && !loadIndexedNode.array().isNullConstant() && loadIndexedNode.index().isConstant()) {
-                ObjectStamp objectStamp = (ObjectStamp) stamp;
-                ResolvedJavaType type = objectStamp.type();
-                if (type != null && type.isArray() && this.nodeClass.isAssignableFrom(type.getComponentType())) {
-                    Object array = loadIndexedNode.array().asConstant().asObject();
-                    int index = loadIndexedNode.index().asConstant().asInt();
-                    Object value = Array.get(array, index);
-                    return ConstantNode.forObject(value, metaAccessProvider, node.graph());
+            if (loadIndexedNode.array().isConstant() && !loadIndexedNode.array().isNullConstant() && loadIndexedNode.index().isConstant()) {
+                Object array = loadIndexedNode.array().asConstant().asObject();
+                long index = loadIndexedNode.index().asConstant().asLong();
+                if (index >= 0 && index < Array.getLength(array)) {
+                    int arrayBaseOffset = Unsafe.getUnsafe().arrayBaseOffset(array.getClass());
+                    int arrayIndexScale = Unsafe.getUnsafe().arrayIndexScale(array.getClass());
+                    Constant constant = metaAccessProvider.readUnsafeConstant(loadIndexedNode.elementKind(), array, arrayBaseOffset + index * arrayIndexScale,
+                                    loadIndexedNode.elementKind() == Kind.Object);
+                    return ConstantNode.forConstant(constant, metaAccessProvider, loadIndexedNode.graph());
                 }
             }
         }
-
         return node;
     }
+
+    private static boolean verifyFieldValue(ResolvedJavaField field, Constant constant) {
+        assert field.getAnnotation(Child.class) == null || constant.isNull() || constant.asObject() instanceof com.oracle.truffle.api.nodes.Node : "@Child field value must be a Node: " + field +
+                        ", but was: " + constant.asObject();
+        return true;
+    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,16 +31,15 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -59,264 +58,168 @@
     private final OptimisticOptimizations optimisticOptimizations;
     private final Replacements replacements;
 
-    private final HashMap<ResolvedJavaMethod, StructuredGraph> cache = new HashMap<>();
+    private final HashMap<List<Object>, StructuredGraph> cache = new HashMap<>();
+    private final StructuredGraph markerGraph = new StructuredGraph();
+    private final ResolvedJavaType stringBuilderClass;
 
     public TruffleCache(MetaAccessProvider metaAccessProvider, GraphBuilderConfiguration config, OptimisticOptimizations optimisticOptimizations, Replacements replacements) {
         this.metaAccessProvider = metaAccessProvider;
         this.config = config;
         this.optimisticOptimizations = optimisticOptimizations;
         this.replacements = replacements;
+        this.stringBuilderClass = metaAccessProvider.lookupJavaType(StringBuilder.class);
     }
 
-    public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList<ValueNode> arguments, final Assumptions assumptions) {
+    @SuppressWarnings("unused")
+    public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList<ValueNode> arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer) {
 
-        StructuredGraph resultGraph = null;
-        if (cache.containsKey(method)) {
-            StructuredGraph graph = cache.get(method);
-            if (checkArgumentStamps(graph, arguments)) {
-                resultGraph = graph;
+        List<Object> key = new ArrayList<>(arguments.size() + 1);
+        key.add(method);
+        for (ValueNode v : arguments) {
+            if (v.kind() == Kind.Object) {
+                key.add(v.stamp());
             }
         }
+        StructuredGraph resultGraph = cache.get(key);
+        if (resultGraph != null) {
+            return resultGraph;
+        }
+
+        if (resultGraph == markerGraph) {
+            // Avoid recursive inline.
+            return null;
+        }
 
-        if (resultGraph == null) {
-            resultGraph = Debug.sandbox("TruffleCache", new Object[]{metaAccessProvider, method}, DebugScope.getConfig(), new Callable<StructuredGraph>() {
+        cache.put(key, markerGraph);
+        resultGraph = Debug.scope("TruffleCache", new Object[]{metaAccessProvider, method}, new Callable<StructuredGraph>() {
+
+            public StructuredGraph call() {
+
+                final StructuredGraph graph = new StructuredGraph(method);
+                PhaseContext context = new PhaseContext(metaAccessProvider, new Assumptions(false), replacements);
+                new GraphBuilderPhase(metaAccessProvider, config, optimisticOptimizations).apply(graph);
+
+                for (LocalNode l : graph.getNodes(LocalNode.class)) {
+                    if (l.kind() == Kind.Object) {
+                        ValueNode actualArgument = arguments.get(l.index());
+                        l.setStamp(l.stamp().join(actualArgument.stamp()));
+                    }
+                }
 
-                public StructuredGraph call() {
-                    StructuredGraph newGraph = parseGraph(method);
+                // Intrinsify methods.
+                new ReplaceIntrinsicsPhase(replacements).apply(graph);
+
+                // Convert deopt to guards.
+                new ConvertDeoptimizeToGuardPhase().apply(graph);
+
+                CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!AOTCompilation.getValue());
+                PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizerPhase);
+
+                int mark = 0;
+                while (true) {
+
+                    partialEscapePhase.apply(graph, context);
+
+                    // Conditional elimination.
+                    ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(metaAccessProvider);
+                    conditionalEliminationPhase.apply(graph);
+
+                    // Canonicalize / constant propagate.
+                    canonicalizerPhase.apply(graph, context);
 
-                    // Get stamps from actual arguments.
-                    List<Stamp> stamps = new ArrayList<>();
-                    for (ValueNode arg : arguments) {
-                        stamps.add(arg.stamp());
-                    }
-
-                    if (cache.containsKey(method)) {
-                        // Make sure stamps are generalized based on previous stamps.
-                        StructuredGraph graph = cache.get(method);
-                        for (LocalNode localNode : graph.getNodes(LocalNode.class)) {
-                            int index = localNode.index();
-                            Stamp stamp = stamps.get(index);
-                            stamps.set(index, stamp.meet(localNode.stamp()));
+                    boolean inliningProgress = false;
+                    for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) {
+                        if (graph.getMark() != mark) {
+                            // Make sure macro substitutions such as
+                            // CompilerDirectives.transferToInterpreter get processed first.
+                            for (Node newNode : graph.getNewNodes(mark)) {
+                                if (newNode instanceof MethodCallTargetNode) {
+                                    MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode;
+                                    Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod());
+                                    if (macroSubstitution != null) {
+                                        InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), methodCallTargetNode.graph(), macroSubstitution);
+                                    } else {
+                                        tryCutOffRuntimeExceptions(methodCallTargetNode);
+                                    }
+                                }
+                            }
+                            mark = graph.getMark();
+                        }
+                        if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null && shouldInline(methodCallTarget)) {
+                            inliningProgress = true;
+                            List<Node> canonicalizerUsages = new ArrayList<Node>();
+                            for (Node n : methodCallTarget.invoke().asNode().usages()) {
+                                if (n instanceof Canonicalizable) {
+                                    canonicalizerUsages.add(n);
+                                }
+                            }
+                            List<ValueNode> argumentSnapshot = methodCallTarget.arguments().snapshot();
+                            int beforeInvokeMark = graph.getMark();
+                            expandInvoke(methodCallTarget);
+                            for (Node arg : argumentSnapshot) {
+                                if (arg != null) {
+                                    for (Node argUsage : arg.usages()) {
+                                        if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) {
+                                            canonicalizerUsages.add(argUsage);
+                                        }
+                                    }
+                                }
+                            }
+                            canonicalizerPhase.applyIncremental(graph, context, canonicalizerUsages);
                         }
                     }
 
-                    // Set stamps into graph before optimizing.
-                    for (LocalNode localNode : newGraph.getNodes(LocalNode.class)) {
-                        int index = localNode.index();
-                        Stamp stamp = stamps.get(index);
-                        localNode.setStamp(stamp);
-                    }
-
-                    Assumptions tmpAssumptions = new Assumptions(false);
-
-                    optimizeGraph(newGraph, tmpAssumptions);
-
-                    PhaseContext context = new PhaseContext(metaAccessProvider, tmpAssumptions, replacements);
-                    PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false);
-                    partialEscapePhase.apply(newGraph, context);
+                    // Convert deopt to guards.
+                    new ConvertDeoptimizeToGuardPhase().apply(graph);
 
-                    cache.put(method, newGraph);
-                    if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
-                        TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, newGraph.getNodeCount()));
-                    }
-                    return newGraph;
-                }
-            });
-        }
-
-        final StructuredGraph clonedResultGraph = resultGraph.copy();
-
-        Debug.sandbox("TruffleCacheConstants", new Object[]{metaAccessProvider, method}, DebugScope.getConfig(), new Runnable() {
-
-            public void run() {
-
-                Debug.dump(clonedResultGraph, "before applying constants");
-                // Pass on constant arguments.
-                for (LocalNode local : clonedResultGraph.getNodes(LocalNode.class)) {
-                    ValueNode arg = arguments.get(local.index());
-                    if (arg.isConstant()) {
-                        Constant constant = arg.asConstant();
-                        local.replaceAndDelete(ConstantNode.forConstant(constant, metaAccessProvider, clonedResultGraph));
-                    } else {
-                        local.setStamp(arg.stamp());
+                    if (!inliningProgress) {
+                        break;
                     }
                 }
-                Debug.dump(clonedResultGraph, "after applying constants");
-                optimizeGraph(clonedResultGraph, assumptions);
+
+                if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
+                    TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, graph.getNodeCount()));
+                }
+                return graph;
             }
         });
-        return clonedResultGraph;
-    }
-
-    private void optimizeGraph(StructuredGraph newGraph, Assumptions assumptions) {
-        PhaseContext context = new PhaseContext(metaAccessProvider, assumptions, replacements);
-        ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(metaAccessProvider);
-        ConvertDeoptimizeToGuardPhase convertDeoptimizeToGuardPhase = new ConvertDeoptimizeToGuardPhase();
-        CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!AOTCompilation.getValue());
-        EarlyReadEliminationPhase readEliminationPhase = new EarlyReadEliminationPhase();
-
-        int maxNodes = TruffleCompilerOptions.TruffleOperationCacheMaxNodes.getValue();
-
-        contractGraph(newGraph, conditionalEliminationPhase, convertDeoptimizeToGuardPhase, canonicalizerPhase, readEliminationPhase, context);
-
-        while (newGraph.getNodeCount() <= maxNodes) {
-
-            int mark = newGraph.getMark();
-
-            expandGraph(newGraph, maxNodes);
-
-            if (newGraph.getNewNodes(mark).count() == 0) {
-                // No progress => exit iterative optimization.
-                break;
-            }
-
-            contractGraph(newGraph, conditionalEliminationPhase, convertDeoptimizeToGuardPhase, canonicalizerPhase, readEliminationPhase, context);
-        }
-
-        if (newGraph.getNodeCount() > maxNodes && (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue() || TruffleCompilerOptions.TraceTrufflePerformanceWarnings.getValue())) {
-            TTY.println(String.format("[truffle] PERFORMANCE WARNING: method %s got too large with %d nodes.", newGraph.method(), newGraph.getNodeCount()));
-        }
+        cache.put(key, resultGraph);
+        return resultGraph;
     }
 
-    private static void contractGraph(StructuredGraph newGraph, ConditionalEliminationPhase conditionalEliminationPhase, ConvertDeoptimizeToGuardPhase convertDeoptimizeToGuardPhase,
-                    CanonicalizerPhase canonicalizerPhase, EarlyReadEliminationPhase readEliminationPhase, PhaseContext context) {
-        // Canonicalize / constant propagate.
-        canonicalizerPhase.apply(newGraph, context);
-
-        // Early read eliminiation
-        readEliminationPhase.apply(newGraph, context);
-
-        // Convert deopt to guards.
-        convertDeoptimizeToGuardPhase.apply(newGraph);
-
-        // Conditional elimination.
-        conditionalEliminationPhase.apply(newGraph);
-    }
-
-    private void expandGraph(StructuredGraph newGraph, int maxNodes) {
-        NodeBitMap visitedNodes = newGraph.createNodeBitMap(true);
-        Queue<AbstractBeginNode> workQueue = new LinkedList<>();
-        workQueue.add(newGraph.start());
-
-        while (!workQueue.isEmpty() && newGraph.getNodeCount() <= maxNodes) {
-            AbstractBeginNode start = workQueue.poll();
-            expandPath(newGraph, maxNodes, visitedNodes, start, workQueue);
+    private void expandInvoke(MethodCallTargetNode methodCallTargetNode) {
+        StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
+        if (inlineGraph == null) {
+            inlineGraph = TruffleCache.this.lookup(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), null, null);
         }
+        if (inlineGraph == this.markerGraph) {
+            // Can happen for recursive calls.
+            throw GraphUtil.approxSourceException(methodCallTargetNode, new IllegalStateException("Found illegal recursive call to " + methodCallTargetNode.targetMethod() +
+                            ", must annotate such calls with @CompilerDirectives.SlowPath!"));
+        }
+        Invoke invoke = methodCallTargetNode.invoke();
+        InliningUtil.inline(invoke, inlineGraph, true);
     }
 
-    private void expandPath(StructuredGraph newGraph, int maxNodes, NodeBitMap visitedNodes, AbstractBeginNode start, Queue<AbstractBeginNode> workQueue) {
-        if (start.isDeleted()) {
-            return;
-        }
-
-        FixedNode next = start;
-        while (!visitedNodes.isMarked(next)) {
-            visitedNodes.mark(next);
-            if (next instanceof Invoke) {
-                Invoke invoke = (Invoke) next;
-                next = expandInvoke(invoke);
-                if (newGraph.getNodeCount() > maxNodes) {
-                    return;
-                }
-            }
-
-            if (next instanceof InvokeWithExceptionNode) {
-                InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) next;
-                next = invokeWithExceptionNode.next();
-            } else if (next instanceof IfNode && isAssertionsEnabledCondition(((IfNode) next).condition())) {
-                next = ((IfNode) next).falseSuccessor();
-            } else if (next instanceof ControlSplitNode) {
-                ControlSplitNode controlSplitNode = (ControlSplitNode) next;
-                AbstractBeginNode maxProbNode = null;
-                for (Node succ : controlSplitNode.cfgSuccessors()) {
-                    AbstractBeginNode successor = (AbstractBeginNode) succ;
-                    if (maxProbNode == null || controlSplitNode.probability(successor) > controlSplitNode.probability(maxProbNode)) {
-                        maxProbNode = successor;
-                    }
-                }
-                for (Node succ : controlSplitNode.cfgSuccessors()) {
-                    AbstractBeginNode successor = (AbstractBeginNode) succ;
-                    if (successor != maxProbNode) {
-                        workQueue.add(successor);
-                    }
-                }
-                next = maxProbNode;
-            } else if (next instanceof EndNode) {
-                EndNode endNode = (EndNode) next;
-                next = endNode.merge();
-            } else if (next instanceof ControlSinkNode) {
-                return;
-            } else if (next instanceof FixedWithNextNode) {
-                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) next;
-                next = fixedWithNextNode.next();
-            }
-        }
-    }
-
-    private static boolean isAssertionsEnabledCondition(LogicNode condition) {
-        if (condition instanceof IntegerEqualsNode) {
-            IntegerEqualsNode equalsNode = (IntegerEqualsNode) condition;
-            if (equalsNode.x() instanceof LoadFieldNode && equalsNode.y().isConstant()) {
-                LoadFieldNode loadFieldNode = (LoadFieldNode) equalsNode.x();
-                if (loadFieldNode.isStatic() && loadFieldNode.field().getName().equals("$assertionsDisabled") && loadFieldNode.field().isSynthetic()) {
-                    return ((ConstantNode) equalsNode.y()).value.equals(Constant.INT_0);
-                }
+    private boolean tryCutOffRuntimeExceptions(MethodCallTargetNode methodCallTargetNode) {
+        if (methodCallTargetNode.targetMethod().isConstructor()) {
+            ResolvedJavaType runtimeException = metaAccessProvider.lookupJavaType(RuntimeException.class);
+            ResolvedJavaType controlFlowException = metaAccessProvider.lookupJavaType(ControlFlowException.class);
+            ResolvedJavaType exceptionType = Objects.requireNonNull(ObjectStamp.typeOrNull(methodCallTargetNode.receiver().stamp()));
+            if (runtimeException.isAssignableFrom(methodCallTargetNode.targetMethod().getDeclaringClass()) && !controlFlowException.isAssignableFrom(exceptionType)) {
+                DeoptimizeNode deoptNode = methodCallTargetNode.graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode));
+                FixedNode invokeNode = methodCallTargetNode.invoke().asNode();
+                invokeNode.replaceAtPredecessor(deoptNode);
+                GraphUtil.killCFG(invokeNode);
+                return true;
             }
         }
         return false;
     }
 
-    private FixedNode expandInvoke(Invoke invoke) {
-        if (invoke.callTarget() instanceof MethodCallTargetNode) {
-            final MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) invoke.callTarget();
-
-            if ((methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) &&
-                            !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null &&
-                            methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null) {
-                Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod());
-                if (macroSubstitution != null) {
-                    return InliningUtil.inlineMacroNode(invoke, methodCallTargetNode.targetMethod(), methodCallTargetNode.graph(), macroSubstitution);
-                } else {
-                    StructuredGraph inlinedGraph = Debug.scope("ExpandInvoke", methodCallTargetNode.targetMethod(), new Callable<StructuredGraph>() {
-
-                        public StructuredGraph call() {
-                            StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
-                            if (inlineGraph == null) {
-                                inlineGraph = parseGraph(methodCallTargetNode.targetMethod());
-                            }
-                            return inlineGraph;
-                        }
-                    });
-                    FixedNode fixedNode = (FixedNode) invoke.predecessor();
-                    InliningUtil.inline(invoke, inlinedGraph, true);
-                    return fixedNode;
-                }
-            }
-        }
-        return invoke.asNode();
-    }
-
-    private StructuredGraph parseGraph(ResolvedJavaMethod method) {
-        StructuredGraph graph = new StructuredGraph(method);
-        new GraphBuilderPhase(metaAccessProvider, config, optimisticOptimizations).apply(graph);
-        // Intrinsify methods.
-        new ReplaceIntrinsicsPhase(replacements).apply(graph);
-        return graph;
-    }
-
-    private static boolean checkArgumentStamps(StructuredGraph graph, NodeInputList<ValueNode> arguments) {
-        assert graph.getNodes(LocalNode.class).count() <= arguments.count();
-        for (LocalNode localNode : graph.getNodes(LocalNode.class)) {
-            Stamp newStamp = localNode.stamp().meet(arguments.get(localNode.index()).stamp());
-            if (!newStamp.equals(localNode.stamp())) {
-                if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
-                    TTY.println(String.format("[truffle] graph cache entry too specific for method %s argument %s previous stamp %s new stamp %s.", graph.method(), localNode, localNode.stamp(),
-                                    newStamp));
-                }
-                return false;
-            }
-        }
-
-        return true;
+    private boolean shouldInline(final MethodCallTargetNode methodCallTargetNode) {
+        return (methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) &&
+                        !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null &&
+                        methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null && methodCallTargetNode.targetMethod().getDeclaringClass() != stringBuilderClass;
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.truffle;
 
 import static com.oracle.graal.api.code.CodeUtil.*;
-import static com.oracle.graal.compiler.GraalDebugConfig.*;
 
 import java.util.*;
 import java.util.concurrent.*;
@@ -78,13 +77,13 @@
         this.graalRuntime = HotSpotGraalRuntime.graalRuntime();
         this.skippedExceptionTypes = getSkippedExceptionTypes(metaAccessProvider);
 
-        final GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault();
+        final GraphBuilderConfiguration config = GraphBuilderConfiguration.getEagerDefault();
         config.setSkippedExceptionTypes(skippedExceptionTypes);
         this.truffleCache = new TruffleCache(this.runtime, config, TruffleCompilerImpl.Optimizations, this.replacements);
 
         this.partialEvaluator = new PartialEvaluator(metaAccessProvider, replacements, truffleCache);
 
-        if (DebugEnabled.getValue()) {
+        if (Debug.isEnabled()) {
             DebugEnvironment.initialize(System.out);
         }
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Wed Oct 02 13:26:31 2013 +0200
@@ -46,6 +46,8 @@
     @Option(help = "")
     public static final OptionValue<Integer> TruffleCompilationThreshold = new OptionValue<>(1000);
     @Option(help = "")
+    public static final OptionValue<Integer> TruffleMinInvokeThreshold = new OptionValue<>(3);
+    @Option(help = "")
     public static final OptionValue<Integer> TruffleInvalidationReprofileCount = new OptionValue<>(3);
     @Option(help = "")
     public static final OptionValue<Integer> TruffleReplaceReprofileCount = new OptionValue<>(10);
@@ -69,7 +71,10 @@
     public static final OptionValue<Integer> TruffleInliningTrivialSize = new OptionValue<>(10);
     @Option(help = "")
     public static final OptionValue<Double> TruffleInliningMinFrequency = new OptionValue<>(0.3);
-
+    @Option(help = "")
+    public static final OptionValue<Boolean> TruffleUseTimeForCompilationDecision = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Integer> TruffleCompilationDecisionTime = new OptionValue<>(100);
     // tracing
     @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleCompilation = new OptionValue<>(true);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Wed Oct 02 13:26:31 2013 +0200
@@ -56,7 +56,6 @@
         truffleReplacements.registerSubstitutions(CompilerDirectivesSubstitutions.class);
         truffleReplacements.registerSubstitutions(ExactMathSubstitutions.class);
         truffleReplacements.registerSubstitutions(UnexpectedResultExceptionSubstitutions.class);
-        truffleReplacements.registerSubstitutions(SlowPathExceptionSubstitutions.class);
         truffleReplacements.registerSubstitutions(FrameWithoutBoxingSubstitutions.class);
         truffleReplacements.registerSubstitutions(OptimizedAssumptionSubstitutions.class);
         truffleReplacements.registerSubstitutions(OptimizedCallTargetSubstitutions.class);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.truffle.nodes;
 
-import com.oracle.graal.api.code.*;
 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.truffle.*;
 
-public class AssumptionNode extends MacroNode implements com.oracle.graal.graph.Node.IterableNodeType, Simplifiable {
+public class AssumptionNode extends MacroNode implements com.oracle.graal.graph.IterableNodeType, Simplifiable {
 
     public AssumptionNode(Invoke invoke) {
         super(invoke);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/BailoutNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/BailoutNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.nodes.*;
 
-public class BailoutNode extends MacroNode implements com.oracle.graal.graph.Node.IterableNodeType, Canonicalizable {
+public class BailoutNode extends MacroNode implements Canonicalizable {
 
     public BailoutNode(Invoke invoke) {
         super(invoke);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/LoadIndexedFinalNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,86 @@
+/*
+ * 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.nodes;
+
+import java.lang.reflect.*;
+
+import sun.misc.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * @see LoadIndexedNode
+ */
+public final class LoadIndexedFinalNode extends AccessIndexedNode implements Canonicalizable {
+
+    /**
+     * Creates a new {@link LoadIndexedFinalNode}.
+     * 
+     * @param array the instruction producing the array
+     * @param index the instruction producing the index
+     * @param elementKind the element type
+     */
+    public LoadIndexedFinalNode(ValueNode array, ValueNode index, Kind elementKind) {
+        super(createStamp(array, elementKind), array, index, elementKind);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (array().isConstant() && !array().isNullConstant() && index().isConstant()) {
+            Object array = array().asConstant().asObject();
+            long index = index().asConstant().asLong();
+            if (index >= 0 && index < Array.getLength(array)) {
+                int arrayBaseOffset = Unsafe.getUnsafe().arrayBaseOffset(array.getClass());
+                int arrayIndexScale = Unsafe.getUnsafe().arrayIndexScale(array.getClass());
+                Constant constant = tool.runtime().readUnsafeConstant(elementKind(), array, arrayBaseOffset + index * arrayIndexScale, elementKind() == Kind.Object);
+                return ConstantNode.forConstant(constant, tool.runtime(), graph());
+            }
+        }
+        return this;
+    }
+
+    private static Stamp createStamp(ValueNode array, Kind kind) {
+        ResolvedJavaType type = ObjectStamp.typeOrNull(array);
+        if (kind == Kind.Object && type != null) {
+            return StampFactory.declared(type.getComponentType());
+        } else {
+            return StampFactory.forKind(kind);
+        }
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(createStamp(array(), elementKind()));
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        LoadIndexedNode loadIndexedNode = graph().add(new LoadIndexedNode(array(), index(), elementKind()));
+        graph().replaceFixedWithFixed(this, loadIndexedNode);
+        loadIndexedNode.lower(tool);
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -77,7 +77,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         IntegerExactArithmeticSplitNode.lower(tool, this);
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
-interface IntegerExactArithmeticNode extends Lowerable, Node.IterableNodeType {
+interface IntegerExactArithmeticNode extends Lowerable, IterableNodeType {
 
     IntegerExactArithmeticSplitNode createSplit(AbstractBeginNode next, AbstractBeginNode deopt);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,14 +22,12 @@
  */
 package com.oracle.graal.truffle.nodes.arithmetic;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.spi.Lowerable.*;
 import com.oracle.graal.nodes.type.*;
 
 public abstract class IntegerExactArithmeticSplitNode extends ControlSplitNode implements LIRGenLowerable {
@@ -82,7 +80,7 @@
     protected abstract Value generateArithmetic(LIRGeneratorTool generator);
 
     static void lower(LoweringTool tool, IntegerExactArithmeticNode node) {
-        if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
+        if (node.asNode().graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
             FloatingNode floatingNode = (FloatingNode) node;
             FixedWithNextNode previous = tool.lastFixedNode();
             FixedNode next = previous.next();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -73,7 +73,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         IntegerExactArithmeticSplitNode.lower(tool, this);
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -77,7 +77,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         IntegerExactArithmeticSplitNode.lower(tool, this);
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverInlineMacroNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverInlineMacroNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,16 +26,17 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.nodes.*;
 
-public class NeverInlineMacroNode extends MacroNode implements com.oracle.graal.graph.Node.IterableNodeType {
+public class NeverInlineMacroNode extends MacroNode implements com.oracle.graal.graph.IterableNodeType {
 
     public NeverInlineMacroNode(Invoke invoke) {
         super(invoke);
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         InvokeNode invoke = createInvoke();
         graph().replaceFixedWithFixed(this, invoke);
         invoke.setUseForInlining(false);
+        invoke.lower(tool);
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,7 +25,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.nodes.*;
 
-public class NeverPartOfCompilationNode extends MacroNode implements com.oracle.graal.graph.Node.IterableNodeType {
+public class NeverPartOfCompilationNode extends MacroNode implements com.oracle.graal.graph.IterableNodeType {
 
     private final String message;
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameAccessNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameAccessNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,7 +25,6 @@
 import java.lang.reflect.*;
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -89,7 +88,7 @@
     @Override
     public String toString(Verbosity verbosity) {
         if (verbosity == Verbosity.Name) {
-            return super.toString(verbosity) + getSlotKind().name() + (isConstantFrameSlot() ? " " + getConstantFrameSlot() : "");
+            return super.toString(verbosity) + getSlotKind().name() + (slot != null && isConstantFrameSlot() ? " " + getConstantFrameSlot() : "");
         } else {
             return super.toString(verbosity);
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameGetNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameGetNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,7 +25,6 @@
 import sun.misc.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -71,7 +70,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         assert !(getFrame() instanceof NewFrameNode);
         StructuredGraph structuredGraph = graph();
 
@@ -89,6 +88,8 @@
             loadNode = graph().add(new UnsafeLoadNode(loadFieldNode, Unsafe.ARRAY_LONG_BASE_OFFSET, slotOffset, getSlotKind()));
         }
         structuredGraph.replaceFixedWithFixed(this, loadNode);
+        loadFieldNode.lower(tool);
+        ((Lowerable) loadNode).lower(tool);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameSetNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameSetNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.truffle.nodes.frame;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -71,7 +70,7 @@
     }
 
     @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
+    public void lower(LoweringTool tool) {
         assert !(getFrame() instanceof NewFrameNode);
         StructuredGraph structuredGraph = graph();
 
@@ -87,6 +86,8 @@
             storeNode = graph().add(new StoreIndexedNode(loadFieldNode, slotIndex, Kind.Long, value));
         }
         structuredGraph.replaceFixedWithFixed(this, storeNode);
+        loadFieldNode.lower(tool);
+        ((Lowerable) storeNode).lower(tool);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.truffle.nodes.frame;
 
-import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.truffle.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -27,7 +27,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -59,7 +58,7 @@
     }
 
     public NewFrameNode(ValueNode descriptor, ValueNode caller, ValueNode arguments) {
-        this(StampFactory.declaredNonNull(FRAME_TYPE), descriptor, caller, arguments);
+        this(StampFactory.exactNonNull(FRAME_TYPE), descriptor, caller, arguments);
     }
 
     public ValueNode getDescriptor() {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomTypeCheckNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomTypeCheckNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public final class CustomTypeCheckNode extends LogicNode implements Lowerable, Virtualizable, com.oracle.graal.graph.Node.IterableNodeType {
+public final class CustomTypeCheckNode extends LogicNode implements Lowerable, Virtualizable, com.oracle.graal.graph.IterableNodeType {
 
     @Input private ValueNode condition;
     @Input private ValueNode object;
@@ -50,8 +50,8 @@
         return customType;
     }
 
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        if (loweringType == LoweringType.BEFORE_GUARDS) {
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
             this.replaceAtUsages(graph().unique(new IntegerEqualsNode(condition, ConstantNode.forInt(1, graph()))));
             this.safeDelete();
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/TypeCastNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/TypeCastNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -28,7 +28,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public final class TypeCastNode extends FixedWithNextNode implements Lowerable, com.oracle.graal.graph.Node.IterableNodeType, ValueProxy, Virtualizable {
+public final class TypeCastNode extends FixedWithNextNode implements Lowerable, com.oracle.graal.graph.IterableNodeType, ValueProxy, Virtualizable {
 
     @Input private ValueNode receiver;
     @Input private ValueNode object;
@@ -59,11 +59,11 @@
         return customType;
     }
 
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        if (loweringType == LoweringType.BEFORE_GUARDS) {
-            ValueAnchorNode valueAnchorNode = graph().add(new ValueAnchorNode());
-            UnsafeCastNode unsafeCast = graph().unique(new UnsafeCastNode(object, this.stamp(), (GuardingNode) valueAnchorNode));
-            this.replaceAtUsages(unsafeCast);
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
+            ValueAnchorNode valueAnchorNode = graph().add(new ValueAnchorNode(null));
+            PiNode piCast = graph().unique(new PiNode(object, this.stamp(), valueAnchorNode));
+            this.replaceAtUsages(piCast);
             graph().replaceFixedWithFixed(this, valueAnchorNode);
         }
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeCustomizationNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeCustomizationNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public final class UnsafeCustomizationNode extends FloatingNode implements LIRLowerable, com.oracle.graal.graph.Node.IterableNodeType {
+public final class UnsafeCustomizationNode extends FloatingNode implements LIRLowerable, com.oracle.graal.graph.IterableNodeType {
 
     @Input private ValueNode receiver;
     private final Object customType;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/InlineTrivialGettersPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +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.phases;
-
-import static com.oracle.graal.phases.GraalOptions.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
-import com.oracle.graal.truffle.*;
-
-/**
- * Inline all trivial getters (i.e. simple field loads).
- */
-public class InlineTrivialGettersPhase extends Phase {
-
-    private static final int TRIVIAL_GETTER_SIZE = 5;
-    private final MetaAccessProvider metaAccessProvider;
-    private final Assumptions assumptions;
-    private final CustomCanonicalizer customCanonicalizer;
-
-    public InlineTrivialGettersPhase(MetaAccessProvider metaAccessProvider, Assumptions assumptions, CustomCanonicalizer customCanonicalizer) {
-        this.metaAccessProvider = metaAccessProvider;
-        this.assumptions = assumptions;
-        this.customCanonicalizer = customCanonicalizer;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) {
-            if (methodCallTarget.isAlive()) {
-                InvokeKind invokeKind = methodCallTarget.invokeKind();
-                if (invokeKind == InvokeKind.Special) {
-                    ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
-                    if (methodCallTarget.receiver().isConstant() && !methodCallTarget.receiver().isNullConstant()) {
-                        if (targetMethod.getCodeSize() == TRIVIAL_GETTER_SIZE && targetMethod.getDeclaringClass().isInitialized() && targetMethod.getName().startsWith("get")) {
-                            StructuredGraph inlineGraph = new StructuredGraph(targetMethod);
-                            new GraphBuilderPhase(metaAccessProvider, GraphBuilderConfiguration.getDefault(), TruffleCompilerImpl.Optimizations).apply(inlineGraph);
-                            int mark = graph.getMark();
-                            InliningUtil.inline(methodCallTarget.invoke(), inlineGraph, false);
-                            Debug.dump(graph, "After inlining trivial getter %s", targetMethod.toString());
-                            new CanonicalizerPhase.Instance(metaAccessProvider, assumptions, !AOTCompilation.getValue(), mark, customCanonicalizer).apply(graph);
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceLoadFinalPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.phases;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.truffle.nodes.*;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.Node.Children;
+
+public class ReplaceLoadFinalPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (LoadIndexedNode loadIndexedNode : graph.getNodes(LoadIndexedNode.class)) {
+            if (loadIndexedNode.array() instanceof LoadFieldNode) {
+                LoadFieldNode loadFieldNode = (LoadFieldNode) loadIndexedNode.array();
+                if (!loadFieldNode.isStatic() && isCompilationFinal(loadFieldNode.field())) {
+                    graph.replaceFixedWithFixed(loadIndexedNode, graph.add(new LoadIndexedFinalNode(loadIndexedNode.array(), loadIndexedNode.index(), loadIndexedNode.elementKind())));
+                }
+            } else if (loadIndexedNode.array() instanceof ConstantNode) {
+                graph.replaceFixedWithFixed(loadIndexedNode, graph.add(new LoadIndexedFinalNode(loadIndexedNode.array(), loadIndexedNode.index(), loadIndexedNode.elementKind())));
+            }
+        }
+    }
+
+    private static boolean isCompilationFinal(ResolvedJavaField field) {
+        assert (field.getAnnotation(Children.class) == null && field.getAnnotation(CompilerDirectives.CompilationFinal.class) == null) || Modifier.isFinal(field.getModifiers()) : "field needs to be declared as final";
+        return Modifier.isFinal(field.getModifiers()) && (field.getAnnotation(Children.class) != null || field.getAnnotation(CompilerDirectives.CompilationFinal.class) != null);
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyNoIntrinsicsLeftPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyNoIntrinsicsLeftPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.truffle.phases;
 
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.truffle.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Wed Oct 02 13:26:31 2013 +0200
@@ -24,7 +24,6 @@
 
 import java.util.concurrent.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.truffle.substitutions;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
@@ -214,7 +213,8 @@
     }
 
     private static void verifyGet(FrameWithoutBoxing frame, FrameSlot slot, FrameSlotKind accessType) {
-        if (getTag(frame, slot) != (byte) accessType.ordinal()) {
+        byte tag = getTag(frame, slot);
+        if (accessType == FrameSlotKind.Object ? (tag & 0xfe) != 0 : tag != (byte) accessType.ordinal()) {
             DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.UnreachedCode);
         }
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Wed Oct 02 13:26:31 2013 +0200
@@ -34,6 +34,9 @@
 public class OptimizedCallTargetSubstitutions {
 
     @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
+    public static native Object callHelper(OptimizedCallTarget target, PackedFrame caller, Arguments args);
+
+    @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
     public static native Object interpreterCall(OptimizedCallTarget target, PackedFrame caller, Arguments args);
 
     @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/SlowPathExceptionSubstitutions.java	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +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.substitutions;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Deoptimize on creation of a new SlowPathException instance.
- */
-@ClassSubstitution(SlowPathException.class)
-public class SlowPathExceptionSubstitutions {
-
-    @MethodSubstitution(value = "<init>")
-    public static void init() {
-        DeoptimizeNode.deopt(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(value = "<init>")
-    public static void init(String result, Throwable cause) {
-        DeoptimizeNode.deopt(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(value = "<init>")
-    public static void init(String result) {
-        DeoptimizeNode.deopt(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(value = "<init>")
-    public static void init(Throwable cause) {
-        DeoptimizeNode.deopt(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode);
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnexpectedResultExceptionSubstitutions.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnexpectedResultExceptionSubstitutions.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.truffle.substitutions;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializedObjectState.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializedObjectState.java	Wed Oct 02 13:26:31 2013 +0200
@@ -29,7 +29,7 @@
 /**
  * This class encapsulated the materialized state of an escape analyzed object.
  */
-public final class MaterializedObjectState extends EscapeObjectState implements Node.IterableNodeType, Node.ValueNumberable {
+public final class MaterializedObjectState extends EscapeObjectState implements IterableNodeType, Node.ValueNumberable {
 
     @Input private ValueNode materializedValue;
 
@@ -44,7 +44,7 @@
 
     @Override
     public MaterializedObjectState duplicateWithVirtualState() {
-        return graph().add(new MaterializedObjectState(object(), materializedValue));
+        return graph().addWithoutUnique(new MaterializedObjectState(object(), materializedValue));
     }
 
     @Override
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java	Wed Oct 02 13:26:31 2013 +0200
@@ -31,7 +31,7 @@
 /**
  * This class encapsulated the virtual state of an escape analyzed object.
  */
-public final class VirtualObjectState extends EscapeObjectState implements Node.IterableNodeType, Node.ValueNumberable {
+public final class VirtualObjectState extends EscapeObjectState implements IterableNodeType, Node.ValueNumberable {
 
     @Input private final NodeInputList<ValueNode> fieldValues;
 
@@ -53,7 +53,7 @@
 
     @Override
     public VirtualObjectState duplicateWithVirtualState() {
-        return graph().add(new VirtualObjectState(object(), fieldValues));
+        return graph().addWithoutUnique(new VirtualObjectState(object(), fieldValues));
     }
 
     @Override
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EarlyReadEliminationPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EarlyReadEliminationPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,13 +25,14 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class EarlyReadEliminationPhase extends EffectsPhase<PhaseContext> {
 
-    public EarlyReadEliminationPhase() {
-        super(1);
+    public EarlyReadEliminationPhase(CanonicalizerPhase canonicalizer) {
+        super(1, canonicalizer);
     }
 
     @Override
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
-import static com.oracle.graal.phases.GraalOptions.*;
-
 import java.util.concurrent.*;
 
 import com.oracle.graal.debug.*;
@@ -47,9 +45,11 @@
     }
 
     private final int maxIterations;
+    private final CanonicalizerPhase canonicalizer;
 
-    public EffectsPhase(int maxIterations) {
+    public EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer) {
         this.maxIterations = maxIterations;
+        this.canonicalizer = canonicalizer;
     }
 
     @Override
@@ -90,7 +90,7 @@
                             listener.getChangedNodes().add(node);
                         }
                     }
-                    new CanonicalizerPhase.Instance(context.getRuntime(), context.getAssumptions(), !AOTCompilation.getValue(), listener.getChangedNodes(), null).apply(graph);
+                    canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
 
                     return true;
                 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Wed Oct 02 13:26:31 2013 +0200
@@ -113,7 +113,7 @@
             @Override
             public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
                 assert !node.isAlive() && !node.isDeleted() : node + " " + cause;
-                graph.add(node);
+                graph.addWithoutUnique(node);
             }
         });
     }
@@ -187,7 +187,7 @@
                         stateAfter.virtualObjectMappings().remove(i);
                     }
                 }
-                stateAfter.addVirtualObjectMapping(graph.add(state));
+                stateAfter.addVirtualObjectMapping(graph.addWithoutUnique(state));
             }
 
             @Override
@@ -328,7 +328,7 @@
             @Override
             public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
                 for (ValueNode otherAllocation : otherAllocations) {
-                    graph.add(otherAllocation);
+                    graph.addWithoutUnique(otherAllocation);
                     if (otherAllocation instanceof FixedWithNextNode) {
                         graph.addBeforeFixed(position, (FixedWithNextNode) otherAllocation);
                     } else {
@@ -344,7 +344,7 @@
                         graph.addBeforeFixed(position, commit);
                     }
                     for (AllocatedObjectNode obj : objects) {
-                        graph.add(obj);
+                        graph.addWithoutUnique(obj);
                         commit.getVirtualObjects().add(obj.getVirtualObject());
                         obj.setCommit(commit);
                     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -60,13 +60,13 @@
                 @Override
                 public Boolean call() {
                     boolean progress = false;
-                    PartialEscapePhase ea = new PartialEscapePhase(false);
+                    PartialEscapePhase ea = new PartialEscapePhase(false, canonicalizer);
                     boolean eaResult = ea.runAnalysis(graph, context);
                     progress |= eaResult;
 
                     Map<Invoke, Double> hints = PEAInliningHints.getValue() ? PartialEscapePhase.getHints(graph) : null;
 
-                    InliningPhase inlining = new InliningPhase(hints);
+                    InliningPhase inlining = new InliningPhase(hints, new CanonicalizerPhase(true));
                     inlining.setMaxMethodsPerInlining(simple ? 1 : Integer.MAX_VALUE);
                     inlining.apply(graph, context);
                     progress |= inlining.getInliningCount() > 0;
@@ -75,7 +75,7 @@
 
                     if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
                         canonicalizer.apply(graph, context);
-                        new IterativeConditionalEliminationPhase().apply(graph, context);
+                        new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context);
                     }
 
                     return progress;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Oct 02 13:26:31 2013 +0200
@@ -111,13 +111,18 @@
             return !(node instanceof CommitAllocationNode || node instanceof AllocatedObjectNode);
         }
         if (isMarked) {
-            if (node instanceof StateSplit) {
-                StateSplit split = (StateSplit) node;
-                FrameState stateAfter = split.stateAfter();
+            if (node instanceof NodeWithState) {
+                NodeWithState nodeWithState = (NodeWithState) node;
+                FrameState stateAfter = nodeWithState.getState();
                 if (stateAfter != null) {
                     if (stateAfter.usages().count() > 1) {
-                        stateAfter = (FrameState) stateAfter.copyWithInputs();
-                        split.setStateAfter(stateAfter);
+                        if (nodeWithState instanceof StateSplit) {
+                            StateSplit split = (StateSplit) nodeWithState;
+                            stateAfter = (FrameState) stateAfter.copyWithInputs();
+                            split.setStateAfter(stateAfter);
+                        } else {
+                            throw GraalInternalError.shouldNotReachHere();
+                        }
                     }
                     final HashSet<ObjectState> virtual = new HashSet<>();
                     stateAfter.applyToNonVirtual(new NodeClosure<ValueNode>() {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.virtual.phases.ea;
 
 import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.virtual.phases.ea.PartialEscapePhase.Options.*;
 
 import java.util.*;
 
@@ -33,25 +34,29 @@
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.options.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class PartialEscapePhase extends EffectsPhase<PhaseContext> {
 
-    //@formatter:off
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptEarlyReadElimination = new OptionValue<>(true);
-    //@formatter:on
+    static class Options {
+
+        //@formatter:off
+        @Option(help = "")
+        public static final OptionValue<Boolean> OptEarlyReadElimination = new OptionValue<>(true);
+        //@formatter:on
+    }
 
     private final boolean readElimination;
 
-    public PartialEscapePhase(boolean iterative) {
-        this(iterative, OptEarlyReadElimination.getValue());
+    public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer) {
+        this(iterative, OptEarlyReadElimination.getValue(), canonicalizer);
     }
 
-    public PartialEscapePhase(boolean iterative, boolean readElimination) {
-        super(iterative ? EscapeAnalysisIterations.getValue() : 1);
+    public PartialEscapePhase(boolean iterative, boolean readElimination, CanonicalizerPhase canonicalizer) {
+        super(iterative ? EscapeAnalysisIterations.getValue() : 1, canonicalizer);
         this.readElimination = readElimination;
     }
 
@@ -76,7 +81,7 @@
     public static Map<Invoke, Double> getHints(StructuredGraph graph) {
         NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply();
         Map<Invoke, Double> hints = null;
-        for (CommitAllocationNode commit : graph.getNodes(CommitAllocationNode.class)) {
+        for (CommitAllocationNode commit : graph.getNodes().filter(CommitAllocationNode.class)) {
             double sum = 0;
             double invokeSum = 0;
             for (Node commitUsage : commit.usages()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/ObjectAccess.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,936 @@
+/*
+ * Copyright (c) 2013, 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.word;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.word.Word.Opcode;
+import com.oracle.graal.word.Word.Operation;
+
+/**
+ * Low-level memory access for Objects. Similarly to the readXxx and writeXxx methods defined for
+ * {@link Pointer}, these methods access the raw memory without any null checks, read- or write
+ * barriers.
+ */
+public final class ObjectAccess {
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native byte readByte(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native char readChar(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native short readShort(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native int readInt(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native long readLong(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native float readFloat(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native double readDouble(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Word readWord(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Object readObject(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native byte readByte(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native char readChar(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native short readShort(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native int readInt(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native long readLong(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native float readFloat(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native double readDouble(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Word readWord(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Object readObject(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeByte(Object object, WordBase offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeChar(Object object, WordBase offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeShort(Object object, WordBase offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeInt(Object object, WordBase offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeLong(Object object, WordBase offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeFloat(Object object, WordBase offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeDouble(Object object, WordBase offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeWord(Object object, WordBase offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeObject(Object object, WordBase offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeByte(Object object, int offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeChar(Object object, int offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeShort(Object object, int offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeInt(Object object, int offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeLong(Object object, int offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeFloat(Object object, int offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeDouble(Object object, int offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeWord(Object object, int offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeObject(Object object, int offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native byte readByte(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native char readChar(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native short readShort(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native int readInt(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native long readLong(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native float readFloat(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native double readDouble(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Word readWord(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Object readObject(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native byte readByte(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native char readChar(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native short readShort(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native int readInt(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native long readLong(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native float readFloat(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native double readDouble(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Word readWord(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Object readObject(Object object, int offset);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeByte(Object object, WordBase offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeChar(Object object, WordBase offset, char val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeShort(Object object, WordBase offset, short val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeInt(Object object, WordBase offset, int val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeLong(Object object, WordBase offset, long val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeFloat(Object object, WordBase offset, float val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeDouble(Object object, WordBase offset, double val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeWord(Object object, WordBase offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeObject(Object object, WordBase offset, Object val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeByte(Object object, int offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeChar(Object object, int offset, char val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeShort(Object object, int offset, short val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeInt(Object object, int offset, int val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeLong(Object object, int offset, long val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeFloat(Object object, int offset, float val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeDouble(Object object, int offset, double val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeWord(Object object, int offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeObject(Object object, int offset, Object val);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, 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.word.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.word.phases.*;
+
+/**
+ * Cast between Word and Object that is introduced by the {@link WordTypeRewriterPhase}. It has an
+ * impact on the pointer maps for the GC, so it must not be scheduled or optimized away.
+ */
+public final class WordCastNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable {
+
+    public static WordCastNode wordToObject(ValueNode input, Kind wordKind) {
+        assert input.kind() == wordKind;
+        return new WordCastNode(StampFactory.object(), input);
+    }
+
+    public static WordCastNode objectToWord(ValueNode input, Kind wordKind) {
+        assert input.kind() == Kind.Object;
+        return new WordCastNode(StampFactory.forKind(wordKind), input);
+    }
+
+    @Input private ValueNode input;
+
+    private WordCastNode(Stamp stamp, ValueNode input) {
+        super(stamp);
+        this.input = input;
+    }
+
+    public ValueNode getInput() {
+        return input;
+    }
+
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (usages().count() == 0) {
+            /* If the cast is unused, it can be eliminated. */
+            return input;
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool generator) {
+        assert kind() != input.kind();
+        assert generator.target().arch.getSizeInBytes(kind()) == generator.target().arch.getSizeInBytes(input.kind());
+
+        AllocatableValue result = generator.newVariable(kind());
+        generator.emitMove(result, generator.operand(input));
+        generator.setResult(this, result);
+    }
+}
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,10 +36,10 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.util.*;
 import com.oracle.graal.word.*;
 import com.oracle.graal.word.Word.Opcode;
 import com.oracle.graal.word.Word.Operation;
+import com.oracle.graal.word.nodes.*;
 
 /**
  * Transforms all uses of the {@link Word} class into unsigned operations on {@code int} or
@@ -47,210 +47,271 @@
  */
 public class WordTypeRewriterPhase extends Phase {
 
-    private final MetaAccessProvider metaAccess;
-    private final ResolvedJavaType wordBaseType;
-    private final ResolvedJavaType wordImplType;
-    private final Kind wordKind;
+    protected final MetaAccessProvider metaAccess;
+    protected final ResolvedJavaType wordBaseType;
+    protected final ResolvedJavaType wordImplType;
+    protected final ResolvedJavaType objectAccessType;
+    protected final Kind wordKind;
 
     public WordTypeRewriterPhase(MetaAccessProvider metaAccess, Kind wordKind) {
         this.metaAccess = metaAccess;
         this.wordKind = wordKind;
         this.wordBaseType = metaAccess.lookupJavaType(WordBase.class);
         this.wordImplType = metaAccess.lookupJavaType(Word.class);
-    }
-
-    public ResolvedJavaType getWordBaseType() {
-        return wordBaseType;
-    }
-
-    public ResolvedJavaType getWordImplType() {
-        return wordImplType;
+        this.objectAccessType = metaAccess.lookupJavaType(ObjectAccess.class);
     }
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (Node n : GraphOrder.forwardGraph(graph)) {
-            if (n instanceof ValueNode && !(n instanceof PhiNode && ((PhiNode) n).isLoopPhi())) {
-                ValueNode valueNode = (ValueNode) n;
-                if (isWord(valueNode)) {
-                    changeToWord(valueNode);
-                }
-            }
-        }
-        for (PhiNode phi : graph.getNodes(PhiNode.class)) {
-            if (phi.isLoopPhi() && isWord(phi)) {
-                changeToWord(phi);
-            }
-        }
-
-        // Remove casts between different word types (which by now no longer have kind Object)
-        for (CheckCastNode checkCastNode : graph.getNodes().filter(CheckCastNode.class).snapshot()) {
-            if (!checkCastNode.isDeleted() && checkCastNode.kind() == wordKind) {
-                checkCastNode.replaceAtUsages(checkCastNode.object());
-                graph.removeFixed(checkCastNode);
-            }
-        }
-
-        // Remove unnecessary/redundant unsafe casts
-        for (UnsafeCastNode unsafeCastNode : graph.getNodes().filter(UnsafeCastNode.class).snapshot()) {
-            if (!unsafeCastNode.isDeleted() && unsafeCastNode.object().stamp() == unsafeCastNode.stamp()) {
-                graph.replaceFloating(unsafeCastNode, unsafeCastNode.object());
-            }
-        }
-
-        // Fold constant field reads (e.g. enum constants)
-        for (LoadFieldNode load : graph.getNodes(LoadFieldNode.class).snapshot()) {
-            ConstantNode constant = load.asConstant(metaAccess);
-            if (constant != null) {
-                graph.replaceFixedWithFloating(load, constant);
-            }
-        }
+        inferStamps(graph);
 
-        // Replace ObjectEqualsNodes with IntegerEqualsNodes where the values being compared are
-        // words
-        for (ObjectEqualsNode objectEqualsNode : graph.getNodes().filter(ObjectEqualsNode.class).snapshot()) {
-            ValueNode x = objectEqualsNode.x();
-            ValueNode y = objectEqualsNode.y();
-            if (x.kind() == wordKind || y.kind() == wordKind) {
-                assert x.kind() == wordKind;
-                assert y.kind() == wordKind;
-
-                // TODO Remove the whole iteration of ObjectEqualsNodes when we are sure that there
-                // is no more code where this triggers.
-                throw GraalInternalError.shouldNotReachHere("Comparison of words with == and != is no longer supported");
-            }
-        }
-
-        for (AccessIndexedNode node : graph.getNodes().filter(AccessIndexedNode.class).snapshot()) {
-            ValueNode array = node.array();
-            ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array);
-            if (arrayType == null) {
-                // There are cases where the array does not have a known type yet. Assume it is not
-                // a word type.
-                continue;
-            }
-            assert arrayType.isArray();
-            if (isWord(arrayType.getComponentType())) {
-                /*
-                 * The elementKind of the node is a final field, and other information such as the
-                 * stamp depends on elementKind. Therefore, just create a new node and replace the
-                 * old one.
-                 */
-                if (node instanceof LoadIndexedNode) {
-                    graph.replaceFixedWithFixed(node, graph.add(new LoadIndexedNode(node.array(), node.index(), wordKind)));
-                } else if (node instanceof StoreIndexedNode) {
-                    graph.replaceFixedWithFixed(node, graph.add(new StoreIndexedNode(node.array(), node.index(), wordKind, ((StoreIndexedNode) node).value())));
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
+        for (Node n : graph.getNodes()) {
+            if (n instanceof ValueNode) {
+                changeToWord(graph, (ValueNode) n);
             }
         }
 
-        for (MethodCallTargetNode callTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) {
-            ResolvedJavaMethod targetMethod = callTargetNode.targetMethod();
-            if (!callTargetNode.isStatic() && (callTargetNode.receiver().kind() == wordKind || isWord(callTargetNode.receiver()))) {
-                targetMethod = getWordImplType().resolveMethod(targetMethod);
-            }
-            Operation operation = targetMethod.getAnnotation(Word.Operation.class);
-            if (operation != null) {
-                NodeInputList<ValueNode> arguments = callTargetNode.arguments();
-                Invoke invoke = (Invoke) callTargetNode.usages().first();
-                assert invoke != null : callTargetNode.targetMethod();
-
-                switch (operation.opcode()) {
-                    case NODE_CLASS:
-                        assert arguments.size() == 2;
-                        ValueNode left = arguments.get(0);
-                        ValueNode right = operation.rightOperandIsInt() ? toUnsigned(graph, arguments.get(1), Kind.Int) : fromSigned(graph, arguments.get(1));
-                        replace(invoke, nodeClassOp(graph, operation.node(), left, right, invoke));
-                        break;
-
-                    case COMPARISON:
-                        assert arguments.size() == 2;
-                        replace(invoke, comparisonOp(graph, operation.condition(), arguments.get(0), fromSigned(graph, arguments.get(1))));
-                        break;
+        for (Node node : graph.getNodes()) {
+            rewriteNode(graph, node);
+        }
+    }
 
-                    case NOT:
-                        assert arguments.size() == 1;
-                        replace(invoke, graph.unique(new XorNode(wordKind, arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph))));
-                        break;
-
-                    case READ: {
-                        assert arguments.size() == 2 || arguments.size() == 3;
-                        Kind readKind = asKind(callTargetNode.returnType());
-                        LocationNode location;
-                        if (arguments.size() == 2) {
-                            location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION);
-                        } else {
-                            location = makeLocation(graph, arguments.get(1), readKind, arguments.get(2));
-                        }
-                        replace(invoke, readOp(graph, arguments.get(0), invoke, location, BarrierType.NONE, false));
-                        break;
-                    }
-                    case READ_HEAP: {
-                        assert arguments.size() == 4;
-                        Kind readKind = asKind(callTargetNode.returnType());
-                        LocationNode location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION);
-                        BarrierType barrierType = (BarrierType) arguments.get(2).asConstant().asObject();
-                        replace(invoke, readOp(graph, arguments.get(0), invoke, location, barrierType, arguments.get(3).asConstant().asInt() == 0 ? false : true));
-                        break;
+    /**
+     * Infer the stamps for all Object nodes in the graph, to make the stamps as precise as
+     * possible. For example, this propagates the word-type through phi functions. To handle phi
+     * functions at loop headers, the stamp inference is called until a fix point is reached.
+     * <p>
+     * Note that we cannot rely on the normal canonicalizer to propagate stamps: The word type
+     * rewriting must run before the first run of the canonicalizer because many nodes are not
+     * prepared to see the word type during canonicalization.
+     */
+    protected void inferStamps(StructuredGraph graph) {
+        boolean stampChanged;
+        do {
+            stampChanged = false;
+            /*
+             * We could use GraphOrder.forwardGraph() to process the nodes in a defined order and
+             * propagate long def-use chains in fewer iterations. However, measurements showed that
+             * we have few iterations anyway, and the overhead of computing the order is much higher
+             * than the benefit.
+             */
+            for (Node n : graph.getNodes()) {
+                if (n instanceof ValueNode) {
+                    ValueNode node = (ValueNode) n;
+                    if (node.kind() == Kind.Object) {
+                        stampChanged |= node.inferStamp();
                     }
-                    case WRITE:
-                    case INITIALIZE: {
-                        assert arguments.size() == 3 || arguments.size() == 4;
-                        Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, targetMethod.getDeclaringClass()));
-                        LocationNode location;
-                        if (arguments.size() == 3) {
-                            location = makeLocation(graph, arguments.get(1), writeKind, LocationIdentity.ANY_LOCATION);
-                        } else {
-                            location = makeLocation(graph, arguments.get(1), writeKind, arguments.get(3));
-                        }
-                        replace(invoke, writeOp(graph, arguments.get(0), arguments.get(2), invoke, location, operation.opcode()));
-                        break;
-                    }
-                    case ZERO:
-                        assert arguments.size() == 0;
-                        replace(invoke, ConstantNode.forIntegerKind(wordKind, 0L, graph));
-                        break;
+                }
+            }
+        } while (stampChanged);
+    }
+
+    /**
+     * Change the stamp for word nodes from the object stamp ({@link WordBase} or anything extending
+     * or implementing that interface) to the primitive word stamp.
+     */
+    protected void changeToWord(StructuredGraph graph, ValueNode node) {
+        if (isWord(node)) {
+            if (node.isConstant()) {
+                ConstantNode oldConstant = (ConstantNode) node;
+                assert oldConstant.value.getKind() == Kind.Object;
+                WordBase value = (WordBase) oldConstant.value.asObject();
+                ConstantNode newConstant = ConstantNode.forIntegerKind(wordKind, value.rawValue(), node.graph());
+                graph.replaceFloating(oldConstant, newConstant);
 
-                    case FROM_UNSIGNED:
-                        assert arguments.size() == 1;
-                        replace(invoke, fromUnsigned(graph, arguments.get(0)));
-                        break;
+            } else {
+                node.setStamp(StampFactory.forKind(wordKind));
+            }
+        }
+    }
+
+    /**
+     * Clean up nodes that are no longer necessary or valid after the stamp change, and perform
+     * intrinsification of all methods called on word types.
+     */
+    protected void rewriteNode(StructuredGraph graph, Node node) {
+        if (node instanceof CheckCastNode) {
+            rewriteCheckCast(graph, (CheckCastNode) node);
+        } else if (node instanceof LoadFieldNode) {
+            rewriteLoadField(graph, (LoadFieldNode) node);
+        } else if (node instanceof AccessIndexedNode) {
+            rewriteAccessIndexed(graph, (AccessIndexedNode) node);
+        } else if (node instanceof MethodCallTargetNode) {
+            rewriteInvoke(graph, (MethodCallTargetNode) node);
+        }
+    }
 
-                    case FROM_SIGNED:
-                        assert arguments.size() == 1;
-                        replace(invoke, fromSigned(graph, arguments.get(0)));
-                        break;
+    /**
+     * Remove casts between word types (which by now no longer have kind Object).
+     */
+    protected void rewriteCheckCast(StructuredGraph graph, CheckCastNode node) {
+        if (node.kind() == wordKind) {
+            node.replaceAtUsages(node.object());
+            graph.removeFixed(node);
+        }
+    }
 
-                    case TO_RAW_VALUE:
-                        assert arguments.size() == 1;
-                        replace(invoke, toUnsigned(graph, arguments.get(0), Kind.Long));
-                        break;
+    /**
+     * Fold constant field reads, e.g. enum constants.
+     */
+    protected void rewriteLoadField(StructuredGraph graph, LoadFieldNode node) {
+        ConstantNode constant = node.asConstant(metaAccess);
+        if (constant != null) {
+            node.replaceAtUsages(constant);
+            graph.removeFixed(node);
+        }
+    }
 
-                    case FROM_OBJECT:
-                        assert arguments.size() == 1;
-                        replace(invoke, graph.unique(new UnsafeCastNode(arguments.get(0), StampFactory.forKind(wordKind))));
-                        break;
-
-                    case FROM_ARRAY:
-                        assert arguments.size() == 2;
-                        replace(invoke, graph.unique(new ComputeAddressNode(arguments.get(0), arguments.get(1), StampFactory.forKind(wordKind))));
-                        break;
-
-                    case TO_OBJECT:
-                        assert arguments.size() == 1;
-                        replace(invoke, graph.unique(new UnsafeCastNode(arguments.get(0), invoke.asNode().stamp())));
-                        break;
-
-                    default:
-                        throw new GraalInternalError("Unknown opcode: %s", operation.opcode());
-                }
+    /**
+     * Change loads and stores of word-arrays. Since the element kind is managed by the node on its
+     * own and not in the stamp, {@link #changeToWord} does not perform all necessary changes.
+     */
+    protected void rewriteAccessIndexed(StructuredGraph graph, AccessIndexedNode node) {
+        ResolvedJavaType arrayType = ObjectStamp.typeOrNull(node.array());
+        /*
+         * There are cases where the array does not have a known type yet, i.e., the type is null.
+         * In that case we assume it is not a word type.
+         */
+        if (arrayType != null && isWord(arrayType.getComponentType()) && node.elementKind() != wordKind) {
+            /*
+             * The elementKind of the node is a final field, and other information such as the stamp
+             * depends on elementKind. Therefore, just create a new node and replace the old one.
+             */
+            if (node instanceof LoadIndexedNode) {
+                graph.replaceFixedWithFixed(node, graph.add(new LoadIndexedNode(node.array(), node.index(), wordKind)));
+            } else if (node instanceof StoreIndexedNode) {
+                graph.replaceFixedWithFixed(node, graph.add(new StoreIndexedNode(node.array(), node.index(), wordKind, ((StoreIndexedNode) node).value())));
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
             }
         }
     }
 
-    private ValueNode fromUnsigned(StructuredGraph graph, ValueNode value) {
+    /**
+     * Intrinsification of methods defined on the {@link Word} class that are annotated with
+     * {@link Operation}.
+     */
+    protected void rewriteInvoke(StructuredGraph graph, MethodCallTargetNode callTargetNode) {
+        ResolvedJavaMethod targetMethod = callTargetNode.targetMethod();
+        if (!wordBaseType.isAssignableFrom(targetMethod.getDeclaringClass()) && !objectAccessType.equals(targetMethod.getDeclaringClass())) {
+            /*
+             * Not a method defined on WordBase or a subclass / subinterface, and not on
+             * ObjectAccess, so nothing to rewrite.
+             */
+            return;
+        }
+
+        if (!callTargetNode.isStatic()) {
+            assert callTargetNode.receiver().kind() == wordKind : "changeToWord() missed the receiver";
+            targetMethod = wordImplType.resolveMethod(targetMethod);
+        }
+        Operation operation = targetMethod.getAnnotation(Word.Operation.class);
+        assert operation != null : targetMethod;
+
+        NodeInputList<ValueNode> arguments = callTargetNode.arguments();
+        Invoke invoke = callTargetNode.invoke();
+
+        switch (operation.opcode()) {
+            case NODE_CLASS:
+                assert arguments.size() == 2;
+                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));
+                if (replacement instanceof FixedWithNextNode) {
+                    graph.addBeforeFixed(invoke.asNode(), (FixedWithNextNode) replacement);
+                }
+                replace(invoke, replacement);
+                break;
+
+            case COMPARISON:
+                assert arguments.size() == 2;
+                replace(invoke, comparisonOp(graph, operation.condition(), arguments.get(0), fromSigned(graph, arguments.get(1))));
+                break;
+
+            case NOT:
+                assert arguments.size() == 1;
+                replace(invoke, graph.unique(new XorNode(wordKind, arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph))));
+                break;
+
+            case READ: {
+                assert arguments.size() == 2 || arguments.size() == 3;
+                Kind readKind = asKind(callTargetNode.returnType());
+                LocationNode location;
+                if (arguments.size() == 2) {
+                    location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION);
+                } else {
+                    location = makeLocation(graph, arguments.get(1), readKind, arguments.get(2));
+                }
+                replace(invoke, readOp(graph, arguments.get(0), invoke, location, BarrierType.NONE, false));
+                break;
+            }
+            case READ_HEAP: {
+                assert arguments.size() == 4;
+                Kind readKind = asKind(callTargetNode.returnType());
+                LocationNode location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION);
+                BarrierType barrierType = (BarrierType) arguments.get(2).asConstant().asObject();
+                replace(invoke, readOp(graph, arguments.get(0), invoke, location, barrierType, arguments.get(3).asConstant().asInt() == 0 ? false : true));
+                break;
+            }
+            case WRITE:
+            case INITIALIZE: {
+                assert arguments.size() == 3 || arguments.size() == 4;
+                Kind writeKind = asKind(targetMethod.getSignature().getParameterType(Modifier.isStatic(targetMethod.getModifiers()) ? 2 : 1, targetMethod.getDeclaringClass()));
+                LocationNode location;
+                if (arguments.size() == 3) {
+                    location = makeLocation(graph, arguments.get(1), writeKind, LocationIdentity.ANY_LOCATION);
+                } else {
+                    location = makeLocation(graph, arguments.get(1), writeKind, arguments.get(3));
+                }
+                replace(invoke, writeOp(graph, arguments.get(0), arguments.get(2), invoke, location, operation.opcode()));
+                break;
+            }
+            case ZERO:
+                assert arguments.size() == 0;
+                replace(invoke, ConstantNode.forIntegerKind(wordKind, 0L, graph));
+                break;
+
+            case FROM_UNSIGNED:
+                assert arguments.size() == 1;
+                replace(invoke, fromUnsigned(graph, arguments.get(0)));
+                break;
+
+            case FROM_SIGNED:
+                assert arguments.size() == 1;
+                replace(invoke, fromSigned(graph, arguments.get(0)));
+                break;
+
+            case TO_RAW_VALUE:
+                assert arguments.size() == 1;
+                replace(invoke, toUnsigned(graph, arguments.get(0), Kind.Long));
+                break;
+
+            case FROM_OBJECT:
+                assert arguments.size() == 1;
+                WordCastNode objectToWord = graph.add(WordCastNode.objectToWord(arguments.get(0), wordKind));
+                graph.addBeforeFixed(invoke.asNode(), objectToWord);
+                replace(invoke, objectToWord);
+                break;
+
+            case FROM_ARRAY:
+                assert arguments.size() == 2;
+                replace(invoke, graph.unique(new ComputeAddressNode(arguments.get(0), arguments.get(1), StampFactory.forKind(wordKind))));
+                break;
+
+            case TO_OBJECT:
+                assert arguments.size() == 1;
+                WordCastNode wordToObject = graph.add(WordCastNode.wordToObject(arguments.get(0), wordKind));
+                graph.addBeforeFixed(invoke.asNode(), wordToObject);
+                replace(invoke, wordToObject);
+                break;
+
+            default:
+                throw new GraalInternalError("Unknown opcode: %s", operation.opcode());
+        }
+    }
+
+    protected ValueNode fromUnsigned(StructuredGraph graph, ValueNode value) {
         return convert(graph, value, wordKind, ConvertNode.Op.L2I, ConvertNode.Op.UNSIGNED_I2L);
     }
 
@@ -258,7 +319,7 @@
         return convert(graph, value, wordKind, ConvertNode.Op.L2I, ConvertNode.Op.I2L);
     }
 
-    private static ValueNode toUnsigned(StructuredGraph graph, ValueNode value, Kind toKind) {
+    protected ValueNode toUnsigned(StructuredGraph graph, ValueNode value, Kind toKind) {
         return convert(graph, value, toKind, ConvertNode.Op.L2I, ConvertNode.Op.UNSIGNED_I2L);
     }
 
@@ -279,14 +340,15 @@
         }
     }
 
-    private ValueNode nodeClassOp(StructuredGraph graph, Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right, Invoke invoke) {
+    /**
+     * Create an instance of a binary node which is used to lower Word operations. This method is
+     * 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) {
         try {
             Constructor<? extends ValueNode> constructor = nodeClass.getConstructor(Kind.class, ValueNode.class, ValueNode.class);
-            ValueNode result = graph.add(constructor.newInstance(wordKind, left, right));
-            if (result instanceof FixedWithNextNode) {
-                graph.addBeforeFixed(invoke.asNode(), (FixedWithNextNode) result);
-            }
-            return result;
+            return constructor.newInstance(kind, left, right);
         } catch (Throwable ex) {
             throw new GraalInternalError(ex).addContext(nodeClass.getName());
         }
@@ -329,20 +391,22 @@
         return SnippetLocationNode.create(locationIdentity, ConstantNode.forObject(readKind, metaAccess, graph), ConstantNode.forLong(0, graph), offset, ConstantNode.forInt(1, graph), graph);
     }
 
-    private static LocationNode makeLocation(StructuredGraph graph, ValueNode offset, Kind readKind, LocationIdentity locationIdentity) {
+    protected LocationNode makeLocation(StructuredGraph graph, ValueNode offset, Kind readKind, LocationIdentity locationIdentity) {
         return IndexedLocationNode.create(locationIdentity, readKind, 0, offset, graph, 1);
     }
 
-    private static ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, BarrierType barrierType, boolean compressible) {
+    protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, BarrierType barrierType, boolean compressible) {
         ReadNode read = graph.add(new ReadNode(base, location, invoke.asNode().stamp(), barrierType, compressible));
         graph.addBeforeFixed(invoke.asNode(), read);
-        // The read must not float outside its block otherwise it may float above an explicit zero
-        // check on its base address
+        /*
+         * The read must not float outside its block otherwise it may float above an explicit zero
+         * check on its base address.
+         */
         read.setGuard(AbstractBeginNode.prevBegin(invoke.asNode()));
         return read;
     }
 
-    private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode value, Invoke invoke, LocationNode location, Opcode op) {
+    protected ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode value, Invoke invoke, LocationNode location, Opcode op) {
         assert op == Opcode.WRITE || op == Opcode.INITIALIZE;
         WriteNode write = graph.add(new WriteNode(base, value, location, BarrierType.NONE, false, op == Opcode.INITIALIZE));
         write.setStateAfter(invoke.stateAfter());
@@ -350,7 +414,7 @@
         return write;
     }
 
-    private static void replace(Invoke invoke, ValueNode value) {
+    protected void replace(Invoke invoke, ValueNode value) {
         FixedNode next = invoke.next();
         invoke.setNext(null);
         invoke.asNode().replaceAtPredecessor(next);
@@ -358,52 +422,19 @@
         GraphUtil.killCFG(invoke.asNode());
     }
 
-    public boolean isWord(ValueNode node) {
-        /*
-         * If we already know that we have a word type, we do not need to infer the stamp. This
-         * avoids exceptions in inferStamp when the inputs have already been rewritten to word,
-         * i.e., when the expected input is no longer an object.
-         */
-        if (isWord0(node)) {
-            return true;
-        }
-        node.inferStamp();
-        return isWord0(node);
-    }
-
-    private boolean isWord0(ValueNode node) {
-        if (node.stamp() == StampFactory.forWord()) {
-            return true;
-        }
-        if (node.stamp() instanceof ObjectStamp) {
-            return isWord(((ObjectStamp) node.stamp()).type());
-        }
-        return false;
+    protected boolean isWord(ValueNode node) {
+        return isWord(ObjectStamp.typeOrNull(node));
     }
 
-    public boolean isWord(ResolvedJavaType type) {
-        if (type != null && wordBaseType.isAssignableFrom(type)) {
-            return true;
-        }
-        return false;
+    protected boolean isWord(ResolvedJavaType type) {
+        return type != null && wordBaseType.isAssignableFrom(type);
     }
 
-    public Kind asKind(JavaType type) {
-        if (type instanceof ResolvedJavaType) {
-            return isWord((ResolvedJavaType) type) ? wordKind : type.getKind();
+    protected Kind asKind(JavaType type) {
+        if (type instanceof ResolvedJavaType && isWord((ResolvedJavaType) type)) {
+            return wordKind;
         } else {
-            return Kind.Object;
-        }
-    }
-
-    private void changeToWord(ValueNode valueNode) {
-        if (valueNode.isConstant() && valueNode.asConstant().getKind() == Kind.Object) {
-            WordBase value = (WordBase) valueNode.asConstant().asObject();
-            ConstantNode newConstant = ConstantNode.forIntegerKind(wordKind, value.rawValue(), valueNode.graph());
-            valueNode.graph().replaceFloating((ConstantNode) valueNode, newConstant);
-        } else {
-            assert !(valueNode instanceof ConstantNode) : "boxed Word constants should not appear in a snippet graph: " + valueNode + ", stamp: " + valueNode.stamp();
-            valueNode.setStamp(StampFactory.forKind(wordKind));
+            return type.getKind();
         }
     }
 }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Wed Oct 02 13:26:31 2013 +0200
@@ -36,8 +36,8 @@
 import com.oracle.graal.word.Word.Operation;
 
 /**
- * Verifies invariants that must hold for snippet code above and beyond normal bytecode
- * verification.
+ * Verifies invariants that must hold for code that uses the {@link WordBase word type} above and
+ * beyond normal bytecode verification.
  */
 public class WordTypeVerificationPhase extends Phase {
 
@@ -49,6 +49,17 @@
 
     @Override
     protected void run(StructuredGraph graph) {
+        assert verify(graph);
+    }
+
+    protected boolean verify(StructuredGraph inputGraph) {
+        /*
+         * This is a verification phase, so we do not want to have side effects. Since inferStamps()
+         * modifies the stamp of nodes, we copy the graph before running the verification.
+         */
+        StructuredGraph graph = inputGraph.copy();
+        wordAccess.inferStamps(graph);
+
         for (ValueNode node : graph.getNodes().filter(ValueNode.class)) {
             for (Node usage : node.usages()) {
                 if (usage instanceof AccessMonitorNode) {
@@ -70,32 +81,7 @@
                     verify(!isWord(node) || ((StoreIndexedNode) usage).value() != node, node, usage, "cannot store word value to array");
                 } else if (usage instanceof MethodCallTargetNode) {
                     MethodCallTargetNode callTarget = (MethodCallTargetNode) usage;
-                    ResolvedJavaMethod method = callTarget.targetMethod();
-                    if (method.getAnnotation(NodeIntrinsic.class) == null) {
-                        Invoke invoke = (Invoke) callTarget.usages().first();
-                        NodeInputList<ValueNode> arguments = callTarget.arguments();
-                        boolean isStatic = Modifier.isStatic(method.getModifiers());
-                        int argc = 0;
-                        if (!isStatic) {
-                            ValueNode receiver = arguments.get(argc);
-                            if (receiver == node && isWord(node)) {
-                                ResolvedJavaMethod resolvedMethod = wordAccess.getWordImplType().resolveMethod(method);
-                                verify(resolvedMethod != null, node, invoke.asNode(), "cannot resolve method on Word class: " + MetaUtil.format("%H.%n(%P) %r", method));
-                                Operation operation = resolvedMethod.getAnnotation(Word.Operation.class);
-                                verify(operation != null, node, invoke.asNode(), "cannot dispatch on word value to non @Operation annotated method " + resolvedMethod);
-                            }
-                            argc++;
-                        }
-                        Signature signature = method.getSignature();
-                        for (int i = 0; i < signature.getParameterCount(false); i++) {
-                            ValueNode argument = arguments.get(argc);
-                            if (argument == node) {
-                                ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass());
-                                verify(isWord(type) == isWord(argument), node, invoke.asNode(), "cannot pass word value to non-word parameter " + i + " or vice-versa");
-                            }
-                            argc++;
-                        }
-                    }
+                    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");
@@ -111,19 +97,39 @@
                 }
             }
         }
+        return true;
+    }
+
+    protected void verifyInvoke(ValueNode node, MethodCallTargetNode callTarget) {
+        ResolvedJavaMethod method = callTarget.targetMethod();
+        if (method.getAnnotation(NodeIntrinsic.class) == null) {
+            Invoke invoke = (Invoke) callTarget.usages().first();
+            NodeInputList<ValueNode> arguments = callTarget.arguments();
+            boolean isStatic = Modifier.isStatic(method.getModifiers());
+            int argc = 0;
+            if (!isStatic) {
+                ValueNode receiver = arguments.get(argc);
+                if (receiver == node && isWord(node)) {
+                    ResolvedJavaMethod resolvedMethod = wordAccess.wordImplType.resolveMethod(method);
+                    verify(resolvedMethod != null, node, invoke.asNode(), "cannot resolve method on Word class: " + MetaUtil.format("%H.%n(%P) %r", method));
+                    Operation operation = resolvedMethod.getAnnotation(Word.Operation.class);
+                    verify(operation != null, node, invoke.asNode(), "cannot dispatch on word value to non @Operation annotated method " + resolvedMethod);
+                }
+                argc++;
+            }
+            Signature signature = method.getSignature();
+            for (int i = 0; i < signature.getParameterCount(false); i++) {
+                ValueNode argument = arguments.get(argc);
+                if (argument == node) {
+                    ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass());
+                    verify(isWord(type) == isWord(argument), node, invoke.asNode(), "cannot pass word value to non-word parameter " + i + " or vice-versa");
+                }
+                argc++;
+            }
+        }
     }
 
     private boolean isWord(ValueNode node) {
-        if (node instanceof ProxyNode) {
-            /*
-             * The proxy node will eventually get the same stamp as the value it is proxying.
-             * However, since we cannot guarantee the order in which isWord is called during the
-             * verification phase, the stamp assignment for the value might not have happened yet.
-             * Therefore, we check the proxied value directly instead of the proxy.
-             */
-            return isWord(((ProxyNode) node).value());
-        }
-
         return wordAccess.isWord(node);
     }
 
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -116,7 +116,7 @@
                     // fall through
                 }
             }
-            FrameUtil.setObjectSafe(frame, slot, o);
+            frame.setObject(slot, o);
             this.replace(new ObjectAssignLocal(slot, value));
             return null;
         }
@@ -134,11 +134,7 @@
         @Override
         Object execute(VirtualFrame frame) {
             Object o = value.execute(frame);
-            try {
-                frame.setObject(slot, o);
-            } catch (FrameSlotTypeException e) {
-                FrameUtil.setObjectSafe(frame, slot, o);
-            }
+            frame.setObject(slot, o);
             return null;
         }
     }
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java	Wed Oct 02 13:26:31 2013 +0200
@@ -120,11 +120,11 @@
                 try {
                     frame.setInt(slot, result);
                 } catch (FrameSlotTypeException e) {
-                    FrameUtil.setObjectSafe(frame, slot, result);
+                    frame.setObject(slot, result);
                     replace(new ObjectAssignLocal(slot, value));
                 }
             } catch (UnexpectedResultException e) {
-                FrameUtil.setObjectSafe(frame, slot, e.getResult());
+                frame.setObject(slot, e.getResult());
                 replace(new ObjectAssignLocal(slot, value));
             }
             return null;
@@ -143,11 +143,7 @@
         @Override
         Object execute(VirtualFrame frame) {
             Object o = value.execute(frame);
-            try {
-                frame.setObject(slot, o);
-            } catch (FrameSlotTypeException e) {
-                FrameUtil.setObjectSafe(frame, slot, o);
-            }
+            frame.setObject(slot, o);
             return null;
         }
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Wed Oct 02 13:26:31 2013 +0200
@@ -25,75 +25,30 @@
 package com.oracle.truffle.api;
 
 /**
- * Represents a contiguous text section within the source code of a guest language program.
+ * Description of contiguous text section within the source code of a guest language program.
  */
-public class 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.
-     * <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 SourceSection(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 interface SourceSection {
 
     /**
      * Returns the object representing the source program that contains this section.
      * 
      * @return the source object
      */
-    public final Source getSource() {
-        return source;
-    }
+    Source getSource();
 
     /**
      * Returns 1-based line number of the first character in this source section (inclusive).
      * 
      * @return the starting line number
      */
-    public final int getStartLine() {
-        return startLine;
-    }
+    int getStartLine();
 
     /**
      * Returns the 1-based column number of the first character in this source section (inclusive).
      * 
      * @return the starting column number
      */
-    public final int getStartColumn() {
-        return startColumn;
-    }
+    int getStartColumn();
 
     /**
      * Returns the 0-based index of the first character in this source section.
@@ -103,9 +58,7 @@
      * 
      * @return the starting character index
      */
-    public final int getCharIndex() {
-        return charIndex;
-    }
+    int getCharIndex();
 
     /**
      * Returns the length of this source section in characters.
@@ -115,85 +68,28 @@
      * 
      * @return the number of characters in the section
      */
-    public final int getCharLength() {
-        return charLength;
-    }
+    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 the identifier of this source section that is used for printing the section.
      * 
      * @return the identifier of the section
      */
-    public final String getIdentifier() {
-        return identifier;
-    }
+    String getIdentifier();
 
     /**
      * Returns text of the code represented by this source section.
      * 
      * @return the code as a String object
      */
-    public final String getCode() {
-        return getSource().getCode().substring(charIndex, charIndex + charLength);
-    }
-
-    @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 SourceSection)) {
-            return false;
-        }
-        SourceSection other = (SourceSection) 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;
-    }
+    String getCode();
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java	Wed Oct 02 13:26:31 2013 +0200
@@ -64,7 +64,7 @@
      * @param slot the slot of the local variable
      * @param value the new value of the local variable
      */
-    void setObject(FrameSlot slot, Object value) throws FrameSlotTypeException;
+    void setObject(FrameSlot slot, Object value);
 
     /**
      * Read access to a local variable of type byte.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java	Wed Oct 02 13:26:31 2013 +0200
@@ -39,6 +39,7 @@
     private final ArrayList<FrameSlotImpl> slots;
     private final HashMap<Object, FrameSlotImpl> identifierToSlotMap;
     private Assumption version;
+    private HashMap<Object, Assumption> identifierToNotInFrameAssumptionMap;
 
     public FrameDescriptor() {
         this(DefaultFrameTypeConversion.getInstance());
@@ -61,6 +62,7 @@
         slots.add(slot);
         identifierToSlotMap.put(identifier, slot);
         updateVersion();
+        invalidateNotInFrameAssumption(identifier);
         return slot;
     }
 
@@ -93,7 +95,7 @@
     }
 
     /**
-     * (db) to retrieve the list of all the identifiers associated with this frame descriptor.
+     * Retrieve the list of all the identifiers associated with this frame descriptor.
      * 
      * @return the list of all the identifiers in this frame descriptor
      */
@@ -133,4 +135,32 @@
     public FrameTypeConversion getTypeConversion() {
         return typeConversion;
     }
+
+    public Assumption getNotInFrameAssumption(Object identifier) {
+        if (identifierToSlotMap.containsKey(identifier)) {
+            throw new IllegalArgumentException("Cannot get not-in-frame assumption for existing frame slot!");
+        }
+
+        if (identifierToNotInFrameAssumptionMap == null) {
+            identifierToNotInFrameAssumptionMap = new HashMap<>();
+        } else {
+            Assumption assumption = identifierToNotInFrameAssumptionMap.get(identifier);
+            if (assumption != null) {
+                return assumption;
+            }
+        }
+        Assumption assumption = Truffle.getRuntime().createAssumption("not in frame: " + identifier);
+        identifierToNotInFrameAssumptionMap.put(identifier, assumption);
+        return assumption;
+    }
+
+    private void invalidateNotInFrameAssumption(Object identifier) {
+        if (identifierToNotInFrameAssumptionMap != null) {
+            Assumption assumption = identifierToNotInFrameAssumptionMap.get(identifier);
+            if (assumption != null) {
+                assumption.invalidate();
+                identifierToNotInFrameAssumptionMap.remove(identifier);
+            }
+        }
+    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotImpl.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotImpl.java	Wed Oct 02 13:26:31 2013 +0200
@@ -51,9 +51,10 @@
     }
 
     public void setKind(final FrameSlotKind kind) {
-        assert this.kind != kind;
-        this.kind = kind;
-        this.descriptor.updateVersion();
+        if (this.kind != kind) {
+            this.kind = kind;
+            this.descriptor.updateVersion();
+        }
     }
 
     @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java	Wed Oct 02 13:26:31 2013 +0200
@@ -35,14 +35,7 @@
      * @param value the new value of the local variable
      */
     public static void setObjectSafe(Frame frame, FrameSlot slot, Object value) {
-        if (slot.getKind() != FrameSlotKind.Object) {
-            slot.setKind(FrameSlotKind.Object);
-        }
-        try {
-            frame.setObject(slot, value);
-        } catch (FrameSlotTypeException e) {
-            throw new IllegalStateException();
-        }
+        frame.setObject(slot, value);
     }
 
     /**
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractAssumption.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractAssumption.java	Wed Oct 02 13:26:31 2013 +0200
@@ -43,6 +43,6 @@
 
     @Override
     public String toString() {
-        return "Assumption: " + name;
+        return "Assumption(valid=" + isValid + "): " + name;
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultFrameTypeConversion.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultFrameTypeConversion.java	Wed Oct 02 13:26:31 2013 +0200
@@ -40,7 +40,7 @@
 
     @Override
     public void updateFrameSlot(Frame frame, FrameSlot slot, Object value) {
-        FrameUtil.setObjectSafe(frame, slot, value);
+        frame.setObject(slot, value);
     }
 
     public static DefaultFrameTypeConversion getInstance() {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java	Wed Oct 02 13:26:31 2013 +0200
@@ -46,7 +46,7 @@
     }
 
     @Override
-    public void setObject(FrameSlot slot, Object value) throws FrameSlotTypeException {
+    public void setObject(FrameSlot slot, Object value) {
         wrapped.setObject(slot, value);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,164 @@
+/*
+ * 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.impl;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Represents a contiguous text section within the source code of a guest language program.
+ */
+public 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;
+    }
+
+    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);
+    }
+
+    @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 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;
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Wed Oct 02 13:26:31 2013 +0200
@@ -42,6 +42,7 @@
         this.caller = caller;
         this.arguments = arguments;
         this.locals = new Object[descriptor.getSize()];
+        Arrays.fill(locals, descriptor.getTypeConversion().getDefaultValue());
         this.tags = new byte[descriptor.getSize()];
     }
 
@@ -73,8 +74,8 @@
     }
 
     @Override
-    public void setObject(FrameSlot slot, Object value) throws FrameSlotTypeException {
-        verifySet(slot, FrameSlotKind.Object);
+    public void setObject(FrameSlot slot, Object value) {
+        verifySetObject(slot);
         locals[slot.getIndex()] = value;
     }
 
@@ -157,17 +158,11 @@
 
     @Override
     public Object getValue(FrameSlot slot) {
-        int index = slot.getIndex();
-        if (index >= tags.length) {
-            assert index >= 0 && index < descriptor.getSize();
-            return descriptor.getTypeConversion().getDefaultValue();
+        int slotIndex = slot.getIndex();
+        if (slotIndex >= tags.length) {
+            resize();
         }
-        byte tag = tags[index];
-        if (tag == FrameSlotKind.Illegal.ordinal()) {
-            return descriptor.getTypeConversion().getDefaultValue();
-        } else {
-            return locals[index];
-        }
+        return locals[slotIndex];
     }
 
     private void verifySet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException {
@@ -186,45 +181,50 @@
         tags[slotIndex] = (byte) accessKind.ordinal();
     }
 
-    private void verifyGet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException {
-        FrameSlotKind slotKind = slot.getKind();
-        if (slotKind != accessKind) {
-            if (slotKind == FrameSlotKind.Illegal && accessKind == FrameSlotKind.Object) {
-                slot.setKind(FrameSlotKind.Object);
-                this.setObject(slot, descriptor.getTypeConversion().getDefaultValue());
-            } else {
-                throw new FrameSlotTypeException();
-            }
+    private void verifySetObject(FrameSlot slot) {
+        if (slot.getKind() != FrameSlotKind.Object) {
+            slot.setKind(FrameSlotKind.Object);
         }
         int slotIndex = slot.getIndex();
         if (slotIndex >= tags.length) {
             resize();
         }
-        if (tags[slotIndex] != accessKind.ordinal()) {
-            descriptor.getTypeConversion().updateFrameSlot(this, slot, getValue(slot));
-            if (tags[slotIndex] != accessKind.ordinal()) {
-                throw new FrameSlotTypeException();
+        tags[slotIndex] = (byte) FrameSlotKind.Object.ordinal();
+    }
+
+    private void verifyGet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException {
+        int slotIndex = slot.getIndex();
+        if (slotIndex >= tags.length) {
+            resize();
+        }
+        byte tag = tags[slotIndex];
+        if (accessKind == FrameSlotKind.Object ? (tag & 0xfe) != 0 : tag != accessKind.ordinal()) {
+            if (slot.getKind() == accessKind || tag == 0) {
+                descriptor.getTypeConversion().updateFrameSlot(this, slot, getValue(slot));
+                if (tags[slotIndex] == accessKind.ordinal()) {
+                    return;
+                }
             }
+            throw new FrameSlotTypeException();
         }
     }
 
     private void resize() {
+        int oldSize = tags.length;
         int newSize = descriptor.getSize();
-        if (newSize > tags.length) {
+        if (newSize > oldSize) {
             locals = Arrays.copyOf(locals, newSize);
+            Arrays.fill(locals, oldSize, newSize, descriptor.getTypeConversion().getDefaultValue());
             tags = Arrays.copyOf(tags, newSize);
         }
     }
 
     @Override
     public boolean isInitialized(FrameSlot slot) {
-        try {
-            return tags[slot.getIndex()] != 0;
-        } catch (ArrayIndexOutOfBoundsException ex) {
-            if (slot.getIndex() >= 0 && slot.getIndex() < descriptor.getSize()) {
-                return false;
-            }
-            throw ex;
+        int slotIndex = slot.getIndex();
+        if (slotIndex >= tags.length) {
+            resize();
         }
+        return tags[slotIndex] != 0;
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Wed Oct 02 13:26:31 2013 +0200
@@ -218,8 +218,10 @@
                 }
             }
             setNodeProperty(node, "class", node.getClass().getSimpleName());
-            readNodeProperties((Node) node);
-            copyDebugProperties(node);
+            if (node instanceof Node) {
+                readNodeProperties((Node) node);
+                copyDebugProperties((Node) node);
+            }
         }
     }
 
@@ -252,12 +254,10 @@
         propElem.setTextContent(String.valueOf(value));
     }
 
-    private void copyDebugProperties(Object node) {
-        if (node instanceof Node) {
-            Map<String, Object> debugProperties = ((Node) node).getDebugProperties();
-            for (Map.Entry<String, Object> property : debugProperties.entrySet()) {
-                setNodeProperty(node, property.getKey(), property.getValue());
-            }
+    private void copyDebugProperties(Node node) {
+        Map<String, Object> debugProperties = node.getDebugProperties();
+        for (Map.Entry<String, Object> property : debugProperties.entrySet()) {
+            setNodeProperty(node, property.getKey(), property.getValue());
         }
     }
 
@@ -274,7 +274,7 @@
         }
     }
 
-    protected void connectNodes(Object a, Object b) {
+    protected void connectNodes(Object a, Object b, String label) {
         if (nodeMap.get(a) == null || nodeMap.get(b) == null) {
             return;
         }
@@ -294,6 +294,9 @@
         edgeElem.setAttribute("from", fromId);
         edgeElem.setAttribute("to", toId);
         edgeElem.setAttribute("index", String.valueOf(count));
+        if (label != null) {
+            edgeElem.setAttribute("label", label);
+        }
         edgesElement.appendChild(edgeElem);
         edgeList.add(edgeElem);
     }
@@ -304,45 +307,60 @@
         }
 
         // if node is visited once again, skip
-        if (getElementByObject(node) == null || NodeUtil.findAnnotation(node.getClass(), GraphDuplicate.class) != null) {
-            visitAny(node);
+        if (getElementByObject(node) != null && NodeUtil.findAnnotation(node.getClass(), GraphDuplicate.class) == null) {
+            return this;
+        }
+
+        // respect node's custom handler
+        if (NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class) != null) {
+            Class<? extends GraphPrintHandler> customHandlerClass = NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class).handler();
+            try {
+                GraphPrintHandler customHandler = customHandlerClass.newInstance();
+                customHandler.visit(node, new GraphPrintAdapter());
+            } catch (InstantiationException | IllegalAccessException e) {
+                assert false : e;
+            }
+        } else if (NodeUtil.findAnnotation(node.getClass(), NullGraphPrintHandler.class) != null) {
+            // ignore
+        } else {
+            // default handler
+            createElementForNode(node);
+
+            if (node instanceof Node) {
+                for (Map.Entry<String, Node> child : findNamedNodeChildren((Node) node).entrySet()) {
+                    visit(child.getValue());
+                    connectNodes(node, child.getValue(), child.getKey());
+                }
+            }
         }
 
         return this;
     }
 
-    private void visitAny(Object node) {
-        // respect node's custom handler
-        if (NodeUtil.findAnnotation(node.getClass(), NullGraphPrintHandler.class) != null) {
-            return;
-        }
-        if (NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class) != null) {
-            Class<? extends GraphPrintHandler> gpHandlerClass = NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class).handler();
-            try {
-                GraphPrintHandler gpHandler = gpHandlerClass.newInstance();
-                gpHandler.visit(node, new GraphPrintAdapter());
-            } catch (InstantiationException e) {
-                assert false;
-            } catch (IllegalAccessException e) {
-                assert false;
+    private static LinkedHashMap<String, Node> findNamedNodeChildren(Node node) {
+        LinkedHashMap<String, Node> nodes = new LinkedHashMap<>();
+        NodeClass nodeClass = NodeClass.get(node.getClass());
+
+        for (NodeField field : nodeClass.getFields()) {
+            NodeFieldKind kind = field.getKind();
+            if (kind == NodeFieldKind.CHILD || kind == NodeFieldKind.CHILDREN) {
+                Object value = field.loadValue(node);
+                if (value != null) {
+                    if (kind == NodeFieldKind.CHILD) {
+                        nodes.put(field.getName(), (Node) value);
+                    } else if (kind == NodeFieldKind.CHILDREN) {
+                        Object[] children = (Object[]) value;
+                        for (int i = 0; i < children.length; i++) {
+                            if (children[i] != null) {
+                                nodes.put(field.getName() + "[" + i + "]", (Node) children[i]);
+                            }
+                        }
+                    }
+                }
             }
-            return;
         }
 
-        // default handler
-        createElementForNode(node);
-
-        List<Node> children = NodeUtil.findNodeChildren((Node) node);
-        for (Object child : children) {
-            if (child == null) {
-                continue;
-            } else if (child instanceof Node) {
-                visit(child);
-            } else {
-                continue;
-            }
-            connectNodes(node, child);
-        }
+        return nodes;
     }
 
     public class GraphPrintAdapter {
@@ -356,7 +374,7 @@
         }
 
         public void connectNodes(Object node, Object child) {
-            GraphPrintVisitor.this.connectNodes(node, child);
+            GraphPrintVisitor.this.connectNodes(node, child, null);
         }
 
         public void setNodeProperty(Object node, String propertyName, Object value) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Wed Oct 02 13:26:31 2013 +0200
@@ -71,7 +71,12 @@
      */
     public final void assignSourceSection(SourceSection section) {
         if (sourceSection != null) {
-            throw new IllegalStateException("Source section is already assigned.");
+            // Patch this test during the transition to constructor-based
+            // source attribution, which would otherwise trigger this
+            // exception. This method will eventually be deprecated.
+            if (getSourceSection() != section) {
+                throw new IllegalStateException("Source section is already assigned. Old: " + getSourceSection() + ", new: " + section);
+            }
         }
         this.sourceSection = section;
     }
@@ -97,6 +102,7 @@
      * 
      * @return the assigned source code section
      */
+    @CompilerDirectives.SlowPath
     public final SourceSection getEncapsulatingSourceSection() {
         if (sourceSection == null && getParent() != null) {
             return getParent().getEncapsulatingSourceSection();
@@ -169,7 +175,7 @@
         if (this.getParent() == null) {
             throw new IllegalStateException("This node cannot be replaced, because it does not yet have a parent.");
         }
-        if (sourceSection != null) {
+        if (sourceSection != null && newNode.getSourceSection() == null) {
             // Pass on the source section to the new node.
             newNode.assignSourceSection(sourceSection);
         }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Wed Oct 02 13:26:31 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -31,13 +31,14 @@
 
 import sun.misc.*;
 
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.Node.Child;
 import com.oracle.truffle.api.nodes.Node.Children;
 
 /**
  * Utility class that manages the special access methods for node instances.
  */
-public class NodeUtil {
+public final class NodeUtil {
 
     /**
      * Interface that allows the customization of field offsets used for {@link Unsafe} field
@@ -274,7 +275,7 @@
         return array;
     }
 
-    protected static final Unsafe unsafe = getUnsafe();
+    private static final Unsafe unsafe = getUnsafe();
 
     private static Unsafe getUnsafe() {
         try {
@@ -292,12 +293,8 @@
 
     @SuppressWarnings("unchecked")
     public static <T extends Node> T cloneNode(T orig) {
-        Class<? extends Node> clazz = orig.getClass();
-        NodeClass nodeClass = NodeClass.get(clazz);
-        Node clone = orig.copy();
-        if (clone == null) {
-            return null;
-        }
+        final Node clone = orig.copy();
+        NodeClass nodeClass = NodeClass.get(clone.getClass());
 
         unsafe.putObject(clone, nodeClass.parentOffset, null);
 
@@ -305,10 +302,6 @@
             Node child = (Node) unsafe.getObject(orig, fieldOffset);
             if (child != null) {
                 Node clonedChild = cloneNode(child);
-                if (clonedChild == null) {
-                    return null;
-                }
-
                 unsafe.putObject(clonedChild, nodeClass.parentOffset, clone);
                 unsafe.putObject(clone, fieldOffset, clonedChild);
             }
@@ -316,16 +309,13 @@
         for (long fieldOffset : nodeClass.childrenOffsets) {
             Node[] children = (Node[]) unsafe.getObject(orig, fieldOffset);
             if (children != null) {
-                Node[] clonedChildren = children.clone();
-                Arrays.fill(clonedChildren, null);
+                Node[] clonedChildren = (Node[]) Array.newInstance(children.getClass().getComponentType(), children.length);
                 for (int i = 0; i < children.length; i++) {
-                    Node clonedChild = cloneNode(children[i]);
-                    if (clonedChild == null) {
-                        return null;
+                    if (children[i] != null) {
+                        Node clonedChild = cloneNode(children[i]);
+                        clonedChildren[i] = clonedChild;
+                        unsafe.putObject(clonedChild, nodeClass.parentOffset, clone);
                     }
-
-                    clonedChildren[i] = clonedChild;
-                    unsafe.putObject(clonedChild, nodeClass.parentOffset, clone);
                 }
                 unsafe.putObject(clone, fieldOffset, clonedChildren);
             }
@@ -364,6 +354,7 @@
             if (unsafe.getObject(parent, fieldOffset) == oldChild) {
                 assert assertAssignable(nodeClass, fieldOffset, newChild);
                 unsafe.putObject(parent, fieldOffset, newChild);
+                return;
             }
         }
 
@@ -376,6 +367,7 @@
                     if (array[i] == oldChild) {
                         assert assertAssignable(nodeClass, fieldOffset, newChild);
                         array[i] = newChild;
+                        return;
                     }
                 }
             }
@@ -423,6 +415,24 @@
         return result;
     }
 
+    /**
+     * Get the nth parent of a node, where the 0th parent is the node itself. Returns null if there
+     * are less than n ancestors.
+     */
+    public static Node getNthParent(Node node, int n) {
+        Node parent = node;
+
+        for (int i = 0; i < n; i++) {
+            parent = parent.getParent();
+
+            if (parent == null) {
+                return null;
+            }
+        }
+
+        return parent;
+    }
+
     /** find annotation in class/interface hierarchy. */
     public static <T extends Annotation> T findAnnotation(Class<?> clazz, Class<T> annotationClass) {
         if (clazz.getAnnotation(annotationClass) != null) {
@@ -628,6 +638,66 @@
         p.flush();
     }
 
+    public static String printSourceAttributionTree(Node node) {
+        StringWriter out = new StringWriter();
+        printSourceAttributionTree(new PrintWriter(out), null, node, 1);
+        return out.toString();
+    }
+
+    public static void printSourceAttributionTree(OutputStream out, Node node) {
+        printSourceAttributionTree(new PrintWriter(out), null, node, 1);
+    }
+
+    private static void printSourceAttributionTree(PrintWriter p, Node parent, Node node, int level) {
+        if (node == null) {
+            return;
+        }
+        if (parent == null) {
+            // Add some preliminary information before starting with the root node
+            final SourceSection sourceSection = node.getSourceSection();
+            if (sourceSection != null) {
+                final String txt = sourceSection.getSource().getCode();
+                p.println("Full source len=(" + txt.length() + ")  txt=___" + txt + "___");
+                p.println("AST source attribution:");
+            }
+        }
+        final StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < level; i++) {
+            sb.append("| ");
+        }
+
+        if (parent != null) {
+            String childName = "";
+            NodeField[] fields = NodeClass.get(parent.getClass()).fields;
+            for (NodeField field : fields) {
+                Object value = field.loadValue(parent);
+                if (value == node) {
+                    childName = field.getName();
+                    break;
+                } else if (value instanceof Node[]) {
+                    int index = 0;
+                    for (Node arrayNode : (Node[]) value) {
+                        if (arrayNode == node) {
+                            childName = field.getName() + "[" + index + "]";
+                            break;
+                        }
+                        index++;
+                    }
+                }
+            }
+            sb.append(childName);
+        }
+
+        sb.append("  (" + node.getClass().getSimpleName() + ")  ");
+        sb.append(displaySourceAttribution(node));
+        p.println(sb.toString());
+
+        for (Node child : node.getChildren()) {
+            printSourceAttributionTree(p, node, child, level + 1);
+        }
+        p.flush();
+    }
+
     /**
      * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This
      * print method does not check for cycles in the node structure.
@@ -715,4 +785,17 @@
     private static String nodeName(Node node) {
         return node.getClass().getSimpleName();
     }
+
+    private static String displaySourceAttribution(Node node) {
+        final SourceSection section = node.getSourceSection();
+        if (section != null) {
+            final String srcText = section.getCode();
+            final StringBuilder sb = new StringBuilder();
+            sb.append("source:  len=" + srcText.length());
+            sb.append(" (" + section.getCharIndex() + "," + (section.getCharEndIndex() - 1) + ")");
+            sb.append(" txt=___" + srcText + "___");
+            return sb.toString();
+        }
+        return "";
+    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java	Wed Oct 02 13:26:31 2013 +0200
@@ -35,7 +35,7 @@
     private final Object result;
 
     /**
-     * Creates the exception with the alternative result that cannot be respresented as a value of
+     * Creates the exception with the alternative result that cannot be represented as a value of
      * the return type.
      * 
      * @param result the alternative result
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Wed Oct 02 13:26:31 2013 +0200
@@ -56,6 +56,7 @@
     private final TypeMirror compilerDirectives;
     private final TypeMirror compilerAsserts;
     private final DeclaredType slowPath;
+    private final DeclaredType sourceSection;
     private final DeclaredType truffleOptions;
     private final TypeElement expectError;
 
@@ -75,6 +76,7 @@
         nodeInfoAnnotation = getRequired(context, NodeInfo.class);
         nodeInfoKind = getRequired(context, NodeInfo.Kind.class);
         slowPath = getRequired(context, SlowPath.class);
+        sourceSection = getRequired(context, SourceSection.class);
         truffleOptions = getRequired(context, TruffleOptions.class);
         expectError = (TypeElement) getRequired(context, ExpectError.class).asElement();
     }
@@ -158,4 +160,8 @@
     public DeclaredType getSlowPath() {
         return slowPath;
     }
+
+    public DeclaredType getSourceSection() {
+        return sourceSection;
+    }
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Wed Oct 02 13:26:31 2013 +0200
@@ -1102,15 +1102,19 @@
 
         private void createConstructors(NodeData node, CodeTypeElement clazz) {
             List<ExecutableElement> constructors = findUserConstructors(node.getNodeType());
+            ExecutableElement sourceSectionConstructor = null;
             if (constructors.isEmpty()) {
                 clazz.add(createUserConstructor(clazz, null));
             } else {
                 for (ExecutableElement constructor : constructors) {
                     clazz.add(createUserConstructor(clazz, constructor));
+                    if (NodeParser.isSourceSectionConstructor(context, constructor)) {
+                        sourceSectionConstructor = constructor;
+                    }
                 }
             }
             if (node.needsRewrites(getContext())) {
-                clazz.add(createCopyConstructor(clazz, findCopyConstructor(node.getNodeType())));
+                clazz.add(createCopyConstructor(clazz, findCopyConstructor(node.getNodeType()), sourceSectionConstructor));
             }
         }
 
@@ -1181,31 +1185,15 @@
             return builder.getRoot();
         }
 
-        private CodeTree createCopyArray(CodeTreeBuilder parent, NodeChildData child, TypeMirror arrayType, CodeBlock<String> accessElement) {
-            CodeTreeBuilder builder = parent.create();
-            NodeData node = getModel().getNode();
-            builder.string("new ").type(arrayType).string(" {");
-            builder.startCommaGroup();
-            for (ActualParameter parameter : getModel().getParameters()) {
-                NodeChildData foundChild = node.findChild(parameter.getSpecification().getName());
-                if (foundChild == child) {
-                    builder.startGroup();
-                    builder.tree(accessElement.create(builder, String.valueOf(parameter.getIndex())));
-                    builder.end();
-                }
-            }
-            builder.end();
-            builder.end().string("}");
-            return builder.getRoot();
-        }
-
-        private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor) {
+        private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor, ExecutableElement sourceSectionConstructor) {
             CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString());
             CodeTreeBuilder builder = method.createBuilder();
             method.getParameters().add(new CodeVariableElement(type.asType(), "copy"));
 
             if (superConstructor != null) {
                 builder.startStatement().startSuperCall().string("copy").end().end();
+            } else if (sourceSectionConstructor != null) {
+                builder.startStatement().startSuperCall().string("copy.getSourceSection()").end().end();
             }
 
             for (VariableElement var : type.getFields()) {
@@ -1213,18 +1201,11 @@
                 final String varName = var.getSimpleName().toString();
                 final TypeMirror varType = var.asType();
 
-                final String copyAccess = "copy." + varName;
-                CodeTree init = CodeTreeBuilder.singleString(copyAccess);
-                if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) {
-                    NodeChildData child = getModel().getNode().findChild(varName);
-                    init = createCopyArray(builder, child, varType, new CodeBlock<String>() {
-
-                        public CodeTree create(CodeTreeBuilder parent, String index) {
-                            return CodeTreeBuilder.singleString(copyAccess + "[" + index + "]");
-                        }
-                    });
+                String copyAccess = "copy." + varName;
+                if (Utils.isAssignable(getContext(), varType, getContext().getTruffleTypes().getNodeArray())) {
+                    copyAccess += ".clone()";
                 }
-                init = createAdoptChild(builder, varType, init);
+                CodeTree init = createAdoptChild(builder, varType, CodeTreeBuilder.singleString(copyAccess));
                 builder.startStatement().string("this.").string(varName).string(" = ").tree(init).end();
             }
             if (getModel().getNode().isPolymorphic()) {
@@ -1492,7 +1473,7 @@
                     guardsAnd = " && ";
                 }
 
-                CodeTree cast = createCast(castBuilder, child, valueParam, typeGuard.getType(), minimumState);
+                CodeTree cast = createCast(castBuilder, child, valueParam, typeGuard.getType(), checkMinimumState);
                 if (cast != null) {
                     castBuilder.tree(cast);
                 }
@@ -1605,7 +1586,7 @@
             return builder.getRoot();
         }
 
-        private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType, boolean minimumState) {
+        private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType, boolean checkMinimumState) {
             NodeData node = field.getNodeData();
             TypeData sourceType = source.getTypeSystemType();
 
@@ -1632,7 +1613,7 @@
 
             CodeTreeBuilder builder = parent.create();
             builder.tree(createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, value));
-            if (minimumState && types.size() > 1) {
+            if (checkMinimumState && types.size() > 1) {
                 CodeTree castType = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.getImplicitClass(targetType), CodeTreeBuilder.singleString(valueName(source)));
                 builder.tree(createLazyAssignment(builder, typeName(source), getContext().getType(Class.class), condition, castType));
             }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java	Wed Oct 02 13:26:31 2013 +0200
@@ -1052,7 +1052,7 @@
 
         boolean parametersFound = false;
         for (ExecutableElement constructor : constructors) {
-            if (!constructor.getParameters().isEmpty()) {
+            if (!constructor.getParameters().isEmpty() && !isSourceSectionConstructor(context, constructor)) {
                 parametersFound = true;
             }
         }
@@ -1077,6 +1077,10 @@
         nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type));
     }
 
+    static boolean isSourceSectionConstructor(ProcessorContext context, ExecutableElement constructor) {
+        return constructor.getParameters().size() == 1 && Utils.typeEquals(constructor.getParameters().get(0).asType(), context.getTruffleTypes().getSourceSection());
+    }
+
     private static boolean verifySpecializationParameters(NodeData nodeData) {
         boolean valid = true;
         int args = -1;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemParser.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemParser.java	Wed Oct 02 13:26:31 2013 +0200
@@ -108,7 +108,6 @@
             cast.getTargetType().addTypeCast(cast);
         }
 
-        verifyImplicitCasts(typeSystem);
         verifyGenericTypeChecksAndCasts(typeSystem);
         verifyMethodSignatures(typeSystem);
         verifyNamesUnique(typeSystem);
@@ -116,24 +115,6 @@
         return typeSystem;
     }
 
-    private static void verifyImplicitCasts(TypeSystemData typeSystem) {
-        Set<TypeData> types = new HashSet<>();
-        Set<TypeData> duplicateSourceTypes = new HashSet<>();
-        for (ImplicitCastData cast : typeSystem.getImplicitCasts()) {
-            if (types.contains(cast.getSourceType())) {
-                duplicateSourceTypes.add(cast.getSourceType());
-            }
-            types.add(cast.getSourceType());
-        }
-        for (TypeData duplicateType : duplicateSourceTypes) {
-            for (ImplicitCastData cast : typeSystem.getImplicitCasts()) {
-                if (cast.getSourceType().equals(duplicateType)) {
-                    cast.addError("Duplicate cast source type %s.", Utils.getSimpleName(duplicateType.getPrimitiveType()), ImplicitCast.class.getSimpleName());
-                }
-            }
-        }
-    }
-
     private static void verifyGenericTypeChecksAndCasts(TypeSystemData typeSystem) {
         for (TypeData type : typeSystem.getTypes()) {
             if (!type.getTypeChecks().isEmpty()) {
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadLocalNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadLocalNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -50,7 +50,7 @@
         try {
             return frame.getObject(slot);
         } catch (FrameSlotTypeException e) {
-            throw new RuntimeException("uninitialized variable " + slot.getIdentifier());
+            throw new IllegalStateException();
         }
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -50,11 +50,7 @@
 
     @Specialization
     public Object writeGeneric(VirtualFrame frame, Object right) {
-        try {
-            frame.setObject(slot, right);
-        } catch (FrameSlotTypeException e) {
-            FrameUtil.setObjectSafe(frame, slot, right);
-        }
+        frame.setObject(slot, right);
         return right;
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Wed Oct 02 13:26:31 2013 +0200
@@ -32,11 +32,11 @@
 // Checkstyle: stop
 // @formatter:off
 public class Parser {
-	public static final int _EOF = 0;
-	public static final int _identifier = 1;
-	public static final int _stringLiteral = 2;
-	public static final int _numericLiteral = 3;
-	public static final int maxT = 28;
+	public static final int _EOF = 0;
+	public static final int _identifier = 1;
+	public static final int _stringLiteral = 2;
+	public static final int _numericLiteral = 3;
+	public static final int maxT = 28;
 
     static final boolean T = true;
     static final boolean x = false;
@@ -120,255 +120,255 @@
         }
     }
 
-	void SimpleLanguage() {
-		Function();
-		while (la.kind == 4) {
-			Function();
-		}
-	}
-
-	void Function() {
-		Expect(4);
-		factory.startFunction(); 
-		Expect(1);
-		String name = t.val; 
-		StatementNode body = Block();
-		factory.createFunction(body, name); 
-	}
-
-	StatementNode  Block() {
-		StatementNode  result;
-		List<StatementNode> statements = new ArrayList<>(); 
-		Expect(5);
-		while (StartOf(1)) {
-			StatementNode statement = Statement();
-			statements.add(statement); 
-		}
-		Expect(6);
-		result = factory.createBlock(statements); 
-		return result;
-	}
-
-	StatementNode  Statement() {
-		StatementNode  result;
-		result = null; 
-		if (la.kind == 7) {
-			result = WhileStatement();
-		} else if (la.kind == 1) {
-			result = AssignmentStatement();
-		} else if (la.kind == 12) {
-			result = OutputStatement();
-		} else if (la.kind == 13) {
-			result = ReturnStatement();
-		} else SynErr(29);
-		return result;
-	}
-
-	StatementNode  WhileStatement() {
-		StatementNode  result;
-		Expect(7);
-		Expect(8);
-		ConditionNode condition = Expression();
-		Expect(9);
-		StatementNode body = Block();
-		result = factory.createWhile(condition, body); 
-		return result;
-	}
-
-	StatementNode  AssignmentStatement() {
-		StatementNode  result;
-		Expect(1);
-		String name = t.val; 
-		Expect(10);
-		TypedNode rvalue = Expression();
-		Expect(11);
-		result = factory.createAssignment(name, rvalue); 
-		return result;
-	}
-
-	StatementNode  OutputStatement() {
-		StatementNode  result;
-		List<TypedNode> expressions = new ArrayList<>(); 
-		Expect(12);
-		while (StartOf(2)) {
-			TypedNode value = Expression();
-			expressions.add(value); 
-		}
-		Expect(11);
-		result = factory.createPrint(expressions); 
-		return result;
-	}
-
-	StatementNode  ReturnStatement() {
-		StatementNode  result;
-		Expect(13);
-		TypedNode value = Expression();
-		Expect(11);
-		result = factory.createReturn(value); 
-		return result;
-	}
-
-	TypedNode  Expression() {
-		TypedNode  result;
-		result = ValueExpression();
-		if (StartOf(3)) {
-			switch (la.kind) {
-			case 14: {
-				Get();
-				break;
-			}
-			case 15: {
-				Get();
-				break;
-			}
-			case 16: {
-				Get();
-				break;
-			}
-			case 17: {
-				Get();
-				break;
-			}
-			case 18: {
-				Get();
-				break;
-			}
-			case 19: {
-				Get();
-				break;
-			}
-			}
-			String op = t.val; 
-			TypedNode right = ValueExpression();
-			result = factory.createBinary(op, result, right); 
-		}
-		return result;
-	}
-
-	TypedNode  ValueExpression() {
-		TypedNode  result;
-		result = Term();
-		while (la.kind == 20 || la.kind == 21) {
-			if (la.kind == 20) {
-				Get();
-			} else {
-				Get();
-			}
-			String op = t.val; 
-			TypedNode right = Term();
-			result = factory.createBinary(op, result, right); 
-		}
-		return result;
-	}
-
-	TypedNode  Term() {
-		TypedNode  result;
-		result = Factor();
-		while (la.kind == 22 || la.kind == 23) {
-			if (la.kind == 22) {
-				Get();
-			} else {
-				Get();
-			}
-			String op = t.val; 
-			TypedNode right = Factor();
-			result = factory.createBinary(op, result, right); 
-		}
-		return result;
-	}
-
-	TypedNode  Factor() {
-		TypedNode  result;
-		result = null; 
-		switch (la.kind) {
-		case 27: {
-			result = TimeRef();
-			break;
-		}
-		case 1: {
-			result = VariableRef();
-			break;
-		}
-		case 2: {
-			result = StringLiteral();
-			break;
-		}
-		case 3: {
-			result = NumericLiteral();
-			break;
-		}
-		case 24: {
-			result = Ternary();
-			break;
-		}
-		case 8: {
-			Get();
-			result = Expression();
-			Expect(9);
-			break;
-		}
-		default: SynErr(30); break;
-		}
-		return result;
-	}
-
-	TypedNode  TimeRef() {
-		TypedNode  result;
-		Expect(27);
-		result = factory.createTime(); 
-		return result;
-	}
-
-	TypedNode  VariableRef() {
-		TypedNode  result;
-		Expect(1);
-		result = factory.createLocal(t.val); 
-		return result;
-	}
-
-	TypedNode  StringLiteral() {
-		TypedNode  result;
-		Expect(2);
-		result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1)); 
-		return result;
-	}
-
-	TypedNode  NumericLiteral() {
-		TypedNode  result;
-		Expect(3);
-		result = factory.createNumericLiteral(t.val); 
-		return result;
-	}
-
-	TypedNode  Ternary() {
-		TypedNode  result;
-		TypedNode condition, thenPart, elsePart; 
-		Expect(24);
-		condition = Expression();
-		Expect(25);
-		thenPart = Expression();
-		Expect(26);
-		elsePart = Expression();
-		result = factory.createTernary(condition, thenPart, elsePart); 
-		return result;
-	}
-
+	void SimpleLanguage() {
+		Function();
+		while (la.kind == 4) {
+			Function();
+		}
+	}
+
+	void Function() {
+		Expect(4);
+		factory.startFunction(); 
+		Expect(1);
+		String name = t.val; 
+		StatementNode body = Block();
+		factory.createFunction(body, name); 
+	}
+
+	StatementNode  Block() {
+		StatementNode  result;
+		List<StatementNode> statements = new ArrayList<>(); 
+		Expect(5);
+		while (StartOf(1)) {
+			StatementNode statement = Statement();
+			statements.add(statement); 
+		}
+		Expect(6);
+		result = factory.createBlock(statements); 
+		return result;
+	}
+
+	StatementNode  Statement() {
+		StatementNode  result;
+		result = null; 
+		if (la.kind == 7) {
+			result = WhileStatement();
+		} else if (la.kind == 1) {
+			result = AssignmentStatement();
+		} else if (la.kind == 12) {
+			result = OutputStatement();
+		} else if (la.kind == 13) {
+			result = ReturnStatement();
+		} else SynErr(29);
+		return result;
+	}
+
+	StatementNode  WhileStatement() {
+		StatementNode  result;
+		Expect(7);
+		Expect(8);
+		ConditionNode condition = Expression();
+		Expect(9);
+		StatementNode body = Block();
+		result = factory.createWhile(condition, body); 
+		return result;
+	}
+
+	StatementNode  AssignmentStatement() {
+		StatementNode  result;
+		Expect(1);
+		String name = t.val; 
+		Expect(10);
+		TypedNode rvalue = Expression();
+		Expect(11);
+		result = factory.createAssignment(name, rvalue); 
+		return result;
+	}
+
+	StatementNode  OutputStatement() {
+		StatementNode  result;
+		List<TypedNode> expressions = new ArrayList<>(); 
+		Expect(12);
+		while (StartOf(2)) {
+			TypedNode value = Expression();
+			expressions.add(value); 
+		}
+		Expect(11);
+		result = factory.createPrint(expressions); 
+		return result;
+	}
+
+	StatementNode  ReturnStatement() {
+		StatementNode  result;
+		Expect(13);
+		TypedNode value = Expression();
+		Expect(11);
+		result = factory.createReturn(value); 
+		return result;
+	}
+
+	TypedNode  Expression() {
+		TypedNode  result;
+		result = ValueExpression();
+		if (StartOf(3)) {
+			switch (la.kind) {
+			case 14: {
+				Get();
+				break;
+			}
+			case 15: {
+				Get();
+				break;
+			}
+			case 16: {
+				Get();
+				break;
+			}
+			case 17: {
+				Get();
+				break;
+			}
+			case 18: {
+				Get();
+				break;
+			}
+			case 19: {
+				Get();
+				break;
+			}
+			}
+			String op = t.val; 
+			TypedNode right = ValueExpression();
+			result = factory.createBinary(op, result, right); 
+		}
+		return result;
+	}
+
+	TypedNode  ValueExpression() {
+		TypedNode  result;
+		result = Term();
+		while (la.kind == 20 || la.kind == 21) {
+			if (la.kind == 20) {
+				Get();
+			} else {
+				Get();
+			}
+			String op = t.val; 
+			TypedNode right = Term();
+			result = factory.createBinary(op, result, right); 
+		}
+		return result;
+	}
+
+	TypedNode  Term() {
+		TypedNode  result;
+		result = Factor();
+		while (la.kind == 22 || la.kind == 23) {
+			if (la.kind == 22) {
+				Get();
+			} else {
+				Get();
+			}
+			String op = t.val; 
+			TypedNode right = Factor();
+			result = factory.createBinary(op, result, right); 
+		}
+		return result;
+	}
+
+	TypedNode  Factor() {
+		TypedNode  result;
+		result = null; 
+		switch (la.kind) {
+		case 27: {
+			result = TimeRef();
+			break;
+		}
+		case 1: {
+			result = VariableRef();
+			break;
+		}
+		case 2: {
+			result = StringLiteral();
+			break;
+		}
+		case 3: {
+			result = NumericLiteral();
+			break;
+		}
+		case 24: {
+			result = Ternary();
+			break;
+		}
+		case 8: {
+			Get();
+			result = Expression();
+			Expect(9);
+			break;
+		}
+		default: SynErr(30); break;
+		}
+		return result;
+	}
+
+	TypedNode  TimeRef() {
+		TypedNode  result;
+		Expect(27);
+		result = factory.createTime(); 
+		return result;
+	}
+
+	TypedNode  VariableRef() {
+		TypedNode  result;
+		Expect(1);
+		result = factory.createLocal(t.val); 
+		return result;
+	}
+
+	TypedNode  StringLiteral() {
+		TypedNode  result;
+		Expect(2);
+		result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1)); 
+		return result;
+	}
+
+	TypedNode  NumericLiteral() {
+		TypedNode  result;
+		Expect(3);
+		result = factory.createNumericLiteral(t.val); 
+		return result;
+	}
+
+	TypedNode  Ternary() {
+		TypedNode  result;
+		TypedNode condition, thenPart, elsePart; 
+		Expect(24);
+		condition = Expression();
+		Expect(25);
+		thenPart = Expression();
+		Expect(26);
+		elsePart = Expression();
+		result = factory.createTernary(condition, thenPart, elsePart); 
+		return result;
+	}
+
 
 
     public void Parse() {
         la = new Token();
         la.val = "";
         Get();
-		SimpleLanguage();
-		Expect(0);
+		SimpleLanguage();
+		Expect(0);
 
     }
 
     private static final boolean[][] set = {
-		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
-		{x,T,x,x, x,x,x,T, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
-		{x,T,T,T, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, x,x},
-		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x}
+		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+		{x,T,x,x, x,x,x,T, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+		{x,T,T,T, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, x,x},
+		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x}
 
     };
 
@@ -416,37 +416,37 @@
 
     public void SynErr(int line, int col, int n) {
         String s;
-        switch (n) {
-			case 0: s = "EOF expected"; break;
-			case 1: s = "identifier expected"; break;
-			case 2: s = "stringLiteral expected"; break;
-			case 3: s = "numericLiteral expected"; break;
-			case 4: s = "\"function\" expected"; break;
-			case 5: s = "\"{\" expected"; break;
-			case 6: s = "\"}\" expected"; break;
-			case 7: s = "\"while\" expected"; break;
-			case 8: s = "\"(\" expected"; break;
-			case 9: s = "\")\" expected"; break;
-			case 10: s = "\"=\" expected"; break;
-			case 11: s = "\";\" expected"; break;
-			case 12: s = "\"print\" expected"; break;
-			case 13: s = "\"return\" expected"; break;
-			case 14: s = "\"<\" expected"; break;
-			case 15: s = "\">\" expected"; break;
-			case 16: s = "\"<=\" expected"; break;
-			case 17: s = "\">=\" expected"; break;
-			case 18: s = "\"==\" expected"; break;
-			case 19: s = "\"!=\" expected"; break;
-			case 20: s = "\"+\" expected"; break;
-			case 21: s = "\"-\" expected"; break;
-			case 22: s = "\"*\" expected"; break;
-			case 23: s = "\"/\" expected"; break;
-			case 24: s = "\"#\" expected"; break;
-			case 25: s = "\"?\" expected"; break;
-			case 26: s = "\":\" expected"; break;
-			case 27: s = "\"time\" expected"; break;
-			case 28: s = "??? expected"; break;
-			case 29: s = "invalid Statement"; break;
+        switch (n) {
+			case 0: s = "EOF expected"; break;
+			case 1: s = "identifier expected"; break;
+			case 2: s = "stringLiteral expected"; break;
+			case 3: s = "numericLiteral expected"; break;
+			case 4: s = "\"function\" expected"; break;
+			case 5: s = "\"{\" expected"; break;
+			case 6: s = "\"}\" expected"; break;
+			case 7: s = "\"while\" expected"; break;
+			case 8: s = "\"(\" expected"; break;
+			case 9: s = "\")\" expected"; break;
+			case 10: s = "\"=\" expected"; break;
+			case 11: s = "\";\" expected"; break;
+			case 12: s = "\"print\" expected"; break;
+			case 13: s = "\"return\" expected"; break;
+			case 14: s = "\"<\" expected"; break;
+			case 15: s = "\">\" expected"; break;
+			case 16: s = "\"<=\" expected"; break;
+			case 17: s = "\">=\" expected"; break;
+			case 18: s = "\"==\" expected"; break;
+			case 19: s = "\"!=\" expected"; break;
+			case 20: s = "\"+\" expected"; break;
+			case 21: s = "\"-\" expected"; break;
+			case 22: s = "\"*\" expected"; break;
+			case 23: s = "\"/\" expected"; break;
+			case 24: s = "\"#\" expected"; break;
+			case 25: s = "\"?\" expected"; break;
+			case 26: s = "\":\" expected"; break;
+			case 27: s = "\"time\" expected"; break;
+			case 28: s = "??? expected"; break;
+			case 29: s = "invalid Statement"; break;
 			case 30: s = "invalid Factor"; break;
             default:
                 s = "error " + n;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java	Wed Oct 02 13:26:31 2013 +0200
@@ -21,7 +21,7 @@
  * questions.
  */
 
-// The content of this file is automatically generated. DO NOT EDIT.
+ // The content of this file is automatically generated. DO NOT EDIT.
 
 package com.oracle.truffle.sl.parser;
 
@@ -518,66 +518,66 @@
                 } // NextCh already done
 				case 1:
 					recEnd = pos; recKind = 1;
-					if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;}
+					if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;}
 					else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
 				case 2:
-					if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 2; break;}
-					else if (ch == '"') {AddCh(); state = 3; break;}
+					if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 2; break;}
+					else if (ch == '"') {AddCh(); state = 3; break;}
 					else {state = 0; break;}
-				case 3:
+				case 3:
 					{t.kind = 2; break loop;}
 				case 4:
 					recEnd = pos; recKind = 3;
-					if (ch >= '0' && ch <= '9') {AddCh(); state = 4; break;}
+					if (ch >= '0' && ch <= '9') {AddCh(); state = 4; break;}
 					else {t.kind = 3; break loop;}
-				case 5:
+				case 5:
 					{t.kind = 3; break loop;}
-				case 6:
+				case 6:
 					{t.kind = 5; break loop;}
-				case 7:
+				case 7:
 					{t.kind = 6; break loop;}
-				case 8:
+				case 8:
 					{t.kind = 8; break loop;}
-				case 9:
+				case 9:
 					{t.kind = 9; break loop;}
-				case 10:
+				case 10:
 					{t.kind = 11; break loop;}
-				case 11:
+				case 11:
 					{t.kind = 16; break loop;}
-				case 12:
+				case 12:
 					{t.kind = 17; break loop;}
-				case 13:
+				case 13:
 					{t.kind = 18; break loop;}
 				case 14:
-					if (ch == '=') {AddCh(); state = 15; break;}
+					if (ch == '=') {AddCh(); state = 15; break;}
 					else {state = 0; break;}
-				case 15:
+				case 15:
 					{t.kind = 19; break loop;}
-				case 16:
+				case 16:
 					{t.kind = 20; break loop;}
-				case 17:
+				case 17:
 					{t.kind = 21; break loop;}
-				case 18:
+				case 18:
 					{t.kind = 22; break loop;}
-				case 19:
+				case 19:
 					{t.kind = 23; break loop;}
-				case 20:
+				case 20:
 					{t.kind = 24; break loop;}
-				case 21:
+				case 21:
 					{t.kind = 25; break loop;}
-				case 22:
+				case 22:
 					{t.kind = 26; break loop;}
 				case 23:
 					recEnd = pos; recKind = 10;
-					if (ch == '=') {AddCh(); state = 13; break;}
+					if (ch == '=') {AddCh(); state = 13; break;}
 					else {t.kind = 10; break loop;}
 				case 24:
 					recEnd = pos; recKind = 14;
-					if (ch == '=') {AddCh(); state = 11; break;}
+					if (ch == '=') {AddCh(); state = 11; break;}
 					else {t.kind = 14; break loop;}
 				case 25:
 					recEnd = pos; recKind = 15;
-					if (ch == '=') {AddCh(); state = 12; break;}
+					if (ch == '=') {AddCh(); state = 12; break;}
 					else {t.kind = 15; break loop;}
 
             }
--- a/mx/.pylintrc	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,278 +0,0 @@
-[MASTER]
-
-# Specify a configuration file.
-#rcfile=
-
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
-
-# Profiled execution.
-profile=no
-
-# Add files or directories to the blacklist. They should be base names, not
-# paths.
-ignore=CVS
-
-# Pickle collected data for later comparisons.
-persistent=no
-
-# List of plugins (as comma separated values of python modules names) to load,
-# usually to register additional checkers.
-load-plugins=
-
-
-[MESSAGES CONTROL]
-
-# Enable the message, report, category or checker with the given id(s). You can
-# either give multiple identifier separated by comma (,) or put this option
-# multiple time. See also the "--disable" option for examples.
-#enable=
-
-# Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifiers separated by comma (,) or put this
-# option multiple times (only on the command line, not in the configuration
-# file where it should appear only once).You can also use "--disable=all" to
-# disable everything first and then reenable specific checks. For example, if
-# you want to run only the similarities checker, you can use "--disable=all
-# --enable=similarities". If you want to run only the classes checker, but have
-# no Warning level messages displayed, use"--disable=all --enable=classes
-# --disable=W"
-disable=attribute-defined-outside-init,arguments-differ,
-        bare-except,global-statement,protected-access,redefined-outer-name,
-        unused-argument,star-args,pointless-string-statement,old-style-class,
-        too-many-lines,missing-docstring,no-init,no-self-use,too-many-statements,
-        too-many-locals,too-few-public-methods,too-many-instance-attributes,
-        too-many-arguments,too-many-branches,too-many-public-methods,
-        abstract-method
-
-[REPORTS]
-
-# Set the output format. Available formats are text, parseable, colorized, msvs
-# (visual studio) and html. You can also give a reporter class, eg
-# mypackage.mymodule.MyReporterClass.
-output-format=text
-
-# Put messages in a separate file for each module / package specified on the
-# command line instead of printing them on stdout. Reports (if any) will be
-# written in a file name "pylint_global.[txt|html]".
-files-output=no
-
-# Tells whether to display a full report or only the messages
-reports=no
-
-# Python expression which should return a note less than 10 (10 is the highest
-# note). You have access to the variables errors warning, statement which
-# respectively contain the number of errors / warnings messages and the total
-# number of statements analyzed. This is used by the global evaluation report
-# (RP0004).
-evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
-
-# Add a comment according to your evaluation note. This is used by the global
-# evaluation report (RP0004).
-comment=no
-
-# Template used to display messages. This is a python new-style format string
-# used to format the massage information. See doc for all details
-#msg-template=
-
-
-[BASIC]
-
-# Required attributes for module, separated by a comma
-required-attributes=
-
-# List of builtins function names that should not be used, separated by a comma
-bad-functions=filter,apply,input
-
-# Regular expression which should only match correct module names
-module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
-
-# Regular expression which should only match correct module level names
-const-rgx=[a-zA-Z0-9_]{2,30}$
-
-# Regular expression which should only match correct class names
-class-rgx=[A-Z_][a-zA-Z0-9]+$
-
-# Regular expression which should only match correct function names
-function-rgx=[a-z_][a-zA-Z0-9_]{1,40}$
-
-# Regular expression which should only match correct method names
-method-rgx=[a-z_][a-zA-Z0-9_]{2,40}$
-
-# Regular expression which should only match correct instance attribute names
-attr-rgx=[a-z_][a-zA-Z0-9_]{1,30}$
-
-# Regular expression which should only match correct argument names
-argument-rgx=[a-z_][a-zA-Z0-9_]{0,30}$
-
-# Regular expression which should only match correct variable names
-variable-rgx=[a-z_][a-zA-Z0-9_]{0,30}$
-
-# Regular expression which should only match correct attribute names in class
-# bodies
-class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
-
-# Regular expression which should only match correct list comprehension /
-# generator expression variable names
-inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
-
-# Good variable names which should always be accepted, separated by a comma
-good-names=i,j,k,ex,Run,_
-
-# Bad variable names which should always be refused, separated by a comma
-bad-names=foo,bar,baz,toto,tutu,tata
-
-# Regular expression which should only match function or class names that do
-# not require a docstring.
-no-docstring-rgx=.*
-
-# Minimum line length for functions/classes that require docstrings, shorter
-# ones are exempt.
-docstring-min-length=-1
-
-
-[FORMAT]
-
-# Maximum number of characters on a single line.
-max-line-length=300
-
-# Regexp for a line that is allowed to be longer than the limit.
-ignore-long-lines=^\s*(# )?<?https?://\S+>?$
-
-# Maximum number of lines in a module
-max-module-lines=1000
-
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-indent-string='    '
-
-
-[MISCELLANEOUS]
-
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME
-
-
-[SIMILARITIES]
-
-# Minimum lines number of a similarity.
-min-similarity-lines=4
-
-# Ignore comments when computing similarities.
-ignore-comments=yes
-
-# Ignore docstrings when computing similarities.
-ignore-docstrings=yes
-
-# Ignore imports when computing similarities.
-ignore-imports=no
-
-
-[TYPECHECK]
-
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
-
-# List of classes names for which member attributes should not be checked
-# (useful for classes with attributes dynamically set).
-ignored-classes=SQLObject
-
-# When zope mode is activated, add a predefined set of Zope acquired attributes
-# to generated-members.
-zope=no
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E0201 when accessed. Python regular
-# expressions are accepted.
-generated-members=REQUEST,acl_users,aq_parent
-
-
-[VARIABLES]
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# A regular expression matching the beginning of the name of dummy variables
-# (i.e. not used).
-dummy-variables-rgx=_$|dummy
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=
-
-
-[CLASSES]
-
-# List of interface methods to ignore, separated by a comma. This is used for
-# instance to not check methods defines in Zope's Interface base class.
-ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
-
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,__new__,setUp
-
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
-
-# List of valid names for the first argument in a metaclass class method.
-valid-metaclass-classmethod-first-arg=mcs
-
-
-[DESIGN]
-
-# Maximum number of arguments for function / method
-max-args=5
-
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore
-ignored-argument-names=_.*
-
-# Maximum number of locals for function / method body
-max-locals=15
-
-# Maximum number of return / yield for function / method body
-max-returns=6
-
-# Maximum number of branch for function / method body
-max-branches=12
-
-# Maximum number of statements in function / method body
-max-statements=50
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of attributes for a class (see R0902).
-max-attributes=7
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=2
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=20
-
-
-[IMPORTS]
-
-# Deprecated modules which should not be used, separated by a comma
-deprecated-modules=regsub,TERMIOS,Bastion,rexec
-
-# Create a graph of every (i.e. internal and external) dependencies in the
-# given file (report RP0402 must not be disabled)
-import-graph=
-
-# Create a graph of external dependencies in the given file (report RP0402 must
-# not be disabled)
-ext-import-graph=
-
-# Create a graph of internal dependencies in the given file (report RP0402 must
-# not be disabled)
-int-import-graph=
-
-
-[EXCEPTIONS]
-
-# Exceptions that will emit a warning when being caught. Defaults to
-# "Exception"
-overgeneral-exceptions=Exception
--- a/mx/commands.py	Fri Sep 06 21:37:50 2013 +0200
+++ b/mx/commands.py	Wed Oct 02 13:26:31 2013 +0200
@@ -243,7 +243,7 @@
     machine = platform.uname()[4]
     if machine in ['amd64', 'AMD64', 'x86_64', 'i86pc']:
         return 'amd64'
-    if machine in ['sun4v']:
+    if machine in ['sun4v', 'sun4u']:
         return 'sparc'
     if machine == 'i386' and mx.get_os() == 'darwin':
         try:
@@ -345,8 +345,8 @@
                 pass
     else:
         if not exists(jdk):
-            if _installed_jdks and mx._opts.verbose:
-                mx.log("Could not find JDK directory at " + jdk)
+            if _installed_jdks:
+                mx.log("The selected JDK directory does not (yet) exist: " + jdk)
             _handle_missing_VM(build, vmToCheck if vmToCheck else 'graal')
 
     if installGraalJar:
@@ -442,43 +442,14 @@
         log.close()
     return ret
 
-def pylint(args):
-    """run pylint (if available) over Python source files"""
-    rcfile = join(_graal_home, 'mx', '.pylintrc')
-    if not exists(rcfile):
-        mx.log('pylint configuration file does not exist: ' + rcfile)
-        return
+def jdkhome(vm=None):
+    """return the JDK directory selected for the 'vm' command"""
+    build = _vmbuild if _vmSourcesAvailable else 'product'
+    return _jdk(build, installGraalJar=False)
 
-    try:
-        output = subprocess.check_output(['pylint', '--version'], stderr=subprocess.STDOUT)
-        m = re.match(r'.*pylint (\d+)\.(\d+)\.(\d+).*', output, re.DOTALL)
-        if not m:
-            mx.log('could not determine pylint version from ' + output)
-            return
-        major, minor, micro = (int(m.group(1)), int(m.group(2)), int(m.group(3)))
-        if major < 1:
-            mx.log('require pylint version >= 1 (got {0}.{1}.{2})'.format(major, minor, micro))
-            return
-    except BaseException:
-        mx.log('pylint is not available')
-        return
-
-
-    env = os.environ.copy()
-    env['PYTHONPATH'] = dirname(mx.__file__)
-
-    versioned = subprocess.check_output(['hg', 'locate', '-f'], stderr=subprocess.STDOUT).split(os.linesep)
-    for f in versioned:
-        if f.endswith('.py'):
-            pyfile = f
-            mx.log('Running pylint on ' + pyfile + '...')
-            mx.run(['pylint', '--reports=n', '--rcfile=' + rcfile, pyfile], env=env)
-
-def jdkhome(args, vm=None):
+def print_jdkhome(args, vm=None):
     """print the JDK directory selected for the 'vm' command"""
-
-    build = _vmbuild if _vmSourcesAvailable else 'product'
-    print _jdk(build, installGraalJar=False)
+    print jdkhome(vm)
 
 def buildvars(args):
     """describe the variables that can be set by the -D option to the 'mx build' commmand"""
@@ -800,7 +771,7 @@
             mx.abort('VM option ' + t + ' must precede ' + tests[0])
 
     candidates = []
-    for p in mx.projects():
+    for p in mx.projects_opt_limit_to_suites():
         if mx.java().javaCompliance < p.javaCompliance:
             continue
         candidates += _find_classes_with_annotations(p, None, annotations).keys()
@@ -818,7 +789,7 @@
             if not found:
                 mx.log('warning: no tests matched by substring "' + t)
 
-    projectscp = mx.classpath([pcp.name for pcp in mx.projects() if pcp.javaCompliance <= mx.java().javaCompliance])
+    projectscp = mx.classpath([pcp.name for pcp in mx.projects_opt_limit_to_suites() if pcp.javaCompliance <= mx.java().javaCompliance])
 
     if len(classes) != 0:
         f_testfile = open(testfile, 'w')
@@ -942,31 +913,103 @@
     allDuration = datetime.timedelta(seconds=time.time() - allStart)
     mx.log('TOTAL TIME:   ' + '[' + str(allDuration) + ']')
 
-def gate(args):
+class Task:
+    def __init__(self, title):
+        self.start = time.time()
+        self.title = title
+        self.end = None
+        self.duration = None
+        mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: BEGIN: ') + title)
+    def stop(self):
+        self.end = time.time()
+        self.duration = datetime.timedelta(seconds=self.end - self.start)
+        mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: END:   ') + self.title + ' [' + str(self.duration) + ']')
+        return self
+    def abort(self, codeOrMessage):
+        self.end = time.time()
+        self.duration = datetime.timedelta(seconds=self.end - self.start)
+        mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: ABORT: ') + self.title + ' [' + str(self.duration) + ']')
+        mx.abort(codeOrMessage)
+        return self
+
+def _basic_gate_body(args, tasks):
+    t = Task('BuildHotSpotGraal: fastdebug,product')
+    buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product'])
+    tasks.append(t.stop())
+
+    with VM('graal', 'fastdebug'):
+        t = Task('BootstrapWithSystemAssertions:fastdebug')
+        vm(['-esa', '-version'])
+        tasks.append(t.stop())
+
+    with VM('graal', 'product'):
+        t = Task('BootstrapWithGCVerification:product')
+        vm(['-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'])
+        tasks.append(t.stop())
+
+    with VM('graal', 'product'):
+        t = Task('BootstrapWithG1GCVerification:product')
+        vm(['-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+UseNewCode', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'])
+        tasks.append(t.stop())
+
+    with VM('graal', 'product'):
+        t = Task('BootstrapWithRegisterPressure:product')
+        vm(['-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version'])
+        tasks.append(t.stop())
+
+    with VM('graal', 'product'):
+        t = Task('BootstrapWithAOTConfiguration:product')
+        vm(['-G:+AOTCompilation', '-G:+VerifyPhases', '-esa', '-version'])
+        tasks.append(t.stop())
+
+    with VM('server', 'product'):  # hosted mode
+        t = Task('UnitTests:hosted-product')
+        unittest([])
+        tasks.append(t.stop())
+
+    for vmbuild in ['fastdebug', 'product']:
+        for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild):
+            t = Task(str(test) + ':' + vmbuild)
+            if not test.test('graal'):
+                t.abort(test.name + ' Failed')
+            tasks.append(t.stop())
+
+    if args.jacocout is not None:
+        jacocoreport([args.jacocout])
+
+    global _jacoco
+    _jacoco = 'off'
+
+    t = Task('CleanAndBuildGraalVisualizer')
+    mx.run(['ant', '-f', join(_graal_home, 'visualizer', 'build.xml'), '-q', 'clean', 'build'])
+    tasks.append(t.stop())
+
+    # Prevent Graal modifications from breaking the standard builds
+    if args.buildNonGraal:
+        t = Task('BuildHotSpotVarieties')
+        buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product'])
+        buildvms(['--vms', 'server-nograal', '--builds', 'product'])
+        buildvms(['--vms', 'server-nograal', '--builds', 'optimized'])
+        tasks.append(t.stop())
+
+        for vmbuild in ['product', 'fastdebug']:
+            for theVm in ['client', 'server']:
+                with VM(theVm, vmbuild):
+                    t = Task('DaCapo_pmd:' + theVm + ':' + vmbuild)
+                    dacapo(['pmd'])
+                    tasks.append(t.stop())
+
+                    t = Task('UnitTests:' + theVm + ':' + vmbuild)
+                    unittest(['-XX:CompileCommand=exclude,*::run*', 'graal.api'])
+                    tasks.append(t.stop())
+
+
+def gate(args, gate_body=_basic_gate_body):
     """run the tests used to validate a push
 
     If this command exits with a 0 exit code, then the source code is in
     a state that would be accepted for integration into the main repository."""
 
-    class Task:
-        def __init__(self, title):
-            self.start = time.time()
-            self.title = title
-            self.end = None
-            self.duration = None
-            mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: BEGIN: ') + title)
-        def stop(self):
-            self.end = time.time()
-            self.duration = datetime.timedelta(seconds=self.end - self.start)
-            mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: END:   ') + self.title + ' [' + str(self.duration) + ']')
-            return self
-        def abort(self, codeOrMessage):
-            self.end = time.time()
-            self.duration = datetime.timedelta(seconds=self.end - self.start)
-            mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: ABORT: ') + self.title + ' [' + str(self.duration) + ']')
-            mx.abort(codeOrMessage)
-            return self
-
     parser = ArgumentParser(prog='mx gate')
     parser.add_argument('-j', '--omit-java-clean', action='store_false', dest='cleanJava', help='omit cleaning Java native code')
     parser.add_argument('-n', '--omit-native-clean', action='store_false', dest='cleanNative', help='omit cleaning and building native code')
@@ -982,7 +1025,7 @@
     try:
 
         t = Task('Pylint')
-        pylint([])
+        mx.pylint([])
         tasks.append(t.stop())
 
         t = Task('Clean')
@@ -1029,74 +1072,7 @@
         else:
             _jacoco = 'off'
 
-        t = Task('BuildHotSpotGraal: fastdebug,product')
-        buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product'])
-        tasks.append(t.stop())
-
-        with VM('graal', 'fastdebug'):
-            t = Task('BootstrapWithSystemAssertions:fastdebug')
-            vm(['-esa', '-version'])
-            tasks.append(t.stop())
-
-        with VM('graal', 'product'):
-            t = Task('BootstrapWithGCVerification:product')
-            vm(['-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'])
-            tasks.append(t.stop())
-
-        with VM('graal', 'product'):
-            t = Task('BootstrapWithG1GCVerification:product')
-            vm(['-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+UseNewCode', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'])
-            tasks.append(t.stop())
-
-        with VM('graal', 'product'):
-            t = Task('BootstrapWithRegisterPressure:product')
-            vm(['-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version'])
-            tasks.append(t.stop())
-
-        with VM('graal', 'product'):
-            t = Task('BootstrapWithAOTConfiguration:product')
-            vm(['-G:+AOTCompilation', '-G:+VerifyPhases', '-esa', '-version'])
-            tasks.append(t.stop())
-
-        with VM('server', 'product'):  # hosted mode
-            t = Task('UnitTests:hosted-product')
-            unittest([])
-            tasks.append(t.stop())
-
-        for vmbuild in ['fastdebug', 'product']:
-            for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild):
-                t = Task(str(test) + ':' + vmbuild)
-                if not test.test('graal'):
-                    t.abort(test.name + ' Failed')
-                tasks.append(t.stop())
-
-        if args.jacocout is not None:
-            jacocoreport([args.jacocout])
-
-        _jacoco = 'off'
-
-        t = Task('CleanAndBuildGraalVisualizer')
-        mx.run(['ant', '-f', join(_graal_home, 'visualizer', 'build.xml'), '-q', 'clean', 'build'])
-        tasks.append(t.stop())
-
-        # Prevent Graal modifications from breaking the standard builds
-        if args.buildNonGraal:
-            t = Task('BuildHotSpotVarieties')
-            buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product'])
-            buildvms(['--vms', 'server-nograal', '--builds', 'product'])
-            buildvms(['--vms', 'server-nograal', '--builds', 'optimized'])
-            tasks.append(t.stop())
-
-            for vmbuild in ['product', 'fastdebug']:
-                for theVm in ['client', 'server']:
-                    with VM(theVm, vmbuild):
-                        t = Task('DaCapo_pmd:' + theVm + ':' + vmbuild)
-                        dacapo(['pmd'])
-                        tasks.append(t.stop())
-
-                        t = Task('UnitTests:' + theVm + ':' + vmbuild)
-                        unittest(['-XX:CompileCommand=exclude,*::run*', 'graal.api'])
-                        tasks.append(t.stop())
+        gate_body(args, tasks)
 
     except KeyboardInterrupt:
         total.abort(1)
@@ -1358,7 +1334,7 @@
                     '--title', 'Graal OpenJDK Project Documentation',
                     '--dot-output-base', 'projects'] + args)
 
-def mx_init():
+def mx_init(suite):
     commands = {
         'build': [build, ''],
         'buildvars': [buildvars, ''],
@@ -1367,8 +1343,7 @@
         'hsdis': [hsdis, '[att]'],
         'hcfdis': [hcfdis, ''],
         'igv' : [igv, ''],
-        'jdkhome': [jdkhome, ''],
-        'pylint': [pylint, ''],
+        'jdkhome': [print_jdkhome, ''],
         'dacapo': [dacapo, '[VM options] benchmarks...|"all" [DaCapo options]'],
         'scaladacapo': [scaladacapo, '[VM options] benchmarks...|"all" [Scala DaCapo options]'],
         'specjvm2008': [specjvm2008, '[VM options] benchmarks...|"all" [SPECjvm2008 options]'],
@@ -1406,7 +1381,7 @@
             'export': [export, '[-options] [zipfile]'],
         })
 
-    mx._commands.update(commands)
+    mx.update_commands(suite, commands)
 
 def mx_post_parse_cmd_line(opts):  #
     # TODO _minVersion check could probably be part of a Suite in mx?
--- a/mx/eclipse-settings/org.eclipse.jdt.core.prefs	Fri Sep 06 21:37:50 2013 +0200
+++ b/mx/eclipse-settings/org.eclipse.jdt.core.prefs	Wed Oct 02 13:26:31 2013 +0200
@@ -157,7 +157,7 @@
 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
 org.eclipse.jdt.core.formatter.blank_lines_after_package=1
 org.eclipse.jdt.core.formatter.blank_lines_before_field=0
-org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
 org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
 org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
 org.eclipse.jdt.core.formatter.blank_lines_before_method=1
--- a/mx/projects	Fri Sep 06 21:37:50 2013 +0200
+++ b/mx/projects	Wed Oct 02 13:26:31 2013 +0200
@@ -28,7 +28,7 @@
 library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.2.jar
 
 distribution@GRAAL@path=graal.jar
-distribution@GRAAL@dependencies=com.oracle.graal.hotspot.amd64,com.oracle.graal.truffle,com.oracle.graal.truffle.printer,com.oracle.graal.hotspot.sparc,com.oracle.graal.hotspot,com.oracle.graal.compiler.hsail
+distribution@GRAAL@dependencies=com.oracle.graal.hotspot.amd64,com.oracle.graal.hotspot.ptx,com.oracle.graal.truffle,com.oracle.graal.truffle.printer,com.oracle.graal.hotspot.sparc,com.oracle.graal.hotspot,com.oracle.graal.compiler.hsail
 
 # graal.api.runtime
 project@com.oracle.graal.api.runtime@subDir=graal
@@ -134,6 +134,15 @@
 project@com.oracle.graal.hotspot.sparc@javaCompliance=1.7
 project@com.oracle.graal.hotspot.sparc@workingSets=Graal,HotSpot,SPARC
 
+# graal.hotspot.ptx
+project@com.oracle.graal.hotspot.ptx@subDir=graal
+project@com.oracle.graal.hotspot.ptx@sourceDirs=src
+project@com.oracle.graal.hotspot.ptx@dependencies=com.oracle.graal.hotspot,com.oracle.graal.ptx
+project@com.oracle.graal.hotspot.ptx@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.hotspot.ptx@annotationProcessors=com.oracle.graal.service.processor
+project@com.oracle.graal.hotspot.ptx@javaCompliance=1.7
+project@com.oracle.graal.hotspot.ptx@workingSets=Graal,HotSpot,PTX
+
 # graal.hotspot.server
 project@com.oracle.graal.hotspot.server@subDir=graal
 project@com.oracle.graal.hotspot.server@sourceDirs=src
@@ -177,7 +186,7 @@
 # graal.graph
 project@com.oracle.graal.graph@subDir=graal
 project@com.oracle.graal.graph@sourceDirs=src
-project@com.oracle.graal.graph@dependencies=
+project@com.oracle.graal.graph@dependencies=com.oracle.graal.debug
 project@com.oracle.graal.graph@javaCompliance=1.7
 project@com.oracle.graal.graph@workingSets=Graal,Graph
 
@@ -223,7 +232,7 @@
 # graal.lir.ptx
 project@com.oracle.graal.lir.ptx@subDir=graal
 project@com.oracle.graal.lir.ptx@sourceDirs=src
-project@com.oracle.graal.lir.ptx@dependencies=com.oracle.graal.asm.ptx,com.oracle.graal.lir
+project@com.oracle.graal.lir.ptx@dependencies=com.oracle.graal.asm.ptx
 project@com.oracle.graal.lir.ptx@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.lir.ptx@javaCompliance=1.7
 project@com.oracle.graal.lir.ptx@workingSets=Graal,LIR,PTX
@@ -288,7 +297,7 @@
 # graal.nodes
 project@com.oracle.graal.nodes@subDir=graal
 project@com.oracle.graal.nodes@sourceDirs=src
-project@com.oracle.graal.nodes@dependencies=com.oracle.graal.graph,com.oracle.graal.debug,com.oracle.graal.api.replacements,com.oracle.graal.api.code
+project@com.oracle.graal.nodes@dependencies=com.oracle.graal.graph,com.oracle.graal.api.replacements,com.oracle.graal.api.code
 project@com.oracle.graal.nodes@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.nodes@javaCompliance=1.7
 project@com.oracle.graal.nodes@workingSets=Graal,Graph
@@ -369,7 +378,7 @@
 # graal.compiler.ptx.test
 project@com.oracle.graal.compiler.ptx.test@subDir=graal
 project@com.oracle.graal.compiler.ptx.test@sourceDirs=src
-project@com.oracle.graal.compiler.ptx.test@dependencies=com.oracle.graal.compiler.ptx,com.oracle.graal.compiler.test,com.oracle.graal.ptx
+project@com.oracle.graal.compiler.ptx.test@dependencies=com.oracle.graal.hotspot.ptx,com.oracle.graal.compiler.ptx,com.oracle.graal.compiler.test
 project@com.oracle.graal.compiler.ptx.test@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.compiler.ptx.test@javaCompliance=1.7
 project@com.oracle.graal.compiler.ptx.test@workingSets=Graal,PTX,Test
@@ -531,7 +540,7 @@
 # graal.asm.ptx
 project@com.oracle.graal.asm.ptx@subDir=graal
 project@com.oracle.graal.asm.ptx@sourceDirs=src
-project@com.oracle.graal.asm.ptx@dependencies=com.oracle.graal.asm
+project@com.oracle.graal.asm.ptx@dependencies=com.oracle.graal.lir
 project@com.oracle.graal.asm.ptx@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.asm.ptx@javaCompliance=1.7
 project@com.oracle.graal.asm.ptx@workingSets=Graal,Assembler,PTX
--- a/mx/sanitycheck.py	Fri Sep 06 21:37:50 2013 +0200
+++ b/mx/sanitycheck.py	Wed Oct 02 13:26:31 2013 +0200
@@ -252,13 +252,15 @@
     return Test("Scala-DaCapo-" + name, ['-jar', dacapo, name] + _noneAsEmptyList(dacapoArgs), [dacapoSuccess], [dacapoFail], [dacapoMatcher], ['-Xms2g', '-XX:+' + gc, '-XX:-UseCompressedOops'])
 
 def getBootstraps():
-    time = re.compile(r"Bootstrapping Graal\.+ in (?P<time>[0-9]+) ms")
+    time = re.compile(r"Bootstrapping Graal\.+ in (?P<time>[0-9]+) ms( \(compiled (?P<methods>[0-9]+) methods\))?")
     scoreMatcher = ValuesMatcher(time, {'group' : 'Bootstrap', 'name' : 'BootstrapTime', 'score' : '<time>'})
+    methodMatcher = ValuesMatcher(time, {'group' : 'Bootstrap', 'name' : 'BootstrapMethods', 'score' : '<methods>'})
     scoreMatcherBig = ValuesMatcher(time, {'group' : 'Bootstrap-bigHeap', 'name' : 'BootstrapTime', 'score' : '<time>'})
+    methodMatcherBig = ValuesMatcher(time, {'group' : 'Bootstrap-bigHeap', 'name' : 'BootstrapMethods', 'score' : '<methods>'})
 
     tests = []
-    tests.append(Test("Bootstrap", ['-version'], successREs=[time], scoreMatchers=[scoreMatcher], ignoredVMs=['client', 'server'], benchmarkCompilationRate=False))
-    tests.append(Test("Bootstrap-bigHeap", ['-version'], successREs=[time], scoreMatchers=[scoreMatcherBig], vmOpts=['-Xms2g'], ignoredVMs=['client', 'server'], benchmarkCompilationRate=False))
+    tests.append(Test("Bootstrap", ['-version'], successREs=[time], scoreMatchers=[scoreMatcher, methodMatcher], ignoredVMs=['client', 'server'], benchmarkCompilationRate=False))
+    tests.append(Test("Bootstrap-bigHeap", ['-version'], successREs=[time], scoreMatchers=[scoreMatcherBig, methodMatcherBig], vmOpts=['-Xms2g'], ignoredVMs=['client', 'server'], benchmarkCompilationRate=False))
     return tests
 
 class CTWMode:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mxtool/.pylintrc	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,278 @@
+[MASTER]
+
+# Specify a configuration file.
+#rcfile=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Profiled execution.
+profile=no
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
+
+# Pickle collected data for later comparisons.
+persistent=no
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+
+[MESSAGES CONTROL]
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time. See also the "--disable" option for examples.
+#enable=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once).You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use"--disable=all --enable=classes
+# --disable=W"
+disable=attribute-defined-outside-init,arguments-differ,
+        bare-except,global-statement,protected-access,redefined-outer-name,
+        unused-argument,star-args,pointless-string-statement,old-style-class,
+        too-many-lines,missing-docstring,no-init,no-self-use,too-many-statements,
+        too-many-locals,too-few-public-methods,too-many-instance-attributes,
+        too-many-arguments,too-many-branches,too-many-public-methods,
+        abstract-method
+
+[REPORTS]
+
+# Set the output format. Available formats are text, parseable, colorized, msvs
+# (visual studio) and html. You can also give a reporter class, eg
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]".
+files-output=no
+
+# Tells whether to display a full report or only the messages
+reports=no
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Add a comment according to your evaluation note. This is used by the global
+# evaluation report (RP0004).
+comment=no
+
+# Template used to display messages. This is a python new-style format string
+# used to format the massage information. See doc for all details
+#msg-template=
+
+
+[BASIC]
+
+# Required attributes for module, separated by a comma
+required-attributes=
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=filter,apply,input
+
+# Regular expression which should only match correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression which should only match correct module level names
+const-rgx=[a-zA-Z0-9_]{2,30}$
+
+# Regular expression which should only match correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression which should only match correct function names
+function-rgx=[a-z_][a-zA-Z0-9_]{1,40}$
+
+# Regular expression which should only match correct method names
+method-rgx=[a-z_][a-zA-Z0-9_]{2,40}$
+
+# Regular expression which should only match correct instance attribute names
+attr-rgx=[a-z_][a-zA-Z0-9_]{1,30}$
+
+# Regular expression which should only match correct argument names
+argument-rgx=[a-z_][a-zA-Z0-9_]{0,30}$
+
+# Regular expression which should only match correct variable names
+variable-rgx=[a-z_][a-zA-Z0-9_]{0,30}$
+
+# Regular expression which should only match correct attribute names in class
+# bodies
+class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Regular expression which should only match correct list comprehension /
+# generator expression variable names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=.*
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=300
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string='    '
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME
+
+
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+
+[TYPECHECK]
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of classes names for which member attributes should not be checked
+# (useful for classes with attributes dynamically set).
+ignored-classes=SQLObject
+
+# When zope mode is activated, add a predefined set of Zope acquired attributes
+# to generated-members.
+zope=no
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E0201 when accessed. Python regular
+# expressions are accepted.
+generated-members=REQUEST,acl_users,aq_parent
+
+
+[VARIABLES]
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching the beginning of the name of dummy variables
+# (i.e. not used).
+dummy-variables-rgx=_$|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+
+[CLASSES]
+
+# List of interface methods to ignore, separated by a comma. This is used for
+# instance to not check methods defines in Zope's Interface base class.
+ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=5
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of branch for function / method body
+max-branches=12
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,TERMIOS,Bastion,rexec
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception"
+overgeneral-exceptions=Exception
--- a/mxtool/mx.py	Fri Sep 06 21:37:50 2013 +0200
+++ b/mxtool/mx.py	Wed Oct 02 13:26:31 2013 +0200
@@ -37,7 +37,11 @@
 containing one or more projects. It's not coincidental that this closely
 matches the layout of one or more projects in a Mercurial repository.
 The configuration information for a suite lives in an 'mx' sub-directory
-at the top level of the suite.
+at the top level of the suite. A suite is given a name by a 'suite=name'
+property in the 'mx/projects' file (if omitted the name is suite directory).
+An 'mx' subdirectory can be named as plain 'mx' or 'mx.name', where
+'name' is typically the name as the suite name.
+The latter is useful to avoid clashes in IDE project names.
 
 When launched, mx treats the current working directory as a suite.
 This is the primary suite. All other suites are called included suites.
@@ -137,7 +141,7 @@
 Property values can use environment variables with Bash syntax (e.g. ${HOME}).
 """
 
-import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils, tempfile
+import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils, tempfile, fnmatch
 import textwrap
 import xml.parsers.expat
 import shutil, re, xml.dom.minidom
@@ -154,6 +158,8 @@
 _mainSuite = None
 _opts = None
 _java = None
+_check_global_structures = True # can be set False to allow suites with duplicate definitions to load without aborting
+
 
 """
 A distribution is a jar or zip file containing the output from one or more Java projects.
@@ -435,10 +441,30 @@
             if url.endswith('/') != self.path.endswith(os.sep):
                 abort('Path for dependency directory must have a URL ending with "/": path=' + self.path + ' url=' + url)
 
+    def __eq__(self, other):
+        if isinstance(other, Library):
+            if len(self.urls) == 0:
+                return self.path == other.path
+            else:
+                return self.urls == other.urls
+        else:
+            return NotImplemented
+
+
+    def __ne__(self, other):
+        result = self.__eq__(other)
+        if result is NotImplemented:
+            return result
+        return not result
+
+
     def get_path(self, resolve):
         path = self.path
         if not isabs(path):
             path = join(self.suite.dir, path)
+        includedInJDK = getattr(self, 'includedInJDK', None)
+        if includedInJDK and java().javaCompliance >= JavaCompliance(includedInJDK):
+            return None
         if resolve and self.mustExist and not exists(path):
             assert not len(self.urls) == 0, 'cannot find required library ' + self.name + ' ' + path
             print('Downloading ' + self.name + ' from ' + str(self.urls))
@@ -458,7 +484,7 @@
 
     def append_to_classpath(self, cp, resolve):
         path = self.get_path(resolve)
-        if exists(path) or not resolve:
+        if path and (exists(path) or not resolve):
             cp.append(path)
 
     def all_deps(self, deps, includeLibs, includeSelf=True, includeAnnotationProcessors=False):
@@ -468,15 +494,15 @@
         return deps
 
 class Suite:
-    def __init__(self, d, primary):
+    def __init__(self, d, mxDir, primary):
         self.dir = d
+        self.mxDir = mxDir
         self.projects = []
         self.libs = []
         self.dists = []
         self.includes = []
         self.commands = None
         self.primary = primary
-        mxDir = join(d, 'mx')
         self._load_env(mxDir)
         self._load_commands(mxDir)
         self._load_includes(mxDir)
@@ -492,6 +518,13 @@
         projectsFile = join(mxDir, 'projects')
         if not exists(projectsFile):
             return
+
+        def _find_suite_key():
+            for items in _suites.items():
+                if items[1].dir == self.dir:
+                    return items[0]
+            raise KeyError
+
         with open(projectsFile) as f:
             for line in f:
                 line = line.strip()
@@ -503,7 +536,11 @@
                     if len(parts) == 1:
                         if parts[0] != 'suite':
                             abort('Single part property must be "suite": ' + key)
-                        self.name = value
+                        if self.name != value:
+                            currentKey = _find_suite_key()
+                            _suites.pop(currentKey)
+                            self.name = value
+                            _suites[value] = self
                         continue
                     if len(parts) != 3:
                         abort('Property name does not have 3 parts separated by "@": ' + key)
@@ -590,7 +627,7 @@
             if hasattr(mod, 'mx_post_parse_cmd_line'):
                 self.mx_post_parse_cmd_line = mod.mx_post_parse_cmd_line
 
-            mod.mx_init()
+            mod.mx_init(self)
             self.commands = mod
 
     def _load_includes(self, mxDir):
@@ -600,7 +637,7 @@
                 for line in f:
                     include = expandvars_in_property(line.strip())
                     self.includes.append(include)
-                    _loadSuite(include, False)
+                    _loadSuite(os.path.abspath(include), False)
 
     def _load_env(self, mxDir):
         e = join(mxDir, 'env')
@@ -615,24 +652,29 @@
                             abort(e + ':' + str(lineNum) + ': line does not match pattern "key=value"')
                         key, value = line.split('=', 1)
                         os.environ[key.strip()] = expandvars_in_property(value.strip())
+
     def _post_init(self, opts):
-        mxDir = join(self.dir, 'mx')
-        self._load_projects(mxDir)
+        self._load_projects(self.mxDir)
+        # set the global data structures, checking for conflicts unless _global_structures is False
         for p in self.projects:
             existing = _projects.get(p.name)
-            if existing is not None:
+            if existing is not None and _check_global_structures:
                 abort('cannot override project  ' + p.name + ' in ' + p.dir + " with project of the same name in  " + existing.dir)
             if not p.name in _opts.ignored_projects:
                 _projects[p.name] = p
         for l in self.libs:
             existing = _libs.get(l.name)
-            if existing is not None:
-                abort('cannot redefine library  ' + l.name)
+            # Check that suites that define same library are consistent
+            if existing is not None and existing != l and _check_global_structures:
+                abort('inconsistent library redefinition of ' + l.name + ' in ' + existing.suite.dir + ' and ' + l.suite.dir)
             _libs[l.name] = l
         for d in self.dists:
             existing = _dists.get(d.name)
-            if existing is not None:
-                abort('cannot redefine distribution  ' + d.name)
+            if existing is not None and _check_global_structures:
+                # allow redefinition, so use path from existing
+                # abort('cannot redefine distribution  ' + d.name)
+                print('WARNING: distribution ' + d.name + ' redefined')
+                d.path = existing.path
             _dists[d.name] = d
         if hasattr(self, 'mx_post_parse_cmd_line'):
             self.mx_post_parse_cmd_line(opts)
@@ -729,19 +771,40 @@
         abort('Unknown operating system ' + sys.platform)
 
 def _loadSuite(d, primary=False):
-    mxDir = join(d, 'mx')
-    if not exists(mxDir) or not isdir(mxDir):
+    """
+    Load a suite from the 'mx' or 'mx.bbb' subdirectory of d, where 'bbb' is basename of d
+    """
+    mxDefaultDir = join(d, 'mx')
+    name = os.path.basename(d)
+    mxTaggedDir = mxDefaultDir + '.' + name
+    mxDir = None
+    if exists(mxTaggedDir) and isdir(mxTaggedDir):
+        mxDir = mxTaggedDir
+    else:
+        if exists(mxDefaultDir) and isdir(mxDefaultDir):
+            mxDir = mxDefaultDir
+
+
+    if mxDir is None:
         return None
     if len([s for s in _suites.itervalues() if s.dir == d]) == 0:
-        s = Suite(d, primary)
-        _suites[s.name] = s
+        s = Suite(d, mxDir, primary)
+        # N.B. this will be updated once the projects file has been read
+        _suites[name] = s
         return s
 
-def suites():
+def suites(opt_limit_to_suite=False):
     """
     Get the list of all loaded suites.
     """
-    return _suites.values()
+    if opt_limit_to_suite and _opts.specific_suites:
+        result = []
+        for s in _suites.values():
+            if s.name in _opts.specific_suites:
+                result.append(s)
+        return result
+    else:
+        return _suites.values()
 
 def suite(name, fatalIfMissing=True):
     """
@@ -752,11 +815,41 @@
         abort('suite named ' + name + ' not found')
     return s
 
-def projects():
+def projects_from_names(projectNames):
+    """
+    Get the list of projects corresponding to projectNames; all projects if None
+    """
+    if projectNames is None:
+        return projects()
+    else:
+        return [project(name) for name in projectNames]
+
+def projects(opt_limit_to_suite=False):
+    """
+    Get the list of all loaded projects limited by --suite option if opt_limit_to_suite == True
     """
-    Get the list of all loaded projects.
+
+    if opt_limit_to_suite:
+        return _projects_opt_limit_to_suites(_projects.values())
+    else:
+        return _projects.values()
+
+def projects_opt_limit_to_suites():
+    """
+    Get the list of all loaded projects optionally limited by --suite option
     """
-    return _projects.values()
+    return projects(True)
+
+def _projects_opt_limit_to_suites(projects):
+    if not _opts.specific_suites:
+        return projects
+    else:
+        result = []
+        for p in projects:
+            s = p.suite
+            if s.name in _opts.specific_suites:
+                result.append(p)
+        return result
 
 def annotation_processors():
     """
@@ -877,12 +970,12 @@
     are before the projects that depend on them. Unless 'includeLibs' is
     true, libraries are omitted from the result.
     """
+    projects = projects_from_names(projectNames)
+
+    return sorted_project_deps(projects, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+
+def sorted_project_deps(projects, includeLibs=False, includeAnnotationProcessors=False):
     deps = []
-    if projectNames is None:
-        projects = _projects.values()
-    else:
-        projects = [project(name) for name in projectNames]
-
     for p in projects:
         p.all_deps(deps, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
     return deps
@@ -936,7 +1029,8 @@
 
     def __init__(self):
         self.java_initialized = False
-        ArgumentParser.__init__(self, prog='mx')
+        # this doesn't resolve the right way, but can't figure out how to override _handle_conflict_resolve in _ActionsContainer
+        ArgumentParser.__init__(self, prog='mx', conflict_handler='resolve')
 
         self.add_argument('-v', action='store_true', dest='verbose', help='enable verbose output')
         self.add_argument('-V', action='store_true', dest='very_verbose', help='enable very verbose output')
@@ -950,6 +1044,7 @@
         self.add_argument('--user-home', help='users home directory', metavar='<path>', default=os.path.expanduser('~'))
         self.add_argument('--java-home', help='bootstrap JDK installation directory (must be JDK 6 or later)', metavar='<path>')
         self.add_argument('--ignore-project', action='append', dest='ignored_projects', help='name of project to ignore', metavar='<name>', default=[])
+        self.add_argument('--suite', action='append', dest='specific_suites', help='limit command to given suite', default=[])
         if get_os() != 'windows':
             # Time outs are (currently) implemented with Unix specific functionality
             self.add_argument('--timeout', help='timeout (in seconds) for command', type=int, default=0, metavar='<secs>')
@@ -987,6 +1082,9 @@
         commandAndArgs = opts.__dict__.pop('commandAndArgs')
         return opts, commandAndArgs
 
+    def _handle_conflict_resolve(self, action, conflicting_actions):
+        self._handle_conflict_error(action, conflicting_actions)
+
 def _format_commands():
     msg = '\navailable commands:\n\n'
     for cmd in sorted(_commands.iterkeys()):
@@ -1500,14 +1598,21 @@
 
     built = set()
 
-    projects = None
-    if args.projects is not None:
-        projects = args.projects.split(',')
-
     if args.only is not None:
+        # N.B. This build will not include dependencies including annotation processor dependencies
         sortedProjects = [project(name) for name in args.only.split(',')]
     else:
-        sortedProjects = sorted_deps(projects, includeAnnotationProcessors=True)
+        if args.projects is not None:
+            projectNames = args.projects.split(',')
+        else:
+            projectNames = None
+
+        projects = _projects_opt_limit_to_suites(projects_from_names(projectNames))
+        # N.B. Limiting to a suite only affects the starting set of projects. Dependencies in other suites will still be compiled
+        sortedProjects = sorted_project_deps(projects, includeAnnotationProcessors=True)
+
+    if args.java:
+        ideinit([], refreshOnly=True, buildProcessorJars=False)
 
     for p in sortedProjects:
         if p.native:
@@ -1807,6 +1912,74 @@
     build(['--projects', ",".join(pnames)])
     archive(pnames)
 
+def pylint(args):
+    """run pylint (if available) over Python source files (found by 'hg locate' or by tree walk with -walk)"""
+
+    parser = ArgumentParser(prog='mx pylint')
+    parser.add_argument('--walk', action='store_true', help='use tree walk find .py files')
+    args = parser.parse_args(args)
+
+    rcfile = join(dirname(__file__), '.pylintrc')
+    if not exists(rcfile):
+        log('pylint configuration file does not exist: ' + rcfile)
+        return
+
+    try:
+        output = subprocess.check_output(['pylint', '--version'], stderr=subprocess.STDOUT)
+        m = re.match(r'.*pylint (\d+)\.(\d+)\.(\d+).*', output, re.DOTALL)
+        if not m:
+            log('could not determine pylint version from ' + output)
+            return
+        major, minor, micro = (int(m.group(1)), int(m.group(2)), int(m.group(3)))
+        if major < 1:
+            log('require pylint version >= 1 (got {0}.{1}.{2})'.format(major, minor, micro))
+            return
+    except BaseException:
+        log('pylint is not available')
+        return
+
+    def findfiles_by_walk():
+        result = []
+        for suite in suites(True):
+            for root, dirs, files in os.walk(suite.dir):
+                for f in files:
+                    if f.endswith('.py'):
+                        pyfile = join(root, f)
+                        result.append(pyfile)
+                if 'bin' in dirs:
+                    dirs.remove('bin')
+                if 'lib' in dirs:
+                    # avoids downloaded .py files
+                    dirs.remove('lib')
+        return result
+
+    def findfiles_by_hg():
+        result = []
+        for suite in suites(True):
+            versioned = subprocess.check_output(['hg', 'locate', '-f'], stderr=subprocess.STDOUT, cwd=suite.dir).split(os.linesep)
+            for f in versioned:
+                if f.endswith('.py') and exists(f):
+                    result.append(f)
+        return result
+
+    # Perhaps we should just look in suite.mxDir directories for .py files?
+    if args.walk:
+        pyfiles = findfiles_by_walk()
+    else:
+        pyfiles = findfiles_by_hg()
+
+    env = os.environ.copy()
+
+    pythonpath = dirname(__file__)
+    for suite in suites(True):
+        pythonpath = os.pathsep.join([pythonpath, suite.mxDir])
+
+    env['PYTHONPATH'] = pythonpath
+
+    for pyfile in pyfiles:
+        log('Running pylint on ' + pyfile + '...')
+        run(['pylint', '--reports=n', '--rcfile=' + rcfile, pyfile], env=env, nonZeroIsFatal=False)
+
 def archive(args):
     """create jar files for projects and distributions"""
     parser = ArgumentParser(prog='mx archive')
@@ -1832,16 +2005,17 @@
                         # merge library jar into distribution jar
                         logv('[' + d.path + ': adding library ' + l.name + ']')
                         lpath = l.get_path(resolve=True)
-                        with zipfile.ZipFile(lpath, 'r') as lp:
-                            for arcname in lp.namelist():
-                                if arcname.startswith('META-INF/services/'):
-                                    f = arcname[len('META-INF/services/'):].replace('/', os.sep)
-                                    with open(join(services, f), 'a') as outfile:
-                                        for line in lp.read(arcname).splitlines():
-                                            outfile.write(line)
-                                else:
-                                    overwriteCheck(zf, arcname, lpath + '!' + arcname)
-                                    zf.writestr(arcname, lp.read(arcname))
+                        if lpath:
+                            with zipfile.ZipFile(lpath, 'r') as lp:
+                                for arcname in lp.namelist():
+                                    if arcname.startswith('META-INF/services/') and not arcname == 'META-INF/services/':
+                                        f = arcname[len('META-INF/services/'):].replace('/', os.sep)
+                                        with open(join(services, f), 'a') as outfile:
+                                            for line in lp.read(arcname).splitlines():
+                                                outfile.write(line)
+                                    else:
+                                        overwriteCheck(zf, arcname, lpath + '!' + arcname)
+                                        zf.writestr(arcname, lp.read(arcname))
                     else:
                         p = dep
                         # skip a  Java project if its Java compliance level is "higher" than the configured JDK
@@ -1912,7 +2086,7 @@
 
     changedFiles = 0
     for s in suites():
-        projectsFile = join(s.dir, 'mx', 'projects')
+        projectsFile = join(s.mxDir, 'projects')
         if not exists(projectsFile):
             continue
         with open(projectsFile) as f:
@@ -1963,6 +2137,34 @@
             changedFiles += 1
     return changedFiles
 
+class TimeStampFile:
+    def __init__(self, path):
+        self.path = path
+        self.timestamp = os.path.getmtime(path) if exists(path) else None
+
+    def outOfDate(self, arg):
+        if not self.timestamp:
+            return True
+        if isinstance(arg, types.ListType):
+            files = arg
+        else:
+            files = [arg]
+        for f in files:
+            if os.path.getmtime(f) > self.timestamp:
+                return True
+        return False
+
+    def exists(self):
+        return exists(self.path)
+
+    def touch(self):
+        if exists(self.path):
+            os.utime(self.path, None)
+        else:
+            if not isdir(dirname(self.path)):
+                os.makedirs(dirname(self.path))
+            file(self.path, 'a')
+
 def checkstyle(args):
     """run Checkstyle on the Java sources
 
@@ -1975,7 +2177,7 @@
     args = parser.parse_args(args)
 
     totalErrors = 0
-    for p in sorted_deps():
+    for p in projects_opt_limit_to_suites():
         if p.native:
             continue
         sourceDirs = p.source_dirs()
@@ -1997,16 +2199,10 @@
                 logv('[no Java sources in {0} - skipping]'.format(sourceDir))
                 continue
 
-            timestampFile = join(p.suite.dir, 'mx', 'checkstyle-timestamps', sourceDir[len(p.suite.dir) + 1:].replace(os.sep, '_') + '.timestamp')
-            if not exists(dirname(timestampFile)):
-                os.makedirs(dirname(timestampFile))
+            timestamp = TimeStampFile(join(p.suite.mxDir, 'checkstyle-timestamps', sourceDir[len(p.suite.dir) + 1:].replace(os.sep, '_') + '.timestamp'))
             mustCheck = False
-            if not args.force and exists(timestampFile):
-                timestamp = os.path.getmtime(timestampFile)
-                for f in javafilelist:
-                    if os.path.getmtime(f) > timestamp:
-                        mustCheck = True
-                        break
+            if not args.force and timestamp.exists():
+                mustCheck = timestamp.outOfDate(javafilelist)
             else:
                 mustCheck = True
 
@@ -2083,18 +2279,15 @@
                                 elif name == 'error':
                                     errors.append('{}:{}: {}'.format(source[0], attrs['line'], attrs['message']))
 
-                            p = xml.parsers.expat.ParserCreate()
-                            p.StartElementHandler = start_element
+                            xp = xml.parsers.expat.ParserCreate()
+                            xp.StartElementHandler = start_element
                             with open(auditfileName) as fp:
-                                p.ParseFile(fp)
+                                xp.ParseFile(fp)
                             if len(errors) != 0:
                                 map(log, errors)
                                 totalErrors = totalErrors + len(errors)
                             else:
-                                if exists(timestampFile):
-                                    os.utime(timestampFile, None)
-                                else:
-                                    file(timestampFile, 'a')
+                                timestamp.touch()
             finally:
                 if exists(auditfileName):
                     os.unlink(auditfileName)
@@ -2115,7 +2308,7 @@
 
     args = parser.parse_args(args)
 
-    for p in projects():
+    for p in projects_opt_limit_to_suites():
         if p.native:
             if args.native:
                 run([gmake_cmd(), '-C', p.dir, 'clean'])
@@ -2207,7 +2400,7 @@
     slm.close('sourceLookupDirector')
     return slm
 
-def make_eclipse_attach(hostname, port, name=None, deps=None):
+def make_eclipse_attach(suite, hostname, port, name=None, deps=None):
     """
     Creates an Eclipse launch configuration file for attaching to a Java process.
     """
@@ -2229,8 +2422,12 @@
     launch = launch.xml(newl='\n', standalone='no') % slm.xml(escape=True, standalone='no')
 
     if name is None:
-        name = 'attach-' + hostname + '-' + port
-    eclipseLaunches = join('mx', 'eclipse-launches')
+        if len(suites()) == 1:
+            suitePrefix = ''
+        else:
+            suitePrefix = suite.name + '-'
+        name = suitePrefix + 'attach-' + hostname + '-' + port
+    eclipseLaunches = join(suite.mxDir, 'eclipse-launches')
     if not exists(eclipseLaunches):
         os.makedirs(eclipseLaunches)
     return update_file(join(eclipseLaunches, name + '.launch'), launch)
@@ -2302,13 +2499,26 @@
         os.makedirs(eclipseLaunches)
     return update_file(join(eclipseLaunches, name + '.launch'), launch)
 
-def eclipseinit(args, suite=None, buildProcessorJars=True):
+def eclipseinit(args, buildProcessorJars=True, refreshOnly=False):
     """(re)generate Eclipse project configurations and working sets"""
-
-    if suite is None:
-        suite = _mainSuite
+    for s in suites(True):
+        _eclipseinit_suite(args, s, buildProcessorJars, refreshOnly)
+
+    generate_eclipse_workingsets()
+
+
+def _eclipseinit_suite(args, suite, buildProcessorJars=True, refreshOnly=False):
+    projectsFile = join(suite.mxDir, 'projects')
+    timestamp = TimeStampFile(join(suite.mxDir, 'eclipseinit.timestamp'))
+    if refreshOnly and not timestamp.exists():
+        return
+
+    if not timestamp.outOfDate(projectsFile):
+        logv('[Eclipse configurations are up to date - skipping]')
+        return
 
     if buildProcessorJars:
+        ## todo suite specific
         processorjars()
 
     projToDist = dict()
@@ -2317,7 +2527,7 @@
         for p in distDeps:
             projToDist[p.name] = (dist, [dep.name for dep in distDeps])
 
-    for p in projects():
+    for p in suite.projects:
         if p.native:
             continue
 
@@ -2356,20 +2566,22 @@
                     out.element('classpathentry', {'combineaccessrules' : 'false', 'exported' : 'true', 'kind' : 'src', 'path' : '/' + getattr(dep, 'eclipse.project')})
                 else:
                     path = dep.path
-                    if dep.mustExist:
-                        dep.get_path(resolve=True)
-                        if not isabs(path):
-                            # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
-                            # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
-                            # safest to simply use absolute paths.
-                            path = join(suite.dir, path)
-
-                        attributes = {'exported' : 'true', 'kind' : 'lib', 'path' : path}
-
-                        sourcePath = dep.get_source_path(resolve=True)
-                        if sourcePath is not None:
-                            attributes['sourcepath'] = sourcePath
-                        out.element('classpathentry', attributes)
+                    dep.get_path(resolve=True)
+                    if not path or (not exists(path) and not dep.mustExist):
+                        continue
+
+                    if not isabs(path):
+                        # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
+                        # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
+                        # safest to simply use absolute paths.
+                        path = join(p.suite.dir, path)
+
+                    attributes = {'exported' : 'true', 'kind' : 'lib', 'path' : path}
+
+                    sourcePath = dep.get_source_path(resolve=True)
+                    if sourcePath is not None:
+                        attributes['sourcepath'] = sourcePath
+                    out.element('classpathentry', attributes)
             else:
                 out.element('classpathentry', {'combineaccessrules' : 'false', 'exported' : 'true', 'kind' : 'src', 'path' : '/' + dep.name})
 
@@ -2454,7 +2666,7 @@
         if not exists(settingsDir):
             os.mkdir(settingsDir)
 
-        eclipseSettingsDir = join(suite.dir, 'mx', 'eclipse-settings')
+        eclipseSettingsDir = join(p.suite.mxDir, 'eclipse-settings')
         if exists(eclipseSettingsDir):
             for name in os.listdir(eclipseSettingsDir):
                 if name == "org.eclipse.jdt.apt.core.prefs" and not len(p.annotation_processors()) > 0:
@@ -2478,20 +2690,20 @@
                         if not hasattr(dep, 'eclipse.container') and not hasattr(dep, 'eclipse.project'):
                             if dep.mustExist:
                                 path = dep.get_path(resolve=True)
-                                if not isabs(path):
-                                    # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
-                                    # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
-                                    # safest to simply use absolute paths.
-                                    path = join(suite.dir, path)
-                                out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : path, 'enabled' : 'true', 'runInBatchMode' : 'false'})
+                                if path:
+                                    if not isabs(path):
+                                        # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
+                                        # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
+                                        # safest to simply use absolute paths.
+                                        path = join(p.suite.dir, path)
+                                    out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : path, 'enabled' : 'true', 'runInBatchMode' : 'false'})
                     else:
                         out.element('factorypathentry', {'kind' : 'WKSPJAR', 'id' : '/' + dep.name + '/' + dep.name + '.jar', 'enabled' : 'true', 'runInBatchMode' : 'false'})
             out.close('factorypath')
             update_file(join(p.dir, '.factorypath'), out.xml(indent='\t', newl='\n'))
 
-    make_eclipse_attach('localhost', '8000', deps=projects())
-    generate_eclipse_workingsets(suite)
-
+    make_eclipse_attach(suite, 'localhost', '8000', deps=projects())
+    timestamp.touch()
 
 def _isAnnotationProcessorDependency(p):
     """
@@ -2548,22 +2760,31 @@
     dotProjectDoc.close('arguments')
     dotProjectDoc.close('buildCommand')
 
-def generate_eclipse_workingsets(suite):
+def generate_eclipse_workingsets():
     """
-    Populate the workspace's working set configuration with working sets generated from project data.
+    Populate the workspace's working set configuration with working sets generated from project data for the primary suite
     If the workspace already contains working set definitions, the existing ones will be retained and extended.
-    In case mx/env does not contain a WORKSPACE definition pointing to the workspace root directory, the Graal project root directory will be assumed.
-    If no workspace root directory can be identified, the Graal project root directory is used and the user has to place the workingsets.xml file by hand.
+    In case mx/env does not contain a WORKSPACE definition pointing to the workspace root directory, a parent search from the primary suite directory is performed.
+    If no workspace root directory can be identified, the primary suite directory is used and the user has to place the workingsets.xml file by hand.
     """
 
     # identify the location where to look for workingsets.xml
     wsfilename = 'workingsets.xml'
-    wsroot = suite.dir
+    wsloc = '.metadata/.plugins/org.eclipse.ui.workbench'
     if os.environ.has_key('WORKSPACE'):
-        wsroot = os.environ['WORKSPACE']
-    wsdir = join(wsroot, '.metadata/.plugins/org.eclipse.ui.workbench')
+        expected_wsroot = os.environ['WORKSPACE']
+    else:
+        expected_wsroot = _mainSuite.dir
+
+    wsroot = _find_eclipse_wsroot(expected_wsroot)
+    if wsroot is None:
+        # failed to find it
+        wsroot = expected_wsroot
+
+    wsdir = join(wsroot, wsloc)
     if not exists(wsdir):
         wsdir = wsroot
+        log('Could not find Eclipse metadata directory. Please place ' + wsfilename + ' in ' + wsloc + ' manually.')
     wspath = join(wsdir, wsfilename)
 
     # gather working set info from project data
@@ -2584,6 +2805,19 @@
 
     update_file(wspath, wsdoc.xml(newl='\n'))
 
+def _find_eclipse_wsroot(wsdir):
+    md = join(wsdir, '.metadata')
+    if exists(md):
+        return wsdir
+    split = os.path.split(wsdir)
+    if split[0] == wsdir: # root directory
+        return None
+    else:
+        return _find_eclipse_wsroot(split[0])
+
+def _foobar(val):
+    print(val)
+
 def _make_workingset_xml(workingSets):
     wsdoc = XMLDoc()
     wsdoc.open('workingSetManager')
@@ -2666,14 +2900,24 @@
 def _workingset_element(wsdoc, p):
     wsdoc.element('item', {'elementID': '=' + p, 'factoryID': 'org.eclipse.jdt.ui.PersistableJavaElementFactory'})
 
-def netbeansinit(args, suite=None):
+def netbeansinit(args, refreshOnly=False, buildProcessorJars=True):
     """(re)generate NetBeans project configurations"""
 
-    if suite is None:
-        suite = _mainSuite
+    for suite in suites(True):
+        _netbeansinit_suite(args, suite, refreshOnly, buildProcessorJars)
+
+def _netbeansinit_suite(args, suite, refreshOnly=False, buildProcessorJars=True):
+    projectsFile = join(suite.mxDir, 'projects')
+    timestamp = TimeStampFile(join(suite.mxDir, 'netbeansinit.timestamp'))
+    if refreshOnly and not timestamp.exists():
+        return
+
+    if not timestamp.outOfDate(projectsFile):
+        logv('[NetBeans configurations are up to date - skipping]')
+        return
 
     updated = False
-    for p in projects():
+    for p in suite.projects:
         if p.native:
             continue
 
@@ -2856,10 +3100,11 @@
                 if not dep.mustExist:
                     continue
                 path = dep.get_path(resolve=True)
-                if os.sep == '\\':
-                    path = path.replace('\\', '\\\\')
-                ref = 'file.reference.' + dep.name + '-bin'
-                print >> out, ref + '=' + path
+                if path:
+                    if os.sep == '\\':
+                        path = path.replace('\\', '\\\\')
+                    ref = 'file.reference.' + dep.name + '-bin'
+                    print >> out, ref + '=' + path
 
             else:
                 n = dep.name.replace('.', '_')
@@ -2886,12 +3131,18 @@
         log('  1. Ensure that a platform named "JDK_' + str(java().version) + '" is defined (Tools -> Java Platforms)')
         log('  2. Open/create a Project Group for the directory containing the projects (File -> Project Group -> New Group... -> Folder of Projects)')
 
-def ideclean(args, suite=None):
+    timestamp.touch()
+
+def ideclean(args):
     """remove all Eclipse and NetBeans project configurations"""
     def rm(path):
         if exists(path):
             os.remove(path)
 
+    for s in suites():
+        rm(join(s.mxDir, 'eclipseinit.timestamp'))
+        rm(join(s.mxDir, 'netbeansinit.timestamp'))
+
     for p in projects():
         if p.native:
             continue
@@ -2910,15 +3161,16 @@
             log("Error removing {0}".format(p.name + '.jar'))
 
 
-def ideinit(args, suite=None):
+def ideinit(args, refreshOnly=False, buildProcessorJars=True):
     """(re)generate Eclipse and NetBeans project configurations"""
-    eclipseinit(args, suite)
-    netbeansinit(args, suite)
-    fsckprojects([])
+    eclipseinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars)
+    netbeansinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars)
+    if not refreshOnly:
+        fsckprojects([])
 
 def fsckprojects(args):
     """find directories corresponding to deleted Java projects and delete them"""
-    for suite in suites():
+    for suite in suites(True):
         projectDirs = [p.dir for p in suite.projects]
         for root, dirnames, files in os.walk(suite.dir):
             currentDir = join(suite.dir, root)
@@ -2933,7 +3185,7 @@
                         shutil.rmtree(currentDir)
                         log('Deleted ' + currentDir)
 
-def javadoc(args, parser=None, docDir='javadoc', includeDeps=True):
+def javadoc(args, parser=None, docDir='javadoc', includeDeps=True, stdDoclet=True):
     """generate javadoc for some/all Java projects"""
 
     parser = ArgumentParser(prog='mx javadoc') if parser is None else parser
@@ -2951,9 +3203,10 @@
     args = parser.parse_args(args)
 
     # build list of projects to be processed
-    candidates = sorted_deps()
     if args.projects is not None:
         candidates = [project(name) for name in args.projects.split(',')]
+    else:
+        candidates = projects_opt_limit_to_suites()
 
     # optionally restrict packages within a project
     packages = []
@@ -3035,10 +3288,14 @@
             nowarnAPI = []
             if not args.warnAPI:
                 nowarnAPI.append('-XDignore.symbol.file')
+
+            # windowTitle onloy applies to the standard doclet processor
+            windowTitle = []
+            if stdDoclet:
+                windowTitle = ['-windowtitle', p.name + ' javadoc']
             try:
                 log('Generating {2} for {0} in {1}'.format(p.name, out, docDir))
                 run([java().javadoc, memory,
-                     '-windowtitle', p.name + ' javadoc',
                      '-XDignore.symbol.file',
                      '-classpath', cp,
                      '-quiet',
@@ -3048,6 +3305,7 @@
                      links +
                      extraArgs +
                      nowarnAPI +
+                     windowTitle +
                      list(pkgs))
                 log('Generated {2} for {0} in {1}'.format(p.name, out, docDir))
             finally:
@@ -3407,7 +3665,7 @@
 def show_projects(args):
     """show all loaded projects"""
     for s in suites():
-        projectsFile = join(s.dir, 'mx', 'projects')
+        projectsFile = join(s.mxDir, 'projects')
         if exists(projectsFile):
             log(projectsFile)
             for p in s.projects:
@@ -3436,6 +3694,14 @@
     assert _argParser is not None
     _argParser.add_argument(*args, **kwargs)
 
+def update_commands(suite, new_commands):
+    for key, value in new_commands.iteritems():
+        if _commands.has_key(key) and not suite.primary:
+            pass
+            # print("WARNING: attempt to redefine command '" + key + "' in suite " + suite.dir)
+        else:
+            _commands[key] = value
+
 # Table of commands in alphabetical order.
 # Keys are command names, value are lists: [<function>, <usage msg>, <format args to doc string of function>...]
 # If any of the format args are instances of Callable, then they are called with an 'env' are before being
@@ -3456,6 +3722,7 @@
     'ideinit': [ideinit, ''],
     'archive': [archive, '[options]'],
     'projectgraph': [projectgraph, ''],
+    'pylint': [pylint, ''],
     'javap': [javap, '<class name patterns>'],
     'javadoc': [javadoc, '[options]'],
     'site': [site, '[options]'],
@@ -3467,9 +3734,12 @@
 
 def _findPrimarySuite():
     def is_suite_dir(d):
-        mxDir = join(d, 'mx')
-        if exists(mxDir) and isdir(mxDir) and exists(join(mxDir, 'projects')):
-            return dirname(mxDir)
+        for f in os.listdir(d):
+            if f == 'mx' or fnmatch.fnmatch(f, 'mx.*'):
+                mxDir = join(d, f)
+                if exists(mxDir) and isdir(mxDir) and exists(join(mxDir, 'projects')):
+                    return dirname(mxDir)
+
 
     # try current working directory first
     if is_suite_dir(os.getcwd()):
--- a/src/cpu/sparc/vm/graalCodeInstaller_sparc.hpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/cpu/sparc/vm/graalCodeInstaller_sparc.hpp	Wed Oct 02 13:26:31 2013 +0200
@@ -182,9 +182,24 @@
   }
 }
 
-inline int32_t* CodeInstaller::pd_locate_operand(address instruction) {
-  fatal("CodeInstaller::pd_locate_operand - sparc unimp");
-  return (int32_t*)0;
+inline void CodeInstaller::pd_relocate_poll(address pc, jint mark) {
+  switch (mark) {
+    case MARK_POLL_NEAR: {
+      fatal("unimplemented");
+    }
+    case MARK_POLL_FAR:
+      _instructions->relocate(pc, relocInfo::poll_type);
+      break;
+    case MARK_POLL_RETURN_NEAR: {
+      fatal("unimplemented");
+    }
+    case MARK_POLL_RETURN_FAR:
+      _instructions->relocate(pc, relocInfo::poll_return_type);
+      break;
+    default:
+      fatal("invalid mark value");
+      break;
+  }
 }
 
 #endif // CPU_SPARC_VM_CODEINSTALLER_SPARC_HPP
--- a/src/cpu/x86/vm/globals_x86.hpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/cpu/x86/vm/globals_x86.hpp	Wed Oct 02 13:26:31 2013 +0200
@@ -46,7 +46,7 @@
 // the the vep is aligned at CodeEntryAlignment whereas c2 only aligns
 // the uep and the vep doesn't get real alignment but just slops on by
 // only assured that the entry instruction meets the 5 byte size requirement.
-#ifdef COMPILER2
+#if defined(COMPILER2) || defined(GRAAL)
 define_pd_global(intx, CodeEntryAlignment,       32);
 #else
 define_pd_global(intx, CodeEntryAlignment,       16);
--- a/src/cpu/x86/vm/graalCodeInstaller_x86.hpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/cpu/x86/vm/graalCodeInstaller_x86.hpp	Wed Oct 02 13:26:31 2013 +0200
@@ -20,8 +20,8 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-#ifndef CPU_SPARC_VM_CODEINSTALLER_X86_HPP
-#define CPU_SPARC_VM_CODEINSTALLER_X86_HPP
+#ifndef CPU_X86_VM_CODEINSTALLER_X86_HPP
+#define CPU_X86_VM_CODEINSTALLER_X86_HPP
 
 #include "compiler/disassembler.hpp"
 #include "runtime/javaCalls.hpp"
@@ -50,6 +50,9 @@
     // the inlined vtable stub contains a "call register" instruction
     assert(method != NULL, "only valid for virtual calls");
     return (pc_offset + ((NativeCallReg *) inst)->next_instruction_offset());
+  } else if (inst->is_cond_jump()) {
+    address pc = (address) (inst);
+    return pc_offset + (jint) (Assembler::locate_next_instruction(pc) - pc);
   } else {
     fatal("unsupported type of instruction for call site");
     return 0;
@@ -145,21 +148,30 @@
 }
 
 inline void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) {
+  address pc = (address) inst;
   if (inst->is_call()) {
     // NOTE: for call without a mov, the offset must fit a 32-bit immediate
     //       see also CompilerToVM.getMaxCallTargetOffset()
-    NativeCall* call = nativeCall_at((address) (inst));
+    NativeCall* call = nativeCall_at(pc);
     call->set_destination((address) foreign_call_destination);
     _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand);
   } else if (inst->is_mov_literal64()) {
-    NativeMovConstReg* mov = nativeMovConstReg_at((address) (inst));
+    NativeMovConstReg* mov = nativeMovConstReg_at(pc);
     mov->set_data((intptr_t) foreign_call_destination);
     _instructions->relocate(mov->instruction_address(), runtime_call_Relocation::spec(), Assembler::imm_operand);
-  } else {
-    NativeJump* jump = nativeJump_at((address) (inst));
+  } else if (inst->is_jump()) {
+    NativeJump* jump = nativeJump_at(pc);
     jump->set_jump_destination((address) foreign_call_destination);
-    _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand);
+    _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand);
+  } else if (inst->is_cond_jump()) {
+    address old_dest = nativeGeneralJump_at(pc)->jump_destination();
+    address disp = Assembler::locate_operand(pc, Assembler::call32_operand);
+    *(jint*) disp += ((address) foreign_call_destination) - old_dest;
+    _instructions->relocate(pc, runtime_call_Relocation::spec(), Assembler::call32_operand);
+  } else {
+    fatal("unsupported relocation for foreign call");
   }
+
   TRACE_graal_3("relocating (foreign call)  at %p", inst);
 }
 
@@ -207,9 +219,35 @@
   }
 }
 
-inline int32_t* CodeInstaller::pd_locate_operand(address instruction) {
-  return (int32_t*) Assembler::locate_operand(instruction, Assembler::disp32_operand);
+inline void CodeInstaller::pd_relocate_poll(address pc, jint mark) {
+  switch (mark) {
+    case MARK_POLL_NEAR: {
+      NativeInstruction* ni = nativeInstruction_at(pc);
+      int32_t* disp = (int32_t*) Assembler::locate_operand(pc, Assembler::disp32_operand);
+      // int32_t* disp = (int32_t*) Assembler::locate_operand(instruction, Assembler::disp32_operand);
+      int32_t offset = *disp; // The Java code installed the polling page offset into the disp32 operand
+      intptr_t new_disp = (intptr_t) (os::get_polling_page() + offset) - (intptr_t) ni;
+      *disp = (int32_t)new_disp;
+    }
+    case MARK_POLL_FAR:
+      _instructions->relocate(pc, relocInfo::poll_type);
+      break;
+    case MARK_POLL_RETURN_NEAR: {
+      NativeInstruction* ni = nativeInstruction_at(pc);
+      int32_t* disp = (int32_t*) Assembler::locate_operand(pc, Assembler::disp32_operand);
+      // int32_t* disp = (int32_t*) Assembler::locate_operand(instruction, Assembler::disp32_operand);
+      int32_t offset = *disp; // The Java code installed the polling page offset into the disp32 operand
+      intptr_t new_disp = (intptr_t) (os::get_polling_page() + offset) - (intptr_t) ni;
+      *disp = (int32_t)new_disp;
+    }
+    case MARK_POLL_RETURN_FAR:
+      _instructions->relocate(pc, relocInfo::poll_return_type);
+      break;
+    default:
+      fatal("invalid mark value");
+      break;
+  }
 }
 
-#endif // CPU_SPARC_VM_CODEINSTALLER_X86_HPP
+#endif // CPU_X86_VM_CODEINSTALLER_X86_HPP
 
--- a/src/gpu/ptx/vm/gpu_ptx.cpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/gpu/ptx/vm/gpu_ptx.cpp	Wed Oct 02 13:26:31 2013 +0200
@@ -29,7 +29,7 @@
 #include "utilities/ostream.hpp"
 #include "memory/allocation.hpp"
 #include "memory/allocation.inline.hpp"
-#include "kernelArguments.hpp"
+#include "ptxKernelArguments.hpp"
 
 void * gpu::Ptx::_device_context;
 int    gpu::Ptx::_cu_device = 0;
@@ -50,34 +50,26 @@
 gpu::Ptx::cuda_cu_memcpy_dtoh_func_t gpu::Ptx::_cuda_cu_memcpy_dtoh;
 gpu::Ptx::cuda_cu_memfree_func_t gpu::Ptx::_cuda_cu_memfree;
 
-void gpu::probe_linkage() {
-#if defined(__APPLE__) || defined(LINUX)
-  set_gpu_linkage(gpu::Ptx::probe_linkage());
-#else
-  set_gpu_linkage(false);
-#endif
-}
 
-void gpu::initialize_gpu() {
-  if (gpu::has_gpu_linkage()) {
-    set_initialized(gpu::Ptx::initialize_gpu());
-  }
-}
+/*
+ * see http://en.wikipedia.org/wiki/CUDA#Supported_GPUs
+ */
+int ncores(int major, int minor) {
+    int device_type = (major << 4) + minor;
 
-void * gpu::generate_kernel(unsigned char *code, int code_len, const char *name) {
-  if (gpu::has_gpu_linkage()) {
-    return (gpu::Ptx::generate_kernel(code, code_len, name));
-  } else {
-    return NULL;
-  }
-}
-
-bool gpu::execute_kernel(address kernel, PTXKernelArguments & ptxka, JavaValue& ret) {
-  if (gpu::has_gpu_linkage()) {
-    return (gpu::Ptx::execute_kernel(kernel, ptxka, ret));
-  } else {
-    return false;
-  }
+    switch (device_type) {
+        case 0x10: return 8;
+        case 0x11: return 8;
+        case 0x12: return 8;
+        case 0x13: return 8;
+        case 0x20: return 32;
+        case 0x21: return 48;
+        case 0x30: return 192;
+        case 0x35: return 192;
+    default:
+        tty->print_cr("[CUDA] Warning: Unhandled device %x", device_type);
+        return 0;
+    }
 }
 
 bool gpu::Ptx::initialize_gpu() {
@@ -125,24 +117,7 @@
   }
 
   /* Get device attributes */
-  int minor, major, unified_addressing;
-  status = _cuda_cu_device_get_attribute(&minor, GRAAL_CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, _cu_device);
-
-  if (status != GRAAL_CUDA_SUCCESS) {
-    tty->print_cr("[CUDA] Failed to get minor attribute of device: %d", _cu_device);
-    return false;
-  }
-
-  status = _cuda_cu_device_get_attribute(&major, GRAAL_CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, _cu_device);
-
-  if (status != GRAAL_CUDA_SUCCESS) {
-    tty->print_cr("[CUDA] Failed to get major attribute of device: %d", _cu_device);
-    return false;
-  }
-
-  if (TraceGPUInteraction) {
-    tty->print_cr("[CUDA] Compatibility version of device %d: %d.%d", _cu_device, major, minor);
-  }
+  int unified_addressing;
 
   status = _cuda_cu_device_get_attribute(&unified_addressing, GRAAL_CU_DEVICE_ATTRIBUTE_UNIFIED_ADDRESSING, _cu_device);
 
@@ -169,9 +144,50 @@
     tty->print_cr("[CUDA] Using %s", device_name);
   }
 
+
   return true;
 }
 
+unsigned int gpu::Ptx::total_cores() {
+
+    int minor, major, nmp;
+    int status = _cuda_cu_device_get_attribute(&minor,
+                                               GRAAL_CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR,
+                                               _cu_device);
+
+    if (status != GRAAL_CUDA_SUCCESS) {
+        tty->print_cr("[CUDA] Failed to get minor attribute of device: %d", _cu_device);
+        return 0;
+    }
+
+    status = _cuda_cu_device_get_attribute(&major,
+                                           GRAAL_CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR,
+                                           _cu_device);
+
+    if (status != GRAAL_CUDA_SUCCESS) {
+        tty->print_cr("[CUDA] Failed to get major attribute of device: %d", _cu_device);
+        return 0;
+    }
+
+    status = _cuda_cu_device_get_attribute(&nmp,
+                                           GRAAL_CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT,
+                                           _cu_device);
+
+    if (status != GRAAL_CUDA_SUCCESS) {
+        tty->print_cr("[CUDA] Failed to get numberof MPs on device: %d", _cu_device);
+        return 0;
+    }
+
+    int total = nmp * ncores(major, minor);
+
+    if (TraceGPUInteraction) {
+        tty->print_cr("[CUDA] Compatibility version of device %d: %d.%d", _cu_device, major, minor);
+        tty->print_cr("[CUDA] Number of cores: %d", total);
+    }
+    return (total);
+    
+}
+
 void *gpu::Ptx::generate_kernel(unsigned char *code, int code_len, const char *name) {
 
   struct CUmod_st * cu_module;
@@ -200,7 +216,7 @@
   int status = _cuda_cu_ctx_create(&_device_context, 0, _cu_device);
 
   if (status != GRAAL_CUDA_SUCCESS) {
-    tty->print_cr("[CUDA] Failed to create CUDA context for device: %d", _cu_device);
+    tty->print_cr("[CUDA] Failed to create CUDA context for device(%d): %d", _cu_device, status);
     return NULL;
   }
 
@@ -258,15 +274,20 @@
 }
 
 bool gpu::Ptx::execute_kernel(address kernel, PTXKernelArguments &ptxka, JavaValue &ret) {
+    return gpu::Ptx::execute_warp(1, 1, 1, kernel, ptxka, ret);
+}
+
+bool gpu::Ptx::execute_warp(int dimX, int dimY, int dimZ,
+                            address kernel, PTXKernelArguments &ptxka, JavaValue &ret) {
   // grid dimensionality
   unsigned int gridX = 1;
   unsigned int gridY = 1;
   unsigned int gridZ = 1;
 
   // thread dimensionality
-  unsigned int blockX = 1;
-  unsigned int blockY = 1;
-  unsigned int blockZ = 1;
+  unsigned int blockX = dimX;
+  unsigned int blockY = dimY;
+  unsigned int blockZ = dimZ;
 
   struct CUfunc_st* cu_function = (struct CUfunc_st*) kernel;
 
@@ -294,7 +315,7 @@
   }
 
   if (TraceGPUInteraction) {
-    tty->print_cr("[CUDA] Success: Kernel Launch");
+    tty->print_cr("[CUDA] Success: Kernel Launch: X: %d Y: %d Z: %d", blockX, blockY, blockZ);
   }
 
   status = _cuda_cu_ctx_synchronize();
@@ -312,7 +333,7 @@
   // Get the result. TODO: Move this code to get_return_oop()
   BasicType return_type = ptxka.get_ret_type();
   switch (return_type) {
-     case T_INT :
+     case T_INT:
        {
          int return_val;
          status = gpu::Ptx::_cuda_cu_memcpy_dtoh(&return_val, ptxka._return_value_ptr, T_INT_BYTE_SIZE);
@@ -323,7 +344,7 @@
          ret.set_jint(return_val);
        }
        break;
-     case T_LONG :
+     case T_LONG:
        {
          long return_val;
          status = gpu::Ptx::_cuda_cu_memcpy_dtoh(&return_val, ptxka._return_value_ptr, T_LONG_BYTE_SIZE);
@@ -334,10 +355,14 @@
          ret.set_jlong(return_val);
        }
        break;
+     case T_VOID:
+       break;
      default:
-       tty->print_cr("[CUDA] TODO *** Unhandled return type");
+       tty->print_cr("[CUDA] TODO *** Unhandled return type: %d", return_type);
   }
 
+  // handle post-invocation object and array arguemtn
+  ptxka.reiterate();
 
   // Free device memory allocated for result
   status = gpu::Ptx::_cuda_cu_memfree(ptxka._return_value_ptr);
--- a/src/gpu/ptx/vm/gpu_ptx.hpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/gpu/ptx/vm/gpu_ptx.hpp	Wed Oct 02 13:26:31 2013 +0200
@@ -34,6 +34,7 @@
 #define GRAAL_CU_DEVICE_ATTRIBUTE_UNIFIED_ADDRESSING        41
 #define GRAAL_CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR  75
 #define GRAAL_CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR  76
+#define GRAAL_CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT      16
 #define GRAAL_CU_JIT_MAX_REGISTERS                           0
 #define GRAAL_CU_JIT_THREADS_PER_BLOCK                       1
 #define GRAAL_CU_JIT_INFO_LOG_BUFFER                         3
@@ -73,7 +74,9 @@
  protected:
   static bool probe_linkage();
   static bool initialize_gpu();
+  static unsigned int total_cores();
   static void * generate_kernel(unsigned char *code, int code_len, const char *name);
+  static bool execute_warp(int dimX, int dimY, int dimZ, address kernel, PTXKernelArguments & ka, JavaValue &ret);
   static bool execute_kernel(address kernel, PTXKernelArguments & ka, JavaValue &ret);
 public:
 #if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64)
--- a/src/gpu/ptx/vm/kernelArguments.cpp	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +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.
- *
- */
-
-#include "precompiled.hpp"
-#include "kernelArguments.hpp"
-#include "runtime/javaCalls.hpp"
-
-gpu::Ptx::cuda_cu_memalloc_func_t gpu::Ptx::_cuda_cu_memalloc;
-gpu::Ptx::cuda_cu_memcpy_htod_func_t gpu::Ptx::_cuda_cu_memcpy_htod;
-
-// Get next java argument
-oop PTXKernelArguments::next_arg(BasicType expectedType) {
-  assert(_index < _args->length(), "out of bounds");
-  oop arg=((objArrayOop) (_args))->obj_at(_index++);
-  assert(expectedType == T_OBJECT || java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch");
-  return arg;
-}
-
-void PTXKernelArguments::do_int()    { 
-  // If the parameter is a return value, 
-  if (is_return_type()) {
-    // Allocate device memory for T_INT return value pointer on device. Size in bytes
-    int status = gpu::Ptx::_cuda_cu_memalloc(&_return_value_ptr, T_INT_BYTE_SIZE);
-    if (status != GRAAL_CUDA_SUCCESS) {
-      tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status);
-      _success = false;
-      return;
-    }
-    // Push _return_value_ptr to _kernelBuffer
-    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _return_value_ptr;
-    _bufferOffset += sizeof(_return_value_ptr);
-  }
-  else {
-    // Get the next java argument and its value which should be a T_INT
-    oop arg = next_arg(T_INT);
-    // Copy the java argument value to kernelArgBuffer
-    jvalue intval;
-    if (java_lang_boxing_object::get_value(arg, &intval) != T_INT) {
-      tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_INT");
-      _success = false;
-      return;
-    }
-    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = intval.i;
-    _bufferOffset += sizeof(intval.i);
-  }
-  return;
-}
-
-void PTXKernelArguments::do_long()    { 
-  // If the parameter is a return value, 
-  if (is_return_type()) {
-    // Allocate device memory for T_LONG return value pointer on device. Size in bytes
-    int status = gpu::Ptx::_cuda_cu_memalloc(&_return_value_ptr, T_LONG_BYTE_SIZE);
-    if (status != GRAAL_CUDA_SUCCESS) {
-      tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status);
-      _success = false;
-      return;
-    }
-    // Push _return_value_ptr to _kernelBuffer
-    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _return_value_ptr;
-    _bufferOffset += sizeof(_return_value_ptr);
-  }
-  else {
-    // Get the next java argument and its value which should be a T_LONG
-    oop arg = next_arg(T_LONG);
-    // Copy the java argument value to kernelArgBuffer
-    jvalue val;
-    if (java_lang_boxing_object::get_value(arg, &val) != T_LONG) {
-      tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_LONG");
-      _success = false;
-      return;
-    }
-    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = val.j;
-    _bufferOffset += sizeof(val.j);
-  }
-  return;
-}
-
-void PTXKernelArguments::do_byte()    { 
-  // If the parameter is a return value, 
-  if (is_return_type()) {
-    // Allocate device memory for T_BYTE return value pointer on device. Size in bytes
-    int status = gpu::Ptx::_cuda_cu_memalloc(&_return_value_ptr, T_BYTE_SIZE);
-    if (status != GRAAL_CUDA_SUCCESS) {
-      tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status);
-      _success = false;
-      return;
-    }
-    // Push _return_value_ptr to _kernelBuffer
-    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _return_value_ptr;
-    _bufferOffset += sizeof(_return_value_ptr);
-  }
-  else {
-    // Get the next java argument and its value which should be a T_BYTE
-    oop arg = next_arg(T_BYTE);
-    // Copy the java argument value to kernelArgBuffer
-    jvalue val;
-    if (java_lang_boxing_object::get_value(arg, &val) != T_BYTE) {
-      tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_BYTE");
-      _success = false;
-      return;
-    }
-    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = val.b;
-    _bufferOffset += sizeof(val.b);
-  }
-  return;
-}
-
-// TODO implement other do_*
--- a/src/gpu/ptx/vm/kernelArguments.hpp	Fri Sep 06 21:37:50 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,129 +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.
- *
- */
-
-#ifndef KERNEL_ARGUMENTS_PTX_HPP
-#define KERNEL_ARGUMENTS_PTX_HPP
-
-#include "runtime/gpu.hpp"
-#include "runtime/signature.hpp"
-
-#define T_BYTE_SIZE       1
-#define T_INT_BYTE_SIZE   4
-#define T_LONG_BYTE_SIZE  8
-
-class PTXKernelArguments : public SignatureIterator {
-public:
-  // Buffer holding CUdeviceptr values that represent the kernel arguments
-  char _kernelArgBuffer[1024];
-  // Current offset into _kernelArgBuffer
-  size_t _bufferOffset;
-  gpu::Ptx::CUdeviceptr _return_value_ptr;
-private:
-  // Array of java argument oops
-  arrayOop _args;
-  // Current index into _args
-  int _index;
-  // Flag to indicate successful creation of kernel argument buffer
-  bool _success;
-  // Get next java argument
-  oop next_arg(BasicType expectedType);
-
- public:
-  PTXKernelArguments(Symbol* signature, arrayOop args, bool is_static) : SignatureIterator(signature) {
-    this->_return_type = T_ILLEGAL;
-    _index = 0;
-    _args = args;
-    _success = true;
-    _bufferOffset = 0;
-    _return_value_ptr = 0;
-    if (!is_static) {
-      // TODO : Create a device argument for receiver object and add it to _kernelBuffer
-      tty->print_cr("{CUDA] ****** TODO: Support for execution of non-static java methods not implemented yet.");
-    }
-    // Iterate over the entire signature
-    iterate();
-    assert((_success && (_index == args->length())), "arg count mismatch with signature");
-  }
-
-  inline char* device_argument_buffer() {
-    return _kernelArgBuffer;
-  }
-
-  inline size_t device_argument_buffer_size() {
-    return _bufferOffset;
-  }
-
-  // Get the return oop value
-  oop get_return_oop();
-
-  // get device return value ptr
-  gpu::Ptx::CUdeviceptr get_return_value_ptr() {
-      return _return_value_ptr;
-  }
-
-  
-  void do_byte();
-  void do_int();
-  void do_long();
-
-  inline void do_bool()   {
-    /* TODO : To be implemented */ 
-    guarantee(false, "NYI");
-  }
-  inline void do_char()   {
-    /* TODO : To be implemented */ 
-    guarantee(false, "NYI");
-  }
-  inline void do_short()  {
-    /* TODO : To be implemented */ 
-    guarantee(false, "NYI");
-  }
-  inline void do_float()  {
-    /* TODO : To be implemented */ 
-    guarantee(false, "NYI");
-  }
-  inline void do_double() {
-    /* TODO : To be implemented */ 
-    guarantee(false, "NYI");
-  }
-
-  inline void do_object() {
-    /* TODO : To be implemented */ 
-    guarantee(false, "NYI");
-  }
-  inline void do_object(int begin, int end) {
-    /* TODO : To be implemented */ 
-    guarantee(false, "NYI");
-  }
-  inline void do_array(int begin, int end)  {
-    /* TODO : To be implemented */ 
-    guarantee(false, "NYI");
-  }
-  inline void do_void() {
-    /* TODO : To be implemented */ 
-    guarantee(false, "NYI");
-  }
-};
-
-#endif  // KERNEL_ARGUMENTS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/ptx/vm/ptxKernelArguments.cpp	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "ptxKernelArguments.hpp"
+#include "runtime/javaCalls.hpp"
+
+gpu::Ptx::cuda_cu_memalloc_func_t gpu::Ptx::_cuda_cu_memalloc;
+gpu::Ptx::cuda_cu_memcpy_htod_func_t gpu::Ptx::_cuda_cu_memcpy_htod;
+
+// Get next java argument
+oop PTXKernelArguments::next_arg(BasicType expectedType) {
+  assert(_index < _args->length(), "out of bounds");
+
+  oop arg = ((objArrayOop) (_args))->obj_at(_index++);
+  assert(expectedType == T_OBJECT ||
+         java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch");
+
+  return arg;
+}
+
+void PTXKernelArguments::do_int() {
+  if (is_after_invocation()) {
+    return;
+  }
+  // If the parameter is a return value,
+  if (is_return_type()) {
+    // Allocate device memory for T_INT return value pointer on device. Size in bytes
+    int status = gpu::Ptx::_cuda_cu_memalloc(&_return_value_ptr, T_INT_BYTE_SIZE);
+    if (status != GRAAL_CUDA_SUCCESS) {
+      tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status);
+      _success = false;
+      return;
+    }
+    // Push _return_value_ptr to _kernelBuffer
+    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _return_value_ptr;
+    _bufferOffset += sizeof(_return_value_ptr);
+  } else {
+    // Get the next java argument and its value which should be a T_INT
+    oop arg = next_arg(T_INT);
+    // Copy the java argument value to kernelArgBuffer
+    jvalue intval;
+    if (java_lang_boxing_object::get_value(arg, &intval) != T_INT) {
+      tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_INT");
+      _success = false;
+      return;
+    }
+    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = intval.i;
+    _bufferOffset += sizeof(intval.i);
+  }
+  return;
+}
+
+void PTXKernelArguments::do_long() {
+  if (is_after_invocation()) {
+    return;
+  }
+  // If the parameter is a return value,
+  if (is_return_type()) {
+    // Allocate device memory for T_LONG return value pointer on device. Size in bytes
+    int status = gpu::Ptx::_cuda_cu_memalloc(&_return_value_ptr, T_LONG_BYTE_SIZE);
+    if (status != GRAAL_CUDA_SUCCESS) {
+      tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status);
+      _success = false;
+      return;
+    }
+    // Push _return_value_ptr to _kernelBuffer
+    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _return_value_ptr;
+    _bufferOffset += sizeof(_return_value_ptr);
+  } else {
+    // Get the next java argument and its value which should be a T_LONG
+    oop arg = next_arg(T_LONG);
+    // Copy the java argument value to kernelArgBuffer
+    jvalue val;
+    if (java_lang_boxing_object::get_value(arg, &val) != T_LONG) {
+      tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_LONG");
+      _success = false;
+      return;
+    }
+    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = val.j;
+    _bufferOffset += sizeof(val.j);
+  }
+  return;
+}
+
+void PTXKernelArguments::do_byte() {
+    if (is_after_invocation()) {
+        return;
+    }
+    // If the parameter is a return value,
+    if (is_return_type()) {
+        // Allocate device memory for T_BYTE return value pointer on device. Size in bytes
+        int status = gpu::Ptx::_cuda_cu_memalloc(&_return_value_ptr, T_BYTE_SIZE);
+        if (status != GRAAL_CUDA_SUCCESS) {
+            tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status);
+            _success = false;
+            return;
+        }
+        // Push _return_value_ptr to _kernelBuffer
+        *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _return_value_ptr;
+        _bufferOffset += sizeof(_return_value_ptr);
+    } else {
+        // Get the next java argument and its value which should be a T_BYTE
+        oop arg = next_arg(T_BYTE);
+        // Copy the java argument value to kernelArgBuffer
+        jvalue val;
+        if (java_lang_boxing_object::get_value(arg, &val) != T_BYTE) {
+            tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_BYTE");
+            _success = false;
+            return;
+        }
+        *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = val.b;
+        _bufferOffset += sizeof(val.b);
+    }
+    return;
+}
+
+void PTXKernelArguments::do_array(int begin, int end) {
+    gpu::Ptx::CUdeviceptr _array_ptr;
+    int status;
+
+    // Get the next java argument and its value which should be a T_ARRAY
+    oop arg = next_arg(T_OBJECT);
+    int array_size = arg->size() * HeapWordSize;
+
+    if (is_after_invocation()) {
+        _array_ptr = *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]);
+        status = gpu::Ptx::_cuda_cu_memcpy_dtoh(arg, _array_ptr, array_size);
+        if (status != GRAAL_CUDA_SUCCESS) {
+            tty->print_cr("[CUDA] *** Error (%d) Failed to copy array argument to host", status);
+            _success = false;
+            return;
+        } else {
+            // tty->print_cr("device: %x host: %x size: %d", _array_ptr, arg, array_size);
+        }
+        return;
+    }
+    // Allocate device memory for T_ARRAY return value pointer on device. Size in bytes
+    status = gpu::Ptx::_cuda_cu_memalloc(&_return_value_ptr, array_size);
+    if (status != GRAAL_CUDA_SUCCESS) {
+        tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status);
+        _success = false;
+        return;
+    }
+    status = gpu::Ptx::_cuda_cu_memcpy_htod(_return_value_ptr, arg, array_size);
+    if (status != GRAAL_CUDA_SUCCESS) {
+        tty->print_cr("[CUDA] *** Error (%d) Failed to copy array to device argument", status);
+        _success = false;
+        return;
+    } else {
+        // tty->print_cr("host: %x device: %x size: %d", arg, _return_value_ptr, array_size);
+    }
+    // Push _return_value_ptr to _kernelBuffer
+    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _return_value_ptr;
+    _bufferOffset += sizeof(_return_value_ptr);
+    return;
+}
+
+void PTXKernelArguments::do_void() {
+    return;
+}
+
+// TODO implement other do_*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/ptx/vm/ptxKernelArguments.hpp	Wed Oct 02 13:26:31 2013 +0200
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef KERNEL_ARGUMENTS_PTX_HPP
+#define KERNEL_ARGUMENTS_PTX_HPP
+
+#include "runtime/gpu.hpp"
+#include "runtime/signature.hpp"
+
+#define T_BYTE_SIZE       1
+#define T_INT_BYTE_SIZE   4
+#define T_LONG_BYTE_SIZE  8
+#define T_ARRAY_BYTE_SIZE 8
+
+class PTXKernelArguments : public SignatureIterator {
+public:
+  // Buffer holding CUdeviceptr values that represent the kernel arguments
+  char _kernelArgBuffer[1024];
+  // Current offset into _kernelArgBuffer
+  size_t _bufferOffset;
+  gpu::Ptx::CUdeviceptr _return_value_ptr;
+private:
+  // Array of java argument oops
+  arrayOop _args;
+  // Current index into _args
+  int _index;
+  // Flag to indicate successful creation of kernel argument buffer
+  bool _success;
+
+    bool _afterInvoocation;
+  // Get next java argument
+  oop next_arg(BasicType expectedType);
+
+ public:
+  PTXKernelArguments(Symbol* signature, arrayOop args, bool is_static) : SignatureIterator(signature) {
+    this->_return_type = T_ILLEGAL;
+    _index = 0;
+    _args = args;
+    _success = true;
+    _bufferOffset = 0;
+    _return_value_ptr = 0;
+    if (!is_static) {
+      // TODO : Create a device argument for receiver object and add it to _kernelBuffer
+      tty->print_cr("{CUDA] ****** TODO: Support for execution of non-static java methods not implemented yet.");
+    }
+    // Iterate over the entire signature
+    iterate();
+    assert((_success && (_index == args->length())), "arg count mismatch with signature");
+  }
+
+  inline char* device_argument_buffer() {
+    return _kernelArgBuffer;
+  }
+
+  inline size_t device_argument_buffer_size() {
+    return _bufferOffset;
+  }
+
+    void reiterate() {
+        _afterInvoocation = true;
+        _bufferOffset = 0;
+        _index = 0;
+        iterate();
+    }
+
+    inline bool is_after_invocation() {
+        return _afterInvoocation;
+    }
+
+  // Get the return oop value
+  oop get_return_oop();
+
+  // get device return value ptr
+  gpu::Ptx::CUdeviceptr get_return_value_ptr() {
+      return _return_value_ptr;
+  }
+
+
+  void do_byte();
+  void do_int();
+  void do_long();
+  void do_array(int begin, int end);
+  void do_void();
+
+  inline void do_bool()   {
+    /* TODO : To be implemented */
+    guarantee(false, "do_bool:NYI");
+  }
+  inline void do_char()   {
+    /* TODO : To be implemented */
+    guarantee(false, "do_char:NYI");
+  }
+  inline void do_short()  {
+    /* TODO : To be implemented */
+    guarantee(false, "do_short:NYI");
+  }
+  inline void do_float()  {
+    /* TODO : To be implemented */
+    guarantee(false, "do_float:NYI");
+  }
+  inline void do_double() {
+    /* TODO : To be implemented */
+    guarantee(false, "do_double:NYI");
+  }
+
+  inline void do_object() {
+    /* TODO : To be implemented */
+    guarantee(false, "do_object:NYI");
+  }
+    
+  inline void do_object(int begin, int end) {
+    /* TODO : To be implemented */
+    guarantee(false, "do_object(II):NYI");
+  }
+
+};
+
+#endif  // KERNEL_ARGUMENTS_HPP
--- a/src/os_gpu/bsd_ptx/vm/gpu_bsd.cpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/os_gpu/bsd_ptx/vm/gpu_bsd.cpp	Wed Oct 02 13:26:31 2013 +0200
@@ -33,6 +33,7 @@
    * a better detection solution for NVIDA PTX and AMD HSAIL.
    */
   set_available(true);
+  set_target_il_type(gpu::PTX);
   if (TraceGPUInteraction) {
     tty->print_cr("gpu_bsd::probe_gpu(APPLE): %d", gpu::is_available());
   }
--- a/src/os_gpu/linux_ptx/vm/gpu_linux.cpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/os_gpu/linux_ptx/vm/gpu_linux.cpp	Wed Oct 02 13:26:31 2013 +0200
@@ -39,32 +39,40 @@
  */
 
 static unsigned int nvidia_vendor_id = 0x10de;
+static unsigned int amd_vendor_id = 0x1002;
 
 bool gpu::Linux::probe_gpu() {
   /* 
-   * Open /proc/bus/pci/devices to look for the first CUDA enabled
-   * device. For now, finding the first CUDA device. Will need to
-   * revisit this to support execution on multiple CUDA devices if
-   * they exist.
+   * Open /proc/bus/pci/devices to look for the first GPU device. For
+   * now, we will just find the first GPU device. Will need to revisit
+   * this to support execution on multiple GPU devices, if they exist.
    */
   FILE *pci_devices = fopen("/proc/bus/pci/devices", "r");
   char contents[4096];
   unsigned int bus_num_devfn_ign;
   unsigned int vendor;
   unsigned int device;
-  bool cuda_device_exists = false;
+  bool gpu_device_exists = false;
   if (pci_devices == NULL) {
     tty->print_cr("*** Failed to open /proc/bus/pci/devices");
-    return cuda_device_exists;
+    return gpu_device_exists;
   }
 
   while (fgets(contents, sizeof(contents)-1, pci_devices)) {
     sscanf(contents, "%04x%04x%04x", &bus_num_devfn_ign, &vendor, &device);
-    /* Break after finding the first CUDA device. */
+    /* Break after finding the first GPU device. */
     if (vendor == nvidia_vendor_id) {
-      cuda_device_exists = true;
+      gpu_device_exists = true;
+      set_target_il_type(gpu::PTX);
       if (TraceGPUInteraction) {
-        tty->print_cr("Found supported nVidia CUDA device vendor : 0x%04x device 0x%04x", vendor, device);
+        tty->print_cr("Found supported nVidia GPU device vendor : 0x%04x device 0x%04x", vendor, device);
+      }
+      break;
+    } else if (vendor == amd_vendor_id) {
+      gpu_device_exists = true;
+      set_target_il_type(gpu::HSAIL);
+      if (TraceGPUInteraction) {
+        tty->print_cr("Found supported AMD GPU device vendor : 0x%04x device 0x%04x", vendor, device);
       }
       break;
     }
@@ -73,5 +81,5 @@
   // Close file pointer.
   fclose(pci_devices);
 
-  return cuda_device_exists;
+  return gpu_device_exists;
 }
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputNode.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputNode.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,7 +23,9 @@
  */
 package com.sun.hotspot.igv.data;
 
+import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.List;
 
 /**
  *
@@ -32,6 +34,7 @@
 public class InputNode extends Properties.Entity {
 
     private int id;
+    private List<InputGraph> subgraphs;
 
     public static final Comparator<InputNode> COMPARATOR = new Comparator<InputNode>() {
         @Override
@@ -81,6 +84,17 @@
         return id;
     }
 
+    public void addSubgraph(InputGraph graph) {
+        if (subgraphs == null) {
+            subgraphs = new ArrayList<>();
+        }
+        subgraphs.add(graph);
+    }
+
+    public List<InputGraph> getSubgraphs() {
+        return subgraphs;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (!(o instanceof InputNode)) {
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Wed Oct 02 13:26:31 2013 +0200
@@ -62,6 +62,7 @@
     private static final int PROPERTY_TRUE = 0x05;
     private static final int PROPERTY_FALSE = 0x06;
     private static final int PROPERTY_ARRAY = 0x07;
+    private static final int PROPERTY_SUBGRAPH = 0x08;
     
     private static final String NO_BLOCK = "noBlock";
     
@@ -522,6 +523,10 @@
                     default:
                         throw new IOException("Unknown type");
                 }
+            case PROPERTY_SUBGRAPH:
+                InputGraph graph = parseGraph(null);
+                new Group(null).addElement(graph);
+                return graph;
             default:
                 throw new IOException("Unknown type");
         }
@@ -612,6 +617,10 @@
             monitor.updateProgress();
         }
         String title = readPoolObject(String.class);
+        return parseGraph(title);
+    }
+
+    private InputGraph parseGraph(String title) throws IOException {
         InputGraph graph = new InputGraph(title);
         parseNodes(graph);
         parseBlocks(graph);
@@ -666,8 +675,14 @@
                     key = "!data." + key;
                 }
                 Object value = readPropertyObject();
-                properties.setProperty(key, value != null ? value.toString() : "null");
-                props.put(key, value);
+                if (value instanceof InputGraph) {
+                    InputGraph subgraph = (InputGraph) value;
+                    subgraph.getProperties().setProperty("name", node.getId() + ":" + key);
+                    node.addSubgraph((InputGraph) value);
+                } else {
+                    properties.setProperty(key, value != null ? value.toString() : "null");
+                    props.put(key, value);
+                }
             }
             int edgesStart = edges.size();
             int suxCount = readShort();
--- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java	Wed Oct 02 13:26:31 2013 +0200
@@ -119,6 +119,7 @@
             Figure f = d.createFigure();
             f.getSource().addSourceNode(n);
             f.getProperties().add(n.getProperties());
+            f.setSubgraphs(n.getSubgraphs());
             figureHash.put(n.getId(), f);
         }
 
--- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,6 +23,7 @@
  */
 package com.sun.hotspot.igv.graph;
 
+import com.sun.hotspot.igv.data.InputGraph;
 import com.sun.hotspot.igv.data.InputNode;
 import com.sun.hotspot.igv.data.Properties;
 import com.sun.hotspot.igv.data.Source;
@@ -51,6 +52,7 @@
     private Point position;
     private List<Figure> predecessors;
     private List<Figure> successors;
+    private List<InputGraph> subgraphs;
     private Color color;
     private int id;
     private String idString;
@@ -177,6 +179,14 @@
         successors.remove(f);
     }
 
+    public List<InputGraph> getSubgraphs() {
+        return subgraphs;
+    }
+
+    public void setSubgraphs(List<InputGraph> subgraphs) {
+        this.subgraphs = subgraphs;
+    }
+
     @Override
     public void setPosition(Point p) {
         this.position = p;
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java	Wed Oct 02 13:26:31 2013 +0200
@@ -69,7 +69,7 @@
 import org.openide.windows.WindowManager;
 
 /**
- * 
+ *
  * @author Thomas Wuerthinger
  */
 public final class EditorTopComponent extends TopComponent implements PropertyChangeListener {
@@ -140,7 +140,7 @@
     };
 
     private ChangedEvent<DiagramProvider> diagramChangedEvent = new ChangedEvent<>(diagramProvider);
-    
+
 
     private void updateDisplayName() {
         setDisplayName(getDiagram().getName());
@@ -254,6 +254,11 @@
         toolBar.add(Box.createHorizontalGlue());
         Action action = Utilities.actionsForPath("QuickSearchShadow").get(0);
         Component quicksearch = ((Presenter.Toolbar) action).getToolbarPresenter();
+        try {
+            // (aw) workaround for disappearing search bar due to reparenting one shared component instance.
+            quicksearch = (Component) quicksearch.getClass().getConstructor(KeyStroke.class).newInstance(new Object[]{null});
+        } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
+        }
         quicksearch.setMinimumSize(quicksearch.getPreferredSize()); // necessary for GTK LAF
         toolBar.add(quicksearch);
 
@@ -420,7 +425,7 @@
             graphContent.set(list, null);
             diagramProvider.getChangedEvent().fire();
         }
-        
+
     };
 
     public boolean showPredSucc() {
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java	Wed Oct 02 13:26:31 2013 +0200
@@ -23,16 +23,20 @@
  */
 package com.sun.hotspot.igv.view.widgets;
 
+import com.sun.hotspot.igv.data.InputGraph;
 import com.sun.hotspot.igv.data.Properties;
+import com.sun.hotspot.igv.data.services.GraphViewer;
 import com.sun.hotspot.igv.graph.Figure;
 import com.sun.hotspot.igv.util.DoubleClickAction;
 import com.sun.hotspot.igv.util.DoubleClickHandler;
 import com.sun.hotspot.igv.util.PropertiesSheet;
 import com.sun.hotspot.igv.view.DiagramScene;
 import java.awt.*;
+import java.awt.event.ActionEvent;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
+import javax.swing.AbstractAction;
 import javax.swing.Action;
 import javax.swing.BorderFactory;
 import javax.swing.JMenu;
@@ -49,6 +53,7 @@
 import org.openide.nodes.Children;
 import org.openide.nodes.Node;
 import org.openide.nodes.Sheet;
+import org.openide.util.Lookup;
 
 /**
  *
@@ -272,6 +277,27 @@
         successors.addMenuListener(new NeighborMenuListener(successors, getFigure(), true));
         menu.add(successors);
 
+        if (getFigure().getSubgraphs() != null) {
+            menu.addSeparator();
+            JMenu subgraphs = new JMenu("Subgraphs");
+            menu.add(subgraphs);
+
+            final GraphViewer viewer = Lookup.getDefault().lookup(GraphViewer.class);
+            for(final InputGraph subgraph : getFigure().getSubgraphs()) {
+                Action a = new AbstractAction() {
+
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        viewer.view(subgraph, true);
+                    }
+                };
+
+                a.setEnabled(true);
+                a.putValue(Action.NAME, subgraph.getName());
+                subgraphs.add(a);
+            }
+        }
+
         return menu;
     }
 
--- a/src/share/vm/classfile/vmSymbols.hpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Wed Oct 02 13:26:31 2013 +0200
@@ -311,6 +311,7 @@
   template(com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType,  "com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType")       \
   template(com_oracle_graal_hotspot_meta_HotSpotMonitorValue,        "com/oracle/graal/hotspot/meta/HotSpotMonitorValue")             \
   template(com_oracle_graal_hotspot_debug_LocalImpl,                 "com/oracle/graal/hotspot/debug/LocalImpl")                      \
+  template(com_oracle_graal_hotspot_ptx_PTXHotSpotGraalRuntime,      "com/oracle/graal/hotspot/ptx/PTXHotSpotGraalRuntime")\
   AMD64_ONLY(template(com_oracle_graal_hotspot_amd64_AMD64HotSpotGraalRuntime,"com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime"))\
   SPARC_ONLY(template(com_oracle_graal_hotspot_sparc_SPARCHotSpotGraalRuntime,"com/oracle/graal/hotspot/sparc/SPARCHotSpotGraalRuntime"))\
   /* graal.api.meta */                                                                                                                \
@@ -356,6 +357,7 @@
   template(compileMethod_signature,               "(JLcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;IZ)V")                  \
   template(setOption_name,                        "setOption")                                                                        \
   template(setOption_signature,                   "(Ljava/lang/String;)Z")                                                            \
+  template(finalizeOptions_name,                  "finalizeOptions")                                                                  \
   template(createUnresolvedJavaMethod_name,       "createUnresolvedJavaMethod")                                                       \
   template(createUnresolvedJavaMethod_signature,  "(Ljava/lang/String;Ljava/lang/String;Lcom/oracle/graal/api/meta/JavaType;)Lcom/oracle/graal/api/meta/JavaMethod;") \
   template(createSignature_name,                  "createSignature")                                                                  \
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Wed Oct 02 13:26:31 2013 +0200
@@ -727,7 +727,7 @@
 
   oop debug_info = CompilationResult_Call::debugInfo(site);
 
-  assert((hotspot_method ? 1 : 0) + (foreign_call ? 1 : 0) == 1, "Call site needs exactly one type");
+  assert(!!hotspot_method ^ !!foreign_call, "Call site needs exactly one type");
 
   NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset);
   jint next_pc_offset = CodeInstaller::pd_next_offset(inst, pc_offset, hotspot_method);
@@ -810,27 +810,11 @@
         _next_call_type = (MarkId) id;
         _invoke_mark_pc = pc;
         break;
-      case MARK_POLL_NEAR: {
-        NativeInstruction* ni = nativeInstruction_at(pc);
-        int32_t* disp = (int32_t*) pd_locate_operand(pc);
-        // int32_t* disp = (int32_t*) Assembler::locate_operand(instruction, Assembler::disp32_operand);
-        int32_t offset = *disp; // The Java code installed the polling page offset into the disp32 operand
-        intptr_t new_disp = (intptr_t) (os::get_polling_page() + offset) - (intptr_t) ni;
-        *disp = (int32_t)new_disp;
-      }
+      case MARK_POLL_NEAR:
       case MARK_POLL_FAR:
-        _instructions->relocate(pc, relocInfo::poll_type);
-        break;
-      case MARK_POLL_RETURN_NEAR: {
-        NativeInstruction* ni = nativeInstruction_at(pc);
-        int32_t* disp = (int32_t*) pd_locate_operand(pc);
-        // int32_t* disp = (int32_t*) Assembler::locate_operand(instruction, Assembler::disp32_operand);
-        int32_t offset = *disp; // The Java code installed the polling page offset into the disp32 operand
-        intptr_t new_disp = (intptr_t) (os::get_polling_page() + offset) - (intptr_t) ni;
-        *disp = (int32_t)new_disp;
-      }
+      case MARK_POLL_RETURN_NEAR:
       case MARK_POLL_RETURN_FAR:
-        _instructions->relocate(pc, relocInfo::poll_return_type);
+        pd_relocate_poll(pc, id);
         break;
       default:
         ShouldNotReachHere();
--- a/src/share/vm/graal/graalCodeInstaller.hpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.hpp	Wed Oct 02 13:26:31 2013 +0200
@@ -80,7 +80,7 @@
   void pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst);
   void pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination);
   void pd_relocate_JavaMethod(oop method, jint pc_offset);
-  int32_t* pd_locate_operand(address instruction);
+  void pd_relocate_poll(address pc, jint mark);
 
 public:
 
--- a/src/share/vm/graal/graalCompiler.cpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp	Wed Oct 02 13:26:31 2013 +0200
@@ -95,6 +95,8 @@
         vm_abort(false);
       }
     }
+    VMToCompiler::finalizeOptions(CITime);
+
     if (UseCompiler) {
       VMToCompiler::startCompiler(BootstrapGraal);
       _initialized = true;
--- a/src/share/vm/graal/graalCompilerToGPU.cpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToGPU.cpp	Wed Oct 02 13:26:31 2013 +0200
@@ -28,7 +28,7 @@
 #include "graal/graalJavaAccess.hpp"
 #include "runtime/gpu.hpp"
 #include "runtime/javaCalls.hpp"
-# include "ptx/vm/kernelArguments.hpp"
+# include "ptx/vm/ptxKernelArguments.hpp"
 
 // Entry to native method implementation that transitions current thread to '_thread_in_vm'.
 #define C2V_VMENTRY(result_type, name, signature) \
@@ -103,6 +103,45 @@
 
 C2V_END
 
+C2V_VMENTRY(jobject, executeParallelMethodVarargs, (JNIEnv *env,
+                                                          jobject,
+                                                          jint dimX, jint dimY, jint dimZ,
+                                                          jobject args, jobject hotspotInstalledCode))
+  ResourceMark rm;
+  HandleMark hm;
+
+  if (gpu::is_available() == false || gpu::has_gpu_linkage() == false && gpu::is_initialized()) {
+    tty->print_cr("executeParallelMethodVarargs - not available / no linkage / not initialized");
+    return NULL;
+  }
+  jlong nmethodValue = HotSpotInstalledCode::codeBlob(hotspotInstalledCode);
+  nmethod* nm = (nmethod*) (address) nmethodValue;
+  methodHandle mh = nm->method();
+  Symbol* signature = mh->signature();
+
+  // start value is the kernel
+  jlong startValue = HotSpotInstalledCode::codeStart(hotspotInstalledCode);
+
+  PTXKernelArguments ptxka(signature, (arrayOop) JNIHandles::resolve(args), mh->is_static());
+  JavaValue result(ptxka.get_ret_type());
+if (!gpu::execute_warp(dimX, dimY, dimZ, (address)startValue, ptxka, result)) {
+    return NULL;
+  }
+
+  if (ptxka.get_ret_type() == T_VOID) {
+    return NULL;
+  } else if (ptxka.get_ret_type() == T_OBJECT || ptxka.get_ret_type() == T_ARRAY) {
+    return JNIHandles::make_local((oop) result.get_jobject());
+  } else {
+    oop o = java_lang_boxing_object::create(ptxka.get_ret_type(), (jvalue *) result.get_value_addr(), CHECK_NULL);
+    if (TraceGPUInteraction) {
+      tty->print_cr("GPU execution returned %d", result.get_jint());
+    }
+    return JNIHandles::make_local(o);
+  }
+
+C2V_END
+
 C2V_VMENTRY(jboolean, deviceInit, (JNIEnv *env, jobject))
   if (gpu::is_available() == false || gpu::has_gpu_linkage() == false) {
     tty->print_cr("deviceInit - not available / no linkage");
@@ -116,6 +155,14 @@
   return gpu::is_initialized();
 C2V_END
 
+C2V_VMENTRY(jint, availableProcessors, (JNIEnv *env, jobject))
+  if (gpu::is_available() == false || gpu::has_gpu_linkage() == false) {
+    tty->print_cr("deviceInit - not available / no linkage");
+    return false;
+  }
+  return gpu::available_processors();
+C2V_END
+
 C2V_VMENTRY(jboolean, deviceDetach, (JNIEnv *env, jobject))
 return true;
 C2V_END
@@ -157,10 +204,12 @@
 #define GPUSPACE_METHOD       "J"
 
 JNINativeMethod CompilerToGPU_methods[] = {
-  {CC"generateKernel",                CC"([B" STRING ")"GPUSPACE_METHOD,        FN_PTR(generateKernel)},
-  {CC"deviceInit",                    CC"()Z",                                  FN_PTR(deviceInit)},
-  {CC"deviceDetach",                  CC"()Z",                                  FN_PTR(deviceDetach)},
-  {CC"executeExternalMethodVarargs",  CC"(["OBJECT HS_INSTALLED_CODE")"OBJECT,  FN_PTR(executeExternalMethodVarargs)},
+  {CC"generateKernel",                CC"([B" STRING ")"GPUSPACE_METHOD,          FN_PTR(generateKernel)},
+  {CC"deviceInit",                    CC"()Z",                                    FN_PTR(deviceInit)},
+  {CC"deviceDetach",                  CC"()Z",                                    FN_PTR(deviceDetach)},
+  {CC"availableProcessors",           CC"()I",                                    FN_PTR(availableProcessors)},
+  {CC"executeExternalMethodVarargs",  CC"(["OBJECT HS_INSTALLED_CODE")"OBJECT,    FN_PTR(executeExternalMethodVarargs)},
+  {CC"executeParallelMethodVarargs",  CC"(III["OBJECT HS_INSTALLED_CODE")"OBJECT, FN_PTR(executeParallelMethodVarargs)},
 };
 
 int CompilerToGPU_methods_count() {
--- a/src/share/vm/graal/graalVMToCompiler.cpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.cpp	Wed Oct 02 13:26:31 2013 +0200
@@ -24,6 +24,7 @@
 #include "precompiled.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "graal/graalVMToCompiler.hpp"
+#include "runtime/gpu.hpp"
 
 // this is a *global* handle
 jobject VMToCompiler::_graalRuntimePermObject = NULL;
@@ -60,7 +61,16 @@
 Handle VMToCompiler::graalRuntime() {
   if (JNIHandles::resolve(_graalRuntimePermObject) == NULL) {
 #ifdef AMD64
-    Symbol* name = vmSymbols::com_oracle_graal_hotspot_amd64_AMD64HotSpotGraalRuntime();
+    Symbol* name = NULL;
+    // Set name to PTXHotSpotRuntime if nVidia GPU was detected.
+    if (UseGPU && (gpu::get_target_il_type() == gpu::PTX) &&
+        gpu::is_available() && gpu::has_gpu_linkage()) {
+      name = vmSymbols::com_oracle_graal_hotspot_ptx_PTXHotSpotGraalRuntime();
+    }
+    
+    if (name == NULL) {
+      name = vmSymbols::com_oracle_graal_hotspot_amd64_AMD64HotSpotGraalRuntime();
+    }
 #endif
 #ifdef SPARC
     Symbol* name = vmSymbols::com_oracle_graal_hotspot_sparc_SPARCHotSpotGraalRuntime();
@@ -90,23 +100,33 @@
 }
 
 void VMToCompiler::initOptions() {
-  KlassHandle compilerKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotOptions());
+  KlassHandle optionsKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotOptions());
   Thread* THREAD = Thread::current();
-  compilerKlass->initialize(THREAD);
+  optionsKlass->initialize(THREAD);
   check_pending_exception("Error while calling initOptions");
 }
 
 jboolean VMToCompiler::setOption(Handle option) {
   assert(!option.is_null(), "");
-  KlassHandle compilerKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotOptions());
+  KlassHandle optionsKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotOptions());
 
   Thread* THREAD = Thread::current();
   JavaValue result(T_BOOLEAN);
-  JavaCalls::call_static(&result, compilerKlass, vmSymbols::setOption_name(), vmSymbols::setOption_signature(), option, THREAD);
+  JavaCalls::call_static(&result, optionsKlass, vmSymbols::setOption_name(), vmSymbols::setOption_signature(), option, THREAD);
   check_pending_exception("Error while calling setOption");
   return result.get_jboolean();
 }
 
+void VMToCompiler::finalizeOptions(jboolean ciTime) {
+  KlassHandle optionsKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotOptions());
+  Thread* THREAD = Thread::current();
+  JavaValue result(T_VOID);
+  JavaCallArguments args;
+  args.push_int(ciTime);
+  JavaCalls::call_static(&result, optionsKlass, vmSymbols::finalizeOptions_name(), vmSymbols::bool_void_signature(), &args, THREAD);
+  check_pending_exception("Error while calling finalizeOptions");
+}
+
 void VMToCompiler::compileMethod(Method* method, Handle holder, int entry_bci, jboolean blocking) {
   assert(method != NULL, "just checking");
   assert(!holder.is_null(), "just checking");
--- a/src/share/vm/graal/graalVMToCompiler.hpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.hpp	Wed Oct 02 13:26:31 2013 +0200
@@ -57,6 +57,9 @@
   // public static boolean HotSpotOptions.setOption(String option);
   static jboolean setOption(Handle option);
 
+  // public static void HotSpotOptions.finalizeOptions(boolean ciTime);
+  static void finalizeOptions(jboolean ciTime);
+
   // public abstract boolean compileMethod(long vmId, String name, int entry_bci, boolean blocking);
   static void compileMethod(Method* method, Handle holder, int entry_bci, jboolean blocking);
 
--- a/src/share/vm/runtime/globals.hpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/vm/runtime/globals.hpp	Wed Oct 02 13:26:31 2013 +0200
@@ -3717,8 +3717,11 @@
   product(bool , AllowNonVirtualCalls, false,                               \
           "Obey the ACC_SUPER flag and allow invokenonvirtual calls")       \
                                                                             \
-  product(bool, TraceGPUInteraction, false,                                    \
-          "Trace external GPU warp loading")                                \
+  product(bool, TraceGPUInteraction, false,                                 \
+          "Trace external GPU Interaction")                                 \
+                                                                            \
+  product(bool, UseGPU, false,                                              \
+          "Run code on GPU")                                                \
                                                                             \
   diagnostic(ccstr, SharedArchiveFile, NULL,                                \
           "Override the default location of the CDS archive file")          \
--- a/src/share/vm/runtime/gpu.cpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/vm/runtime/gpu.cpp	Wed Oct 02 13:26:31 2013 +0200
@@ -25,14 +25,69 @@
 #include "precompiled.hpp"
 #include "runtime/gpu.hpp"
 
-bool gpu::_available = false;   // does the hardware exist?
-bool gpu::_gpu_linkage = false; // is the driver library to access the GPU installed
-bool gpu::_initialized = false; // is the GPU device initialized
+bool gpu::_available = false;    // does the hardware exist?
+bool gpu::_gpu_linkage = false;  // is the driver library to access the GPU installed
+bool gpu::_initialized = false;  // is the GPU device initialized
+gpu::TargetGPUIL gpu::_targetIL = gpu::NONE; // No GPU detected yet.
 
 void gpu::init() {
 #if defined(TARGET_OS_FAMILY_bsd) || defined(TARGET_OS_FAMILY_linux)
   gpu::probe_gpu();
+  if (gpu::get_target_il_type() == gpu::PTX) {
+    set_gpu_linkage(gpu::Ptx::probe_linkage());
+  } else {
+    set_gpu_linkage(false);
+  }
 #endif
-  // need multi-gpu TARGET ifdef
-  gpu::probe_linkage();
+}
+
+void gpu::initialize_gpu() {
+  if (gpu::has_gpu_linkage()) {
+    if (gpu::get_target_il_type() == gpu::PTX) {
+      set_initialized(gpu::Ptx::initialize_gpu());
+    }
+    // Add initialization of other GPUs here
+  }
+}
+
+void * gpu::generate_kernel(unsigned char *code, int code_len, const char *name) {
+  if (gpu::has_gpu_linkage()) {
+    if (gpu::get_target_il_type() == gpu::PTX) {
+      return (gpu::Ptx::generate_kernel(code, code_len, name));
+    }
+    // Add kernel generation functionality of other GPUs here
+  }
+  return NULL;
 }
+
+bool gpu::execute_kernel(address kernel, PTXKernelArguments & ptxka, JavaValue& ret) {
+    if (gpu::has_gpu_linkage()) {
+        if (gpu::get_target_il_type() == gpu::PTX) {
+            return (gpu::Ptx::execute_kernel(kernel, ptxka, ret));
+        }
+        // Add kernel execution functionality of other GPUs here
+    }
+    return false;
+}
+
+bool gpu::execute_warp(int dimX, int dimY, int dimZ,
+                       address kernel, PTXKernelArguments & ptxka, JavaValue& ret) {
+    if (gpu::has_gpu_linkage()) {
+        if (gpu::get_target_il_type() == gpu::PTX) {
+            return (gpu::Ptx::execute_warp(dimX, dimY, dimZ, kernel, ptxka, ret));
+        }
+        // Add kernel execution functionality of other GPUs here
+    }
+    return false;
+}
+
+int gpu::available_processors() {
+    if (gpu::has_gpu_linkage()) {
+        if (gpu::get_target_il_type() == gpu::PTX) {
+            return (gpu::Ptx::total_cores());
+        }
+        // Add kernel execution functionality of other GPUs here
+    }
+    return 0;
+}
+
--- a/src/share/vm/runtime/gpu.hpp	Fri Sep 06 21:37:50 2013 +0200
+++ b/src/share/vm/runtime/gpu.hpp	Wed Oct 02 13:26:31 2013 +0200
@@ -36,16 +36,21 @@
 
 class gpu: AllStatic {
 public:
+
+  enum TargetGPUIL { NONE = 0, PTX = 1, HSAIL = 2};
   static void init(void);
 
   static void probe_gpu();
 
-  static void probe_linkage();
-  
   static void initialize_gpu();
+
+  static int available_processors();
   
   static void * generate_kernel(unsigned char *code, int code_len, const char *name);
 
+  static bool execute_warp(int dimX, int dimY, int dimZ,
+                           address kernel, PTXKernelArguments & ptxka, JavaValue & ret);
+
   static bool execute_kernel(address kernel, PTXKernelArguments & ptxka, JavaValue & ret);
 
   static void set_available(bool value) {
@@ -66,10 +71,19 @@
 
   static bool has_gpu_linkage() { return _gpu_linkage; }
 
+  static void set_target_il_type(TargetGPUIL value) {
+    _targetIL = value;
+  }
+
+  static enum gpu::TargetGPUIL get_target_il_type() {
+    return _targetIL;
+  }
+
 protected:
   static bool _available;
   static bool _gpu_linkage;
   static bool _initialized;
+  static TargetGPUIL _targetIL;
 
   // Platform dependent stuff
 #ifdef TARGET_OS_FAMILY_linux