changeset 15451:3774b6f4319b

Merge with 2f684eda1938cc92a72a35461c8d00f1871fe389
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Tue, 29 Apr 2014 12:43:27 -0700
parents be0c151d912b (current diff) 2f684eda1938 (diff)
children 625f779255a7
files graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRBlock.java graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRControlFlowGraph.java graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRFrameStateBuilder.java graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRLoop.java graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/LIRProviders.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/LIRTypeTool.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResult.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResultBase.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenResLowerable.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FieldIntrospection.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/UnsafeAccess.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryLogicNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalLongUnitTest.java graal/com.oracle.graal.test/src/com/oracle/graal/test/LongTest.java test/baseline_whitelist.txt
diffstat 489 files changed, 14318 insertions(+), 6246 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Apr 29 12:05:58 2014 -0700
+++ b/.hgignore	Tue Apr 29 12:43:27 2014 -0700
@@ -87,3 +87,4 @@
 agent/build/*
 agent/make/filelist
 agent/make/sa17.tar.gz
+export.json
--- a/CHANGELOG.md	Tue Apr 29 12:05:58 2014 -0700
+++ b/CHANGELOG.md	Tue Apr 29 12:43:27 2014 -0700
@@ -8,6 +8,7 @@
 * Added graal.version system property to Graal enabled VM builds.
 * Transitioned to JDK 8 as minimum JDK level for Graal.
 * Added support for stack introspection.
+* New MatchRule facility to convert multiple HIR nodes into specialized LIR
 * ...
 
 ### Truffle
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -93,4 +93,9 @@
      * Gets a description of the target architecture.
      */
     TargetDescription getTarget();
+
+    /**
+     * Create a new speculation log for the target runtime.
+     */
+    SpeculationLog createSpeculationLog();
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.api.code;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -342,7 +341,7 @@
         int sigCount = sig.getParameterCount(false);
         JavaType[] argTypes;
         int argIndex = 0;
-        if (!Modifier.isStatic(method.getModifiers())) {
+        if (!method.isStatic()) {
             argTypes = new JavaType[sigCount + 1];
             argTypes[argIndex++] = method.getDeclaringClass();
         } else {
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Tue Apr 29 12:43:27 2014 -0700
@@ -432,22 +432,20 @@
 
         private static final long serialVersionUID = 3612943150662354844L;
         public final Object id;
-        public final Mark[] references;
 
-        public Mark(int pcOffset, Object id, Mark[] references) {
+        public Mark(int pcOffset, Object id) {
             super(pcOffset);
             this.id = id;
-            this.references = references;
         }
 
         @Override
         public String toString() {
             if (id == null) {
-                return String.format("%d[<mark with %d references>]", pcOffset, references.length);
+                return String.format("%d[<mar>]", pcOffset);
             } else if (id instanceof Integer) {
-                return String.format("%d[<mark with %d references and id %s>]", pcOffset, references.length, Integer.toHexString((Integer) id));
+                return String.format("%d[<mark with id %s>]", pcOffset, Integer.toHexString((Integer) id));
             } else {
-                return String.format("%d[<mark with %d references and id %s>]", pcOffset, references.length, id.toString());
+                return String.format("%d[<mark with id %s>]", pcOffset, id.toString());
             }
         }
     }
@@ -635,10 +633,9 @@
      *
      * @param codePos the position in the code that is covered by the handler
      * @param markId the identifier for this mark
-     * @param references an array of other marks that this mark references
      */
-    public Mark recordMark(int codePos, Object markId, Mark[] references) {
-        Mark mark = new Mark(codePos, markId, references);
+    public Mark recordMark(int codePos, Object markId) {
+        Mark mark = new Mark(codePos, markId);
         marks.add(mark);
         return mark;
     }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,8 +23,6 @@
 package com.oracle.graal.api.code;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -83,7 +81,7 @@
 
     /**
      * Derives hint information for use when generating the code for a type check instruction.
-     * 
+     *
      * @param targetType the target type of the type check
      * @param profile the profiling information available for the instruction (if any)
      * @param assumptions the object in which speculations are recorded. This is null if
@@ -151,10 +149,10 @@
     /**
      * Determines if a given type can have subtypes other than itself. This analysis is purely
      * static; no assumptions are made.
-     * 
+     *
      * @return true if {@code type} can have subtypes
      */
     public static boolean canHaveSubtype(ResolvedJavaType type) {
-        return !isFinal(getElementalType(type).getModifiers());
+        return !getElementalType(type).isFinal();
     }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,7 +27,7 @@
 public interface StackIntrospection {
 
     /**
-     * Accesses the current stack, returning a collection of {@long InspectedFrame}s that can be
+     * Accesses the current stack, returning a collection of {@link InspectedFrame}s that can be
      * used to inspect the stack frames' contents.
      *
      * @param initialMethods if this is non-{@code null}, then the stack trace will start at these
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.api.meta.test;
 
-import static java.lang.reflect.Modifier.*;
 import static org.junit.Assert.*;
 
 import java.lang.annotation.*;
@@ -52,9 +51,9 @@
             if (code == null) {
                 assertTrue(m.getCodeSize() == 0);
             } else {
-                if (isAbstract(m.getModifiers())) {
+                if (m.isAbstract()) {
                     assertTrue(code.length == 0);
-                } else if (!isNative(m.getModifiers())) {
+                } else if (!m.isNative()) {
                     assertTrue(code.length > 0);
                 }
             }
@@ -69,9 +68,9 @@
         for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
             ResolvedJavaMethod m = e.getValue();
             int codeSize = m.getCodeSize();
-            if (isAbstract(m.getModifiers())) {
+            if (m.isAbstract()) {
                 assertTrue(codeSize == 0);
-            } else if (!isNative(m.getModifiers())) {
+            } else if (!m.isNative()) {
                 assertTrue(codeSize > 0);
             }
         }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.api.meta;
 
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
@@ -146,7 +144,7 @@
 
         public ProfiledType(ResolvedJavaType type, double probability) {
             super(type, probability);
-            assert type.isArray() || !isAbstract(type.getModifiers()) : type;
+            assert type.isArray() || !type.isAbstract() : type;
         }
 
         /**
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.api.meta;
 
-import static java.lang.reflect.Modifier.*;
-
 import java.io.*;
 import java.lang.annotation.*;
 import java.lang.reflect.*;
@@ -378,7 +376,7 @@
                         break;
                     }
                     case 'f': {
-                        sb.append(!(method instanceof ResolvedJavaMethod) ? "unresolved" : isStatic(((ResolvedJavaMethod) method).getModifiers()) ? "static" : "virtual");
+                        sb.append(!(method instanceof ResolvedJavaMethod) ? "unresolved" : ((ResolvedJavaMethod) method).isStatic() ? "static" : "virtual");
                         break;
                     }
                     case '%': {
@@ -452,7 +450,7 @@
                         break;
                     }
                     case 'f': {
-                        sb.append(!(field instanceof ResolvedJavaField) ? "unresolved" : isStatic(((ResolvedJavaField) field).getModifiers()) ? "static" : "instance");
+                        sb.append(!(field instanceof ResolvedJavaField) ? "unresolved" : ((ResolvedJavaField) field).isStatic() ? "static" : "instance");
                         break;
                     }
                     case '%': {
@@ -561,7 +559,7 @@
     }
 
     public static JavaType[] signatureToTypes(ResolvedJavaMethod method) {
-        JavaType receiver = isStatic(method.getModifiers()) ? null : method.getDeclaringClass();
+        JavaType receiver = method.isStatic() ? null : method.getDeclaringClass();
         return signatureToTypes(method.getSignature(), receiver);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ModifiersProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+import static java.lang.reflect.Modifier.*;
+
+import java.lang.reflect.*;
+
+/**
+ * A Java element (i.e., a class, interface, field or method) that is described by a set of Java
+ * language {@linkplain #getModifiers() modifiers}.
+ */
+public interface ModifiersProvider {
+
+    /**
+     * Returns the Java language modifiers for this element.
+     */
+    int getModifiers();
+
+    /**
+     * see {@link Modifier#isInterface(int)}
+     */
+    default boolean isInterface() {
+        return Modifier.isInterface(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isSynchronized(int)}
+     */
+    default boolean isSynchronized() {
+        return Modifier.isSynchronized(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isStatic(int)}
+     */
+    default boolean isStatic() {
+        return Modifier.isStatic(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isFinal(int)}
+     */
+    default boolean isFinal() {
+        return Modifier.isFinal(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isPublic(int)}
+     */
+    default boolean isPublic() {
+        return Modifier.isPublic(getModifiers());
+    }
+
+    /**
+     * Determines if this element is neither {@linkplain #isPublic() public},
+     * {@linkplain #isProtected() protected} nor {@linkplain #isPrivate() private}.
+     */
+    default boolean isPackagePrivate() {
+        return ((PUBLIC | PROTECTED | PRIVATE) & getModifiers()) == 0;
+    }
+
+    /**
+     * see {@link Modifier#isPrivate(int)}
+     */
+    default boolean isPrivate() {
+        return Modifier.isPrivate(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isProtected(int)}
+     */
+    default boolean isProtected() {
+        return Modifier.isProtected(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isTransient(int)}
+     */
+    default boolean isTransient() {
+        return Modifier.isTransient(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isStrict(int)}
+     */
+    default boolean isStrict() {
+        return Modifier.isStrict(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isVolatile(int)}
+     */
+    default boolean isVolatile() {
+        return Modifier.isVolatile(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isNative(int)}
+     */
+    default boolean isNative() {
+        return Modifier.isNative(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isAbstract(int)}
+     */
+    default boolean isAbstract() {
+        return Modifier.isAbstract(getModifiers());
+    }
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Tue Apr 29 12:43:27 2014 -0700
@@ -29,12 +29,13 @@
  * Represents a reference to a resolved Java field. Fields, like methods and types, are resolved
  * through {@link ConstantPool constant pools}.
  */
-public interface ResolvedJavaField extends JavaField, LocationIdentity {
+public interface ResolvedJavaField extends JavaField, LocationIdentity, ModifiersProvider {
 
     /**
-     * Returns the Java language modifiers for this field, as an integer. The {@link Modifier} class
-     * should be used to decode the modifiers. Only the {@linkplain Modifier#fieldModifiers() field
-     * flags} specified in the JVM specification will be included in the returned mask.
+     * {@inheritDoc}
+     * <p>
+     * Only the {@linkplain Modifier#fieldModifiers() field flags} specified in the JVM
+     * specification will be included in the returned mask.
      */
     int getModifiers();
 
@@ -53,7 +54,7 @@
      * 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 this field is not considered
@@ -65,7 +66,7 @@
      * 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 {@linkplain #readConstantValue(Constant) 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.
      * @return the value of this field or {@code null} if the value is not available (e.g., because
@@ -82,7 +83,7 @@
     /**
      * Returns the annotation for the specified type of this field, if such an annotation is
      * present.
-     * 
+     *
      * @param annotationClass the Class object corresponding to the annotation type
      * @return this element's annotation for the specified annotation type if present on this field,
      *         else {@code null}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Tue Apr 29 12:43:27 2014 -0700
@@ -29,7 +29,7 @@
  * Represents a resolved Java method. Methods, like fields and types, are resolved through
  * {@link ConstantPool constant pools}.
  */
-public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget {
+public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersProvider {
 
     /**
      * Returns the bytecode of this method, if the method has code. The returned byte array does not
@@ -69,10 +69,10 @@
     int getMaxStackSize();
 
     /**
-     * Returns the Java language modifiers for this method, as an integer. The {@link Modifier}
-     * class should be used to decode the modifiers. Only the
-     * {@linkplain Modifier#methodModifiers() method flags} specified in the JVM specification will
-     * be included in the returned mask.
+     * {@inheritDoc}
+     * <p>
+     * Only the {@linkplain Modifier#methodModifiers() method flags} specified in the JVM
+     * specification will be included in the returned mask.
      */
     int getModifiers();
 
@@ -115,8 +115,6 @@
      */
     boolean canBeStaticallyBound();
 
-    boolean isSynchronized();
-
     /**
      * Returns the list of exception handlers for this method.
      */
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Tue Apr 29 12:43:27 2014 -0700
@@ -31,7 +31,7 @@
  * thereof. Types, like fields and methods, are resolved through {@link ConstantPool constant pools}
  * .
  */
-public interface ResolvedJavaType extends JavaType {
+public interface ResolvedJavaType extends JavaType, ModifiersProvider {
 
     /**
      * Represents each of the several different parts of the runtime representation of a type which
@@ -54,7 +54,7 @@
     /**
      * Gets the encoding of (that is, a constant representing the value of) the specified part of
      * this type.
-     * 
+     *
      * @param r the part of this type
      * @return a constant representing a reference to the specified part of this type
      */
@@ -62,7 +62,7 @@
 
     /**
      * Checks whether this type has a finalizer method.
-     * 
+     *
      * @return {@code true} if this class has a finalizer
      */
     boolean hasFinalizer();
@@ -70,51 +70,52 @@
     /**
      * Checks whether this type has any finalizable subclasses so far. Any decisions based on this
      * information require the registration of a dependency, since this information may change.
-     * 
+     *
      * @return {@code true} if this class has any subclasses with finalizers
      */
     boolean hasFinalizableSubclass();
 
     /**
      * Checks whether this type is an interface.
-     * 
+     *
      * @return {@code true} if this type is an interface
      */
     boolean isInterface();
 
     /**
      * Checks whether this type is an instance class.
-     * 
+     *
      * @return {@code true} if this type is an instance class
      */
     boolean isInstanceClass();
 
     /**
      * Checks whether this type is an array class.
-     * 
+     *
      * @return {@code true} if this type is an array class
      */
     boolean isArray();
 
     /**
      * Checks whether this type is primitive.
-     * 
+     *
      * @return {@code true} if this type is primitive
      */
     boolean isPrimitive();
 
     /**
-     * Returns the Java language modifiers for this type, as an integer. The {@link Modifier} class
-     * should be used to decode the modifiers. Only the flags specified in the JVM specification
-     * will be included in the returned mask. This method is identical to
-     * {@link Class#getModifiers()} in terms of the value return for this type.
+     * {@inheritDoc}
+     * <p>
+     * Only the flags specified in the JVM specification will be included in the returned mask. This
+     * method is identical to {@link Class#getModifiers()} in terms of the value return for this
+     * type.
      */
     int getModifiers();
 
     /**
      * 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
      */
     boolean isInitialized();
@@ -127,7 +128,7 @@
     /**
      * Checks whether this type is linked and verified. When a type is linked the static initializer
      * has not necessarily run. An {@link #isInitialized() initialized} type is always linked.
-     * 
+     *
      * @return {@code true} if this type is linked
      */
     boolean isLinked();
@@ -141,7 +142,7 @@
 
     /**
      * Checks whether the specified object is an instance of this type.
-     * 
+     *
      * @param obj the object to test
      * @return {@code true} if the object is an instance of this type
      */
@@ -150,7 +151,7 @@
     /**
      * Returns this type if it is an exact type otherwise returns null. This type is exact if it is
      * void, primitive, final, or an array of a final or primitive type.
-     * 
+     *
      * @return this type if it is exact; {@code null} otherwise
      */
     ResolvedJavaType asExactType();
@@ -172,7 +173,7 @@
     /**
      * Walks the class hierarchy upwards and returns the least common class that is a superclass of
      * both the current and the given type.
-     * 
+     *
      * @return the least common type that is a super type of both the current and the given type, or
      *         {@code null} if primitive types are involved.
      */
@@ -194,7 +195,7 @@
      * <p>
      * If the compiler uses the result of this method for its compilation, it must register an
      * assumption because dynamic class loading can invalidate the result of this method.
-     * 
+     *
      * @return the unique concrete subclass for this type as described above
      */
     ResolvedJavaType findUniqueConcreteSubtype();
@@ -208,7 +209,7 @@
      * 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 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
@@ -223,7 +224,7 @@
      * <p>
      * If the compiler uses the result of this method for its compilation, it must register an
      * assumption because dynamic class loading can invalidate the result of this method.
-     * 
+     *
      * @param method the method A for which a unique concrete target is searched
      * @return the unique concrete target or {@code null} if no such target exists or assumptions
      *         are not supported by this runtime
@@ -237,7 +238,7 @@
      * is, for a single JVM execution the same order is returned each time this method is called. It
      * is also the "natural" order, which means that the JVM would expect the fields in this order
      * if no specific order is given.
-     * 
+     *
      * @param includeSuperclasses if true, then instance fields for the complete hierarchy of this
      *            type are included in the result
      * @return an array of instance fields
@@ -247,7 +248,7 @@
     /**
      * Returns the annotation for the specified type of this class, if such an annotation is
      * present.
-     * 
+     *
      * @param annotationClass the Class object corresponding to the annotation type
      * @return this element's annotation for the specified annotation type if present on this class,
      *         else {@code null}
@@ -257,7 +258,7 @@
     /**
      * Returns the instance field of this class (or one of its super classes) at the given offset,
      * or {@code null} if there is no such field.
-     * 
+     *
      * @param offset the offset of the field to look for
      * @return the field with the given offset, or {@code null} if there is no such field.
      */
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Tue Apr 29 12:43:27 2014 -0700
@@ -40,12 +40,30 @@
         }
     };
 
+    /**
+     * This is the Value of a node which was matched as part of a complex match. The value isn't
+     * actually useable but this marks it as having been evaluated.
+     */
+    @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(Kind.Illegal) {
+
+        @Override
+        public String toString() {
+            return "INTERIOR_MATCH";
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            // This class is a singleton
+            return other != null && getClass() == other.getClass();
+        }
+    };
+
     private final Kind kind;
     private final PlatformKind platformKind;
 
     /**
      * Initializes a new value of the specified kind.
-     * 
+     *
      * @param platformKind the kind
      */
     protected Value(PlatformKind platformKind) {
--- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Tue Apr 29 12:43:27 2014 -0700
@@ -136,6 +136,11 @@
         emitAddrOp("lda_global_u64", dest, addr);
     }
 
+    public final void emitLea(Value dest, HSAILAddress addr) {
+        String prefix = getArgType(dest);
+        emitString(String.format("add_%s %s, $%s, 0x%s;", prefix, HSAIL.mapRegister(dest), addr.getBase().name, Long.toHexString(addr.getDisplacement())));
+    }
+
     public final void emitLoadKernelArg(Value dest, String kernArgName, String argTypeStr) {
         emitString("ld_kernarg_" + argTypeStr + " " + HSAIL.mapRegister(dest) + ", [" + kernArgName + "];");
     }
@@ -250,6 +255,9 @@
             case Byte:
                 prefix = "s8";
                 break;
+            case Boolean:
+                prefix = "u8";
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -548,6 +556,17 @@
     }
 
     /**
+     * Emits an atomic_exch_global instruction.
+     *
+     * @param result result operand that gets the original contents of the memory location
+     * @param address the memory location
+     * @param newValue the new value to write to the memory location
+     */
+    public void emitAtomicExch(Kind accessKind, AllocatableValue result, HSAILAddress address, Value newValue) {
+        emitString(String.format("atomic_exch_global_b%d   %s, %s, %s;", getArgSizeFromKind(accessKind), HSAIL.mapRegister(result), mapAddress(address), mapRegOrConstToString(newValue)));
+    }
+
+    /**
      * Emits a comment. Useful for debugging purposes.
      *
      * @param comment
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAddress.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAddress.java	Tue Apr 29 12:43:27 2014 -0700
@@ -30,11 +30,6 @@
 
 public class SPARCAddress extends AbstractAddress {
 
-    /**
-     * Stack bias for stack and frame pointer loads.
-     */
-    private static final int STACK_BIAS = 0x7ff;
-
     private final Register base;
     private final Register index;
     private final int displacement;
@@ -42,7 +37,7 @@
     /**
      * Creates an {@link SPARCAddress} with given base register, no scaling and a given
      * displacement.
-     * 
+     *
      * @param base the base register
      * @param displacement the displacement
      */
@@ -54,7 +49,7 @@
 
     /**
      * Creates an {@link SPARCAddress} with given base register, no scaling and a given index.
-     * 
+     *
      * @param base the base register
      * @param index the index register
      */
@@ -113,7 +108,7 @@
     /**
      * This method adds the stack-bias to the displacement if the base register is either
      * {@link SPARC#sp} or {@link SPARC#fp}.
-     * 
+     *
      * @return Optional additive displacement.
      */
     public int getDisplacement() {
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Tue Apr 29 12:43:27 2014 -0700
@@ -37,7 +37,7 @@
 
     /**
      * Constructs an assembler for the SPARC architecture.
-     * 
+     *
      * @param registerConfig the register configuration used to bind {@link Register#Frame} and
      *            {@link Register#CallerFrame} to physical registers. This value can be null if this
      *            assembler instance will not be used to assemble instructions using these logical
@@ -50,7 +50,7 @@
     // @formatter:off
     /**
      * Instruction format for sethi.
-     * 
+     *
      * | 00  |  rd    | op2 |               imm22                     |
      * |31 30|29    25|24 22|21                                      0|
      */
@@ -123,7 +123,7 @@
     // @formatter:off
     /**
      * Instruction format for branches.
-     * 
+     *
      * | 00  |a | cond | op2 |             disp22                      |
      * |31 30|29|28  25|24 22|21                                      0|
      */
@@ -142,7 +142,7 @@
     // @formatter:off
     /**
      * Instruction format for conditional branches.
-     * 
+     *
      * | 00  |a | cond | op2 |cc1|cc0|p |             disp19           |
      * |31 30|29|28  25|24 22|21 |20 |19|                             0|
      */
@@ -330,7 +330,7 @@
     // @formatter:off
     /**
      * Instruction format for calls.
-     * 
+     *
      * | 01  |                      disp30                             |
      * |31 30|29                                                      0|
      */
@@ -457,7 +457,7 @@
     // @formatter:off
     /**
      * Instruction format for Arithmetic, Logical, Moves, Tcc, Prefetch, and Misc.
-     * 
+     *
      * | 10  |   rd   |   op3   |   rs1   | i|     imm_asi   |   rs2   |
      * | 10  |   rd   |   op3   |   rs1   | i|          simm13         |
      * | 10  |   rd   |   op3   |   rs1   | i| x|            |   rs2   |
@@ -594,7 +594,7 @@
     // @formatter:off
     /**
      * Instruction format for Loads, Stores and Misc.
-     * 
+     *
      * | 11  |   rd   |   op3   |   rs1   | i|   imm_asi   |   rs2   |
      * | 11  |   rd   |   op3   |   rs1   | i|        simm13         |
      * |31 30|29    25|24     19|18     14|13|12          5|4       0|
@@ -749,7 +749,7 @@
     // @formatter:off
     /**
      * Instruction format for Movcc.
-     * 
+     *
      * | 10  |   rd   |   op3   |cc2|   cond  | i|cc1|cc0|      -      |   rs2   |
      * | 10  |   rd   |   op3   |cc2|   cond  | i|cc1|cc0|        simm11         |
      * |31 30|29    25|24     19| 18|17     14|13| 12| 11|10          5|4       0|
@@ -1007,7 +1007,7 @@
         Wrreg(0x30, "wrreg"),
         Saved(0x31, "saved"),
 
-        Fpop1(0x34, "fpop1"),
+        Fpop1(0b11_0100, "fpop1"),
         Fpop2(0x35, "fpop2"),
         Impdep1(0x36, "impdep1"),
         Impdep2(0x37, "impdep2"),
@@ -1036,14 +1036,14 @@
         Ldx(0b001011, "ldx"),
         Stx(0b001110, "stx"),
 
-        Ldf(0x20, "ldf"),
+        Ldf(0b100000, "ldf"),
         Ldfsr(0x21, "ldfsr"),
         Ldaf(0x22, "ldaf"),
-        Lddf(0x23, "lddf"),
-        Stf(0x24, "stf"),
+        Lddf(0b100011, "lddf"),
+        Stf(0b100100, "stf"),
         Stfsr(0x25, "stfsr"),
         Staf(0x26, "staf"),
-        Stdf(0x27, "stdf");
+        Stdf(0b100111, "stdf");
 
         // @formatter:on
 
@@ -1092,9 +1092,9 @@
     public enum Opfs {
         // @formatter:off
 
-        Fmovs(0x01, "fmovs"),
-        Fmovd(0x02, "fmovd"),
-        Fmovq(0x03, "fmovq"),
+        Fmovs(0b0_0000_0001, "fmovs"),
+        Fmovd(0b0_0000_0010, "fmovd"),
+        Fmovq(0b0_0000_0011, "fmovq"),
         Fnegs(0x05, "fnegs"),
         Fnegd(0x06, "fnegd"),
         Fnegq(0x07, "fnegq"),
@@ -2376,6 +2376,20 @@
         }
     }
 
+    public static class Fmovs extends Fmt3p {
+
+        public Fmovs(Register src, Register dst) {
+            super(Ops.ArithOp, Op3s.Fpop1, Opfs.Fmovs, g0, src, dst);
+        }
+    }
+
+    public static class Fmovd extends Fmt3p {
+
+        public Fmovd(Register src, Register dst) {
+            super(Ops.ArithOp, Op3s.Fpop1, Opfs.Fmovd, g0, src, dst);
+        }
+    }
+
     public static class Fmuls extends Fmt3p {
 
         public Fmuls(Register src1, Register src2, Register dst) {
@@ -3174,6 +3188,20 @@
         }
     }
 
+    public static class Stdf extends Fmt11 {
+
+        public Stdf(Register dst, SPARCAddress src) {
+            super(Op3s.Stdf, src, dst);
+        }
+    }
+
+    public static class Stf extends Fmt11 {
+
+        public Stf(Register dst, SPARCAddress src) {
+            super(Op3s.Stf, src, dst);
+        }
+    }
+
     public static class Sth extends Fmt11 {
 
         public Sth(Register dst, SPARCAddress addr) {
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Tue Apr 29 12:43:27 2014 -0700
@@ -44,13 +44,13 @@
 import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.phases.*;
 
-public class BaselineBytecodeParser extends AbstractBytecodeParser<Value, LIRFrameStateBuilder> implements BytecodeParserTool {
+public class BaselineBytecodeParser extends AbstractBytecodeParser<Value, BaselineFrameStateBuilder> implements BytecodeParserTool {
     private Backend backend;
-    protected LIRGenerator gen;
+    protected LIRGeneratorTool gen;
     private LIRGenerationResult lirGenRes;
     private BytecodeLIRBuilder lirBuilder;
     @SuppressWarnings("unused") private BciBlock[] loopHeaders;
@@ -74,7 +74,7 @@
     }
 
     public BaselineBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
-                    LIRFrameStateBuilder frameState, BytecodeStream stream, ProfilingInfo profilingInfo, ConstantPool constantPool, int entryBCI, Backend backend) {
+                    BaselineFrameStateBuilder frameState, BytecodeStream stream, ProfilingInfo profilingInfo, ConstantPool constantPool, int entryBCI, Backend backend) {
 
         super(metaAccess, method, graphBuilderConfig, optimisticOpts, frameState, stream, profilingInfo, constantPool, entryBCI);
         this.backend = backend;
@@ -109,7 +109,7 @@
                 throw GraalInternalError.unimplemented("Handle synchronized methods");
             }
 
-            frameState = new LIRFrameStateBuilder(method);
+            frameState = new BaselineFrameStateBuilder(method);
             frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true);
 
             currentBlock = blockMap.startBlock;
@@ -121,7 +121,7 @@
             // add loops ? how do we add looks when we haven't parsed the bytecode?
 
             // create the control flow graph
-            LIRControlFlowGraph cfg = new LIRControlFlowGraph(blockMap);
+            BaselineControlFlowGraph cfg = new BaselineControlFlowGraph(blockMap);
 
             BlocksToDoubles blockProbabilities = new BlocksToDoubles(blockMap.blocks.size());
             for (BciBlock b : blockMap.blocks) {
@@ -608,7 +608,7 @@
         }
 
         // We already saw this block before, so we have to merge states.
-        if (!((LIRFrameStateBuilder) block.entryState).isCompatibleWith(frameState)) {
+        if (!((BaselineFrameStateBuilder) block.entryState).isCompatibleWith(frameState)) {
             throw new BailoutException("stacks do not match; bytecodes would not verify");
         }
 
@@ -616,7 +616,7 @@
             assert currentBlock == null || currentBlock.getId() >= block.getId() : "must be backward branch";
             if (currentBlock != null && currentBlock.numNormalSuccessors() == 1) {
                 // this is the only successor of the current block so we can adjust
-                adaptFramestate((LIRFrameStateBuilder) block.entryState);
+                adaptFramestate((BaselineFrameStateBuilder) block.entryState);
                 return;
             }
             GraalInternalError.unimplemented("Loops not yet supported");
@@ -630,7 +630,7 @@
          */
         if (currentBlock != null && currentBlock.numNormalSuccessors() == 1) {
             // this is the only successor of the current block so we can adjust
-            adaptFramestate((LIRFrameStateBuilder) block.entryState);
+            adaptFramestate((BaselineFrameStateBuilder) block.entryState);
             return;
         }
         GraalInternalError.unimplemented("second block visit not yet implemented");
@@ -674,7 +674,7 @@
         }
     }
 
-    private void adaptFramestate(LIRFrameStateBuilder other) {
+    private void adaptFramestate(BaselineFrameStateBuilder other) {
         assert frameState.isCompatibleWith(other) : "framestates not compatible!";
         PhiResolver resolver = new PhiResolver(gen);
         for (int i = 0; i < frameState.stackSize(); i++) {
@@ -692,7 +692,7 @@
 
     @Override
     protected void processBlock(BciBlock block) {
-        frameState = (LIRFrameStateBuilder) block.entryState;
+        frameState = (BaselineFrameStateBuilder) block.entryState;
         setCurrentFrameState(frameState);
         currentBlock = block;
         iterateBytecodesForBlock(block);
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Tue Apr 29 12:43:27 2014 -0700
@@ -57,7 +57,7 @@
         ConstantPool constantPool = method.getConstantPool();
         TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
 
-        LIRFrameStateBuilder frameState = new LIRFrameStateBuilder(method);
+        BaselineFrameStateBuilder frameState = new BaselineFrameStateBuilder(method);
 
         BaselineBytecodeParser parser = new BaselineBytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, frameState, stream, profilingInfo, constantPool, entryBCI, backend);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineControlFlowGraph.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.baseline;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.BciBlockMapping.BciBlock;
+
+public class BaselineControlFlowGraph implements AbstractControlFlowGraph<BciBlock> {
+
+    private BciBlock[] blocks;
+    private Collection<Loop<BciBlock>> loops;
+    private BitSet visited;
+
+    public BaselineControlFlowGraph(BciBlockMapping blockMap) {
+        blocks = blockMap.blocks.toArray(new BciBlock[0]);
+        loops = new ArrayList<>();
+        computeLoopInformation();
+    }
+
+    public BciBlock[] getBlocks() {
+        return blocks;
+    }
+
+    public Collection<Loop<BciBlock>> getLoops() {
+        return loops;
+    }
+
+    public BciBlock getStartBlock() {
+        if (blocks.length > 0) {
+            return blocks[0];
+        }
+        return null;
+    }
+
+    private void computeLoopInformation() {
+        visited = new BitSet(blocks.length);
+        Deque<BaselineLoop> stack = new ArrayDeque<>();
+        for (int i = blocks.length - 1; i >= 0; i--) {
+            BciBlock block = blocks[i];
+            calcLoop(block, stack);
+        }
+    }
+
+    private void calcLoop(BciBlock block, Deque<BaselineLoop> stack) {
+        if (visited.get(block.getId())) {
+            return;
+        }
+        visited.set(block.getId());
+        if (block.isLoopEnd()) {
+            BciBlock loopHeader = getLoopHeader(block);
+            BaselineLoop l = new BaselineLoop(stack.peek(), loops.size(), loopHeader);
+            loops.add(l);
+            stack.push(l);
+        }
+        block.loop = stack.peek();
+        if (block.isLoopHeader()) {
+            assert block.loop.header.equals(block);
+            stack.pop();
+        }
+        for (BciBlock pred : block.getPredecessors()) {
+            calcLoop(pred, stack);
+        }
+    }
+
+    private static BciBlock getLoopHeader(BciBlock block) {
+        assert block.isLoopEnd();
+        for (BciBlock sux : block.getSuccessors()) {
+            if (sux.isLoopHeader() && sux.getId() <= block.getId() && block.loops == sux.loops) {
+                return sux;
+            }
+        }
+        throw GraalInternalError.shouldNotReachHere("No loop header found for " + block);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineFrameStateBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.baseline;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.java.*;
+
+public class BaselineFrameStateBuilder extends AbstractFrameStateBuilder<Value, BaselineFrameStateBuilder> {
+
+    private static final Value[] EMPTY_ARRAY = new Value[0];
+
+    public BaselineFrameStateBuilder(ResolvedJavaMethod method) {
+        // we always need at least one stack slot (for exceptions)
+        super(method, new Value[method.getMaxLocals()], new Value[Math.max(1, method.getMaxStackSize())], EMPTY_ARRAY);
+    }
+
+    protected BaselineFrameStateBuilder(BaselineFrameStateBuilder other) {
+        super(other);
+    }
+
+    @Override
+    protected Value[] getEmtpyArray() {
+        return EMPTY_ARRAY;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[locals: [");
+        for (int i = 0; i < locals.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString());
+        }
+        sb.append("] stack: [");
+        for (int i = 0; i < stackSize; i++) {
+            sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString());
+        }
+        sb.append("] locks: [");
+        for (int i = 0; i < lockedObjects.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString());
+        }
+        sb.append("]");
+        if (rethrowException) {
+            sb.append(" rethrowException");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    @Override
+    public BaselineFrameStateBuilder copy() {
+        return new BaselineFrameStateBuilder(this);
+    }
+
+    private static boolean isCompatible(Value x, Value y) {
+        if (x == null && y == null) {
+            return true;
+        }
+        if ((x == null || y == null) || (x.getKind() != y.getKind())) {
+            return false;
+        }
+        return true;
+
+    }
+
+    @Override
+    public boolean isCompatibleWith(BaselineFrameStateBuilder other) {
+        assert method.equals(other.method) && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
+
+        if (stackSize() != other.stackSize()) {
+            return false;
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            if (!isCompatible(stackAt(i), other.stackAt(i))) {
+                return false;
+            }
+        }
+        if (lockedObjects.length != other.lockedObjects.length) {
+            return false;
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineLoop.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.baseline;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.java.BciBlockMapping.BciBlock;
+
+public class BaselineLoop extends Loop<BciBlock> {
+
+    protected BaselineLoop(Loop<BciBlock> parent, int index, BciBlock header) {
+        super(parent, index, header);
+    }
+
+    @Override
+    public long numBackedges() {
+        // currently only loops with one backedge are supported
+        return 1;
+    }
+
+}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRBlock.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.baseline;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.common.cfg.*;
-
-public class LIRBlock extends AbstractBlockBase<LIRBlock> {
-
-    public LIRBlock(int id) {
-        this.id = id;
-        predecessors = Collections.emptyList();
-        successors = Collections.emptyList();
-    }
-
-    public Loop<LIRBlock> getLoop() {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public int getLoopDepth() {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
-    public boolean isLoopEnd() {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    public boolean isLoopHeader() {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    public boolean isExceptionEntry() {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRControlFlowGraph.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.baseline;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-
-public class LIRControlFlowGraph implements AbstractControlFlowGraph<BciBlock> {
-
-    private BciBlock[] blocks;
-    private Collection<Loop<BciBlock>> loops;
-    private BitSet visited;
-
-    public LIRControlFlowGraph(BciBlockMapping blockMap) {
-        blocks = blockMap.blocks.toArray(new BciBlock[0]);
-        loops = new ArrayList<>();
-        computeLoopInformation();
-    }
-
-    public BciBlock[] getBlocks() {
-        return blocks;
-    }
-
-    public Collection<Loop<BciBlock>> getLoops() {
-        return loops;
-    }
-
-    public BciBlock getStartBlock() {
-        if (blocks.length > 0) {
-            return blocks[0];
-        }
-        return null;
-    }
-
-    private void computeLoopInformation() {
-        visited = new BitSet(blocks.length);
-        Deque<LIRLoop> stack = new ArrayDeque<>();
-        for (int i = blocks.length - 1; i >= 0; i--) {
-            BciBlock block = blocks[i];
-            calcLoop(block, stack);
-        }
-    }
-
-    private void calcLoop(BciBlock block, Deque<LIRLoop> stack) {
-        if (visited.get(block.getId())) {
-            return;
-        }
-        visited.set(block.getId());
-        if (block.isLoopEnd()) {
-            BciBlock loopHeader = getLoopHeader(block);
-            LIRLoop l = new LIRLoop(stack.peek(), loops.size(), loopHeader);
-            loops.add(l);
-            stack.push(l);
-        }
-        block.loop = stack.peek();
-        if (block.isLoopHeader()) {
-            assert block.loop.header.equals(block);
-            stack.pop();
-        }
-        for (BciBlock pred : block.getPredecessors()) {
-            calcLoop(pred, stack);
-        }
-    }
-
-    private static BciBlock getLoopHeader(BciBlock block) {
-        assert block.isLoopEnd();
-        for (BciBlock sux : block.getSuccessors()) {
-            if (sux.isLoopHeader() && sux.getId() <= block.getId() && block.loops == sux.loops) {
-                return sux;
-            }
-        }
-        throw GraalInternalError.shouldNotReachHere("No loop header found for " + block);
-    }
-
-}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRFrameStateBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.baseline;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.java.*;
-
-public class LIRFrameStateBuilder extends AbstractFrameStateBuilder<Value, LIRFrameStateBuilder> {
-
-    private static final Value[] EMPTY_ARRAY = new Value[0];
-
-    public LIRFrameStateBuilder(ResolvedJavaMethod method) {
-        // we always need at least one stack slot (for exceptions)
-        super(method, new Value[method.getMaxLocals()], new Value[Math.max(1, method.getMaxStackSize())], EMPTY_ARRAY);
-    }
-
-    protected LIRFrameStateBuilder(LIRFrameStateBuilder other) {
-        super(other);
-    }
-
-    @Override
-    protected Value[] getEmtpyArray() {
-        return EMPTY_ARRAY;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("[locals: [");
-        for (int i = 0; i < locals.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString());
-        }
-        sb.append("] stack: [");
-        for (int i = 0; i < stackSize; i++) {
-            sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString());
-        }
-        sb.append("] locks: [");
-        for (int i = 0; i < lockedObjects.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString());
-        }
-        sb.append("]");
-        if (rethrowException) {
-            sb.append(" rethrowException");
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
-    @Override
-    public LIRFrameStateBuilder copy() {
-        return new LIRFrameStateBuilder(this);
-    }
-
-    private static boolean isCompatible(Value x, Value y) {
-        if (x == null && y == null) {
-            return true;
-        }
-        if ((x == null || y == null) || (x.getKind() != y.getKind())) {
-            return false;
-        }
-        return true;
-
-    }
-
-    @Override
-    public boolean isCompatibleWith(LIRFrameStateBuilder other) {
-        assert method.equals(other.method) && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
-
-        if (stackSize() != other.stackSize()) {
-            return false;
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            if (!isCompatible(stackAt(i), other.stackAt(i))) {
-                return false;
-            }
-        }
-        if (lockedObjects.length != other.lockedObjects.length) {
-            return false;
-        }
-        return true;
-    }
-}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRLoop.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.baseline;
-
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-
-public class LIRLoop extends Loop<BciBlock> {
-
-    protected LIRLoop(Loop<BciBlock> parent, int index, BciBlock header) {
-        super(parent, index, header);
-    }
-
-    @Override
-    public long numBackedges() {
-        // currently only loops with one backedge are supported
-        return 1;
-    }
-
-}
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -38,7 +38,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.amd64.*;
@@ -70,8 +69,7 @@
 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp;
 import com.oracle.graal.lir.amd64.AMD64Move.ZeroExtendLoadOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -265,6 +263,25 @@
         }
     }
 
+    public void emitCompareBranchMemory(Kind cmpKind, Value left, AMD64AddressValue right, LIRFrameState state, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
+                    double trueLabelProbability) {
+        boolean mirrored = emitCompareMemory(cmpKind, left, right, state);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        switch (left.getKind().getStackKind()) {
+            case Int:
+            case Long:
+            case Object:
+                append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+                break;
+            case Float:
+            case Double:
+                append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("" + left.getKind());
+        }
+    }
+
     @Override
     public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability) {
         append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow, overflowProbability));
@@ -345,6 +362,26 @@
         }
     }
 
+    /**
+     * This method emits the compare against memory instruction, and may reorder the operands. It
+     * returns true if it did so.
+     *
+     * @param b the right operand of the comparison
+     * @return true if the left and right operands were switched, false otherwise
+     */
+    private boolean emitCompareMemory(Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state) {
+        boolean mirrored;
+        if (LIRValueUtil.isVariable(a)) {
+            Variable left = load(a);
+            emitCompareRegMemoryOp(cmpKind, left, b, state);
+            mirrored = false;
+        } else {
+            emitCompareMemoryConOp(cmpKind, b, a, state);
+            mirrored = true;
+        }
+        return mirrored;
+    }
+
     protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, Value value, LIRFrameState state) {
         assert kind.getStackKind() == value.getKind().getStackKind();
         switch (kind) {
@@ -590,8 +627,7 @@
         append(new DivRemOp(op, rax, asAllocatable(b), state));
     }
 
-    public Value[] emitIntegerDivRem(Value a, Value b, DeoptimizingNode deopting) {
-        LIRFrameState state = state(deopting);
+    public Value[] emitIntegerDivRem(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
                 emitDivRem(IDIVREM, a, b, state);
@@ -605,13 +641,13 @@
     }
 
     @Override
-    public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                emitDivRem(IDIV, a, b, state(deopting));
+                emitDivRem(IDIV, a, b, state);
                 return emitMove(RAX_I);
             case Long:
-                emitDivRem(LDIV, a, b, state(deopting));
+                emitDivRem(LDIV, a, b, state);
                 return emitMove(RAX_L);
             case Float: {
                 Variable result = newVariable(a.getPlatformKind());
@@ -629,13 +665,13 @@
     }
 
     @Override
-    public Value emitRem(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                emitDivRem(IREM, a, b, state(deopting));
+                emitDivRem(IREM, a, b, state);
                 return emitMove(RDX_I);
             case Long:
-                emitDivRem(LREM, a, b, state(deopting));
+                emitDivRem(LREM, a, b, state);
                 return emitMove(RDX_L);
             case Float: {
                 Variable result = newVariable(a.getPlatformKind());
@@ -653,8 +689,7 @@
     }
 
     @Override
-    public Variable emitUDiv(Value a, Value b, DeoptimizingNode deopting) {
-        LIRFrameState state = state(deopting);
+    public Variable emitUDiv(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
                 emitDivRem(IUDIV, a, b, state);
@@ -668,8 +703,7 @@
     }
 
     @Override
-    public Variable emitURem(Value a, Value b, DeoptimizingNode deopting) {
-        LIRFrameState state = state(deopting);
+    public Variable emitURem(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
                 emitDivRem(IUREM, a, b, state);
@@ -766,6 +800,28 @@
         }
     }
 
+    public Variable emitRol(Value a, Value b) {
+        switch (a.getKind().getStackKind()) {
+            case Int:
+                return emitShift(IROL, a, b);
+            case Long:
+                return emitShift(LROL, a, b);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    public Variable emitRor(Value a, Value b) {
+        switch (a.getKind().getStackKind()) {
+            case Int:
+                return emitShift(IROR, a, b);
+            case Long:
+                return emitShift(LROR, a, b);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
     private AllocatableValue emitConvert2RegOp(PlatformKind kind, AMD64Arithmetic op, AllocatableValue input) {
         Variable result = newVariable(kind);
         append(new Unary2RegOp(op, result, input));
@@ -1021,7 +1077,7 @@
     }
 
     @Override
-    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
         // a temp is needed for loading object constants
         boolean needsTemp = key.getKind() == Kind.Object;
         append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL));
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,496 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.compiler.amd64;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*;
-import static com.oracle.graal.nodes.ConstantNode.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public class AMD64MemoryPeephole implements MemoryArithmeticLIRLowerer {
-    protected final AMD64NodeLIRBuilder gen;
-    protected List<ValueNode> deferredNodes;
-
-    protected AMD64MemoryPeephole(AMD64NodeLIRBuilder gen) {
-        this.gen = gen;
-    }
-
-    public Value setResult(ValueNode x, Value operand) {
-        return gen.setResult(x, operand);
-    }
-
-    @Override
-    public boolean memoryPeephole(Access access, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred) {
-        this.deferredNodes = deferred;
-        boolean result = operation.generate(this, access);
-        if (result) {
-            Debug.log("merge %s %s with %1s %s %s", access, access.asNode().stamp(), operation, result, access.asNode().graph().method());
-        } else {
-            Debug.log("can't merge %s %s with %1s", access, access.asNode().stamp(), operation);
-        }
-        this.deferredNodes = null;
-        return result;
-    }
-
-    protected LIRFrameState getState(Access access) {
-        if (access instanceof DeoptimizingNode) {
-            return gen.getLIRGenerator().state((DeoptimizingNode) access);
-        }
-        return null;
-    }
-
-    protected Kind getMemoryKind(Access access) {
-        return (Kind) gen.getLIRGenerator().getPlatformKind(access.asNode().stamp());
-    }
-
-    protected AMD64AddressValue makeAddress(Access access) {
-        return (AMD64AddressValue) access.accessLocation().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(access.object()));
-    }
-
-    protected Value emitBinaryMemory(AMD64Arithmetic op, boolean commutative, ValueNode x, ValueNode y, Access access) {
-        ValueNode other = x;
-        if (uncast(other) == access) {
-            if (commutative) {
-                other = y;
-            } else {
-                return null;
-            }
-        }
-        ensureEvaluated(other);
-        return gen.getLIRGenerator().emitBinaryMemory(op, getMemoryKind(access), gen.getLIRGeneratorTool().asAllocatable(gen.operand(other)), makeAddress(access), getState(access));
-    }
-
-    /**
-     * Constants with multiple users need to be evaluated in the right location so that later users
-     * can pick up the operand. Make sure that happens when it needs to.
-     */
-    protected void ensureEvaluated(ValueNode node) {
-        evaluateDeferred(node);
-        evaluateDeferred();
-    }
-
-    protected void evaluateDeferred(ValueNode node) {
-        // Ensure the other input value has a generated value.
-        if (ConstantNodeRecordsUsages) {
-            if (!gen.hasOperand(node)) {
-                assert node instanceof ConstantNode : node;
-                ((ConstantNode) node).generate(gen);
-            }
-        }
-    }
-
-    protected void evaluateDeferred() {
-        if (deferredNodes != null) {
-            for (ValueNode node : deferredNodes) {
-                evaluateDeferred(node);
-            }
-        }
-    }
-
-    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) {
-        AMD64AddressValue address = makeAddress(access);
-        LIRFrameState state = getState(access);
-        evaluateDeferred();
-        return gen.getLIRGenerator().emitConvert2MemoryOp(kind, op, address, state);
-    }
-
-    @Override
-    public Value emitAddMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IADD, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LADD, true, x, y, access);
-            case Float:
-                return emitBinaryMemory(FADD, true, x, y, access);
-            case Double:
-                return emitBinaryMemory(DADD, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitSubMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(ISUB, false, x, y, access);
-            case Long:
-                return emitBinaryMemory(LSUB, false, x, y, access);
-            case Float:
-                return emitBinaryMemory(FSUB, false, x, y, access);
-            case Double:
-                return emitBinaryMemory(DSUB, false, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitMulMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IMUL, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LMUL, true, x, y, access);
-            case Float:
-                return emitBinaryMemory(FMUL, true, x, y, access);
-            case Double:
-                return emitBinaryMemory(DMUL, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitDivMemory(ValueNode x, ValueNode y, Access access) {
-        return null;
-    }
-
-    @Override
-    public Value emitRemMemory(ValueNode x, ValueNode y, Access access) {
-        return null;
-    }
-
-    @Override
-    public Value emitAndMemory(ValueNode x, ValueNode y, Access access) {
-        Kind kind = getMemoryKind(access);
-        switch (kind) {
-            case Int:
-                return emitBinaryMemory(IAND, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LAND, true, x, y, access);
-            case Short: {
-                ValueNode other = selectOtherInput(x, y, access);
-                Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null;
-                if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) {
-                    // Convert to unsigned load
-                    ensureEvaluated(other);
-                    return emitZeroExtendMemory(16, 32, access);
-                }
-                return null;
-            }
-            case Byte: {
-                if (OptFoldMemory.getValue()) {
-                    return null;
-                }
-                ValueNode other = selectOtherInput(x, y, access);
-                Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null;
-                if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) {
-                    // Convert to unsigned load
-                    ensureEvaluated(other);
-                    return emitConvert2MemoryOp(Kind.Int, MOV_B2UI, access);
-                }
-                return null;
-            }
-
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitOrMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IOR, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LOR, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitXorMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IXOR, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LXOR, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitReinterpretMemory(Stamp stamp, Access access) {
-        PlatformKind to = gen.getLIRGenerator().getPlatformKind(stamp);
-        Kind from = getMemoryKind(access);
-        assert to != from : "should have been eliminated";
-
-        /*
-         * Conversions between integer to floating point types require moves between CPU and FPU
-         * registers.
-         */
-        switch ((Kind) to) {
-            case Int:
-                switch (from) {
-                    case Float:
-                        return emitConvert2MemoryOp(to, MOV_F2I, access);
-                }
-                break;
-            case Long:
-                switch (from) {
-                    case Double:
-                        return emitConvert2MemoryOp(to, MOV_D2L, access);
-                }
-                break;
-            case Float:
-                switch (from) {
-                    case Int:
-                        return emitConvert2MemoryOp(to, MOV_I2F, access);
-                }
-                break;
-            case Double:
-                switch (from) {
-                    case Long:
-                        return emitConvert2MemoryOp(to, MOV_L2D, access);
-                }
-                break;
-        }
-        throw GraalInternalError.shouldNotReachHere();
-    }
-
-    @Override
-    public Value emitFloatConvertMemory(FloatConvert op, Access access) {
-        switch (op) {
-            case D2F:
-                return emitConvert2MemoryOp(Kind.Float, D2F, access);
-            case D2I:
-                return emitConvert2MemoryOp(Kind.Int, D2I, access);
-            case D2L:
-                return emitConvert2MemoryOp(Kind.Long, D2L, access);
-            case F2D:
-                return emitConvert2MemoryOp(Kind.Double, F2D, access);
-            case F2I:
-                return emitConvert2MemoryOp(Kind.Int, F2I, access);
-            case F2L:
-                return emitConvert2MemoryOp(Kind.Long, F2L, access);
-            case I2D:
-                return emitConvert2MemoryOp(Kind.Double, I2D, access);
-            case I2F:
-                return emitConvert2MemoryOp(Kind.Float, I2F, access);
-            case L2D:
-                return emitConvert2MemoryOp(Kind.Double, L2D, access);
-            case L2F:
-                return emitConvert2MemoryOp(Kind.Float, L2F, access);
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    @Override
-    public Value emitSignExtendMemory(Access access, int fromBits, int toBits) {
-        assert fromBits <= toBits && toBits <= 64;
-        if (fromBits == toBits) {
-            return null;
-        } else if (toBits > 32) {
-            // sign extend to 64 bits
-            switch (fromBits) {
-                case 8:
-                    return emitConvert2MemoryOp(Kind.Long, B2L, access);
-                case 16:
-                    return emitConvert2MemoryOp(Kind.Long, S2L, access);
-                case 32:
-                    return emitConvert2MemoryOp(Kind.Long, I2L, access);
-                default:
-                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
-            }
-        } else {
-
-            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
-            switch (fromBits) {
-                case 8:
-                    return emitConvert2MemoryOp(Kind.Int, B2I, access);
-                case 16:
-                    return emitConvert2MemoryOp(Kind.Int, S2I, access);
-                case 32:
-                    return null;
-                default:
-                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
-            }
-        }
-    }
-
-    @Override
-    public Value emitNarrowMemory(int resultBits, Access access) {
-        // TODO
-        return null;
-    }
-
-    @Override
-    public Value emitZeroExtendMemory(int fromBits, int toBits, Access access) {
-        assert fromBits != toBits;
-        Kind memoryKind = getMemoryKind(access);
-        if (memoryKind.getBitCount() != fromBits && !memoryKind.isUnsigned()) {
-            // The memory being read from is signed and smaller than the result size so
-            // this is a sign extension to inputBits followed by a zero extension to resultBits
-            // which can't be expressed in a memory operation.
-            return null;
-        }
-        if (memoryKind == Kind.Short) {
-            memoryKind = Kind.Char;
-        }
-        evaluateDeferred();
-        return gen.getLIRGenerator().emitZeroExtendMemory(memoryKind, toBits, makeAddress(access), getState(access));
-    }
-
-    public boolean emitIfMemory(IfNode x, Access access) {
-        return emitBranchMemory(x.condition(), access, gen.getLIRBlock(x.trueSuccessor()), gen.getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor()));
-    }
-
-    private boolean emitBranchMemory(LogicNode node, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        if (node instanceof IsNullNode) {
-            // can't do anything interesting.
-            return false;
-        } else if (node instanceof CompareNode) {
-            CompareNode compare = (CompareNode) node;
-            return emitCompareBranchMemory(compare, access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-        } else if (node instanceof LogicConstantNode) {
-            return false;
-        } else if (node instanceof IntegerTestNode) {
-            return emitIntegerTestBranchMemory((IntegerTestNode) node, access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-        } else {
-            throw GraalInternalError.unimplemented(node.toString());
-        }
-    }
-
-    public boolean emitCompareBranchMemory(CompareNode compare, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        return emitCompareBranchMemory(compare.x(), compare.y(), access, compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability);
-    }
-
-    public boolean emitIntegerTestBranchMemory(IntegerTestNode test, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        return emitIntegerTestBranchMemory(test.x(), test.y(), access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-    }
-
-    private boolean emitIntegerTestBranchMemory(ValueNode left, ValueNode right, Access access, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
-        ValueNode other = selectOtherInput(left, right, access);
-        Kind kind = getMemoryKind(access);
-        if (other.isConstant()) {
-            if (kind != kind.getStackKind()) {
-                return false;
-            }
-            Constant constant = other.asConstant();
-            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
-                // Only imm32 as long
-                return false;
-            }
-            ensureEvaluated(other);
-            gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access)));
-        } else {
-            evaluateDeferred();
-            gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), gen.operand(other), getState(access)));
-        }
-
-        gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
-        return true;
-    }
-
-    /**
-     * @return the input which is not equal to access, accounting for possible UnsafeCastNodes.
-     */
-    protected ValueNode selectOtherInput(ValueNode left, ValueNode right, Access access) {
-        assert uncast(left) == access || uncast(right) == access;
-        return uncast(left) == access ? right : left;
-    }
-
-    protected ValueNode uncast(ValueNode value) {
-        if (value instanceof UnsafeCastNode) {
-            UnsafeCastNode cast = (UnsafeCastNode) value;
-            return cast.getOriginalNode();
-        }
-        return value;
-    }
-
-    protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
-                    double trueLabelProbability) {
-        ValueNode other = selectOtherInput(left, right, access);
-        Kind kind = getMemoryKind(access);
-        boolean mirrored = false;
-
-        if (other.isConstant()) {
-            Constant constant = other.asConstant();
-            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
-                // Only imm32 as long
-                return false;
-            }
-            if (kind.isNumericFloat()) {
-                Debug.log("Skipping constant compares for float kinds");
-                return false;
-            }
-            if (kind == Kind.Object) {
-                if (!constant.isNull()) {
-                    Debug.log("Skipping constant compares for Object kinds");
-                    return false;
-                }
-            }
-            ensureEvaluated(other);
-            gen.getLIRGenerator().emitCompareMemoryConOp(kind, makeAddress(access), constant, getState(access));
-            mirrored = uncast(right) == access;
-        } else {
-            if (kind == Kind.Object) {
-                // Can't compare against objects since they require encode/decode
-                Debug.log("Skipping compares for Object kinds");
-                return false;
-            }
-
-            evaluateDeferred();
-            gen.getLIRGenerator().emitCompareRegMemoryOp(kind, gen.operand(other), makeAddress(access), getState(access));
-            mirrored = uncast(left) == access;
-        }
-
-        Condition finalCondition = mirrored ? cond.mirror() : cond;
-        switch (kind.getStackKind()) {
-            case Long:
-            case Int:
-            case Object:
-                gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
-                return true;
-            case Float:
-            case Double:
-                gen.append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
-                return true;
-            default:
-                throw GraalInternalError.shouldNotReachHere("" + kind.getStackKind());
-        }
-    }
-}
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,33 +23,31 @@
 
 package com.oracle.graal.compiler.amd64;
 
+import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*;
+
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.extended.*;
 
 public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder {
 
-    public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) {
+    public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         super(graph, gen);
     }
 
-    protected MemoryArithmeticLIRLowerer memoryPeephole;
-
-    @Override
-    public MemoryArithmeticLIRLowerer getMemoryLowerer() {
-        if (memoryPeephole == null) {
-            // Use the generic one
-            memoryPeephole = new AMD64MemoryPeephole(this);
-        }
-        return memoryPeephole;
-    }
-
     @Override
     protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
         AllocatableValue targetAddress = AMD64.rax.asValue();
@@ -60,7 +58,7 @@
     @Override
     public void emitNullCheck(ValueNode v, DeoptimizingNode deopt) {
         assert v.getKind() == Kind.Object : v + " - " + v.stamp() + " @ " + deopt;
-        append(new AMD64Move.NullCheckOp(gen.load(operand(v)), gen.state(deopt)));
+        append(new AMD64Move.NullCheckOp(gen.load(operand(v)), state(deopt)));
     }
 
     @Override
@@ -73,7 +71,7 @@
                 if (((fixedWithNextNode instanceof IntegerDivNode) || (fixedWithNextNode instanceof IntegerRemNode)) && fixedWithNextNode.getClass() != divRem.getClass()) {
                     FixedBinaryNode otherDivRem = (FixedBinaryNode) fixedWithNextNode;
                     if (otherDivRem.x() == divRem.x() && otherDivRem.y() == divRem.y() && !hasOperand(otherDivRem)) {
-                        Value[] results = ((AMD64LIRGenerator) gen).emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()), (DeoptimizingNode) valueNode);
+                        Value[] results = ((AMD64LIRGenerator) gen).emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()), state((DeoptimizingNode) valueNode));
                         if (divRem instanceof IntegerDivNode) {
                             setResult(divRem, results[0]);
                             setResult(otherDivRem, results[1]);
@@ -90,6 +88,525 @@
         return false;
     }
 
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    protected Kind getMemoryKind(Access access) {
+        return (Kind) gen.getPlatformKind(access.asNode().stamp());
+    }
+
+    protected AMD64AddressValue makeAddress(Access access) {
+        return (AMD64AddressValue) access.accessLocation().generateAddress(this, gen, operand(access.object()));
+    }
+
+    protected ValueNode uncast(ValueNode value) {
+        if (value instanceof UnsafeCastNode) {
+            UnsafeCastNode cast = (UnsafeCastNode) value;
+            return cast.getOriginalNode();
+        }
+        return value;
+    }
+
+    protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, Access access) {
+        Condition cond = compare.condition();
+        Kind kind = getMemoryKind(access);
+
+        if (value.isConstant()) {
+            Constant constant = value.asConstant();
+            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return null;
+            }
+            if (kind.isNumericFloat()) {
+                Debug.log("Skipping constant compares for float kinds");
+                return null;
+            }
+            if (kind == Kind.Object) {
+                if (!constant.isNull()) {
+                    Debug.log("Skipping constant compares for Object kinds");
+                    return null;
+                }
+            }
+        } else {
+            if (kind == Kind.Object) {
+                // Can't compare against objects since they require encode/decode
+                Debug.log("Skipping compares for Object kinds");
+                return null;
+            }
+        }
+
+        PlatformKind cmpKind = gen.getPlatformKind(compare.x().stamp());
+        if (cmpKind instanceof Kind) {
+            // emitCompareBranchMemory expects the memory on the right, so mirror the condition if
+            // that's not true. It might be mirrored again the actual compare is emitted but that's
+            // ok.
+            Condition finalCondition = uncast(compare.x()) == access ? cond.mirror() : cond;
+            return new ComplexMatchResult() {
+                public Value evaluate(NodeLIRBuilder builder) {
+                    LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+                    LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+                    boolean unorderedIsTrue = compare.unorderedIsTrue();
+                    double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+                    Value other;
+                    if (value.isConstant()) {
+                        other = value.asConstant();
+                    } else {
+                        other = operand(value);
+                    }
+
+                    getLIRGeneratorTool().emitCompareBranchMemory((Kind) cmpKind, other, makeAddress(access), getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel,
+                                    trueLabelProbability);
+                    return null;
+                }
+            };
+        }
+        return null;
+
+    }
+
+    private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, Access access) {
+        LabelRef trueLabel = getLIRBlock(x.trueSuccessor());
+        LabelRef falseLabel = getLIRBlock(x.falseSuccessor());
+        double trueLabelProbability = x.probability(x.trueSuccessor());
+        Kind kind = getMemoryKind(access);
+        if (value.isConstant()) {
+            if (kind != kind.getStackKind()) {
+                return null;
+            }
+            Constant constant = value.asConstant();
+            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return null;
+            }
+            return new ComplexMatchResult() {
+                public Value evaluate(NodeLIRBuilder builder) {
+                    gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access)));
+                    gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                    return null;
+                }
+            };
+        } else {
+            return new ComplexMatchResult() {
+                public Value evaluate(NodeLIRBuilder builder) {
+                    gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access)));
+                    gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                    return null;
+                }
+            };
+        }
+    }
+
+    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) {
+        AMD64AddressValue address = makeAddress(access);
+        LIRFrameState state = getState(access);
+        return getLIRGeneratorTool().emitConvert2MemoryOp(kind, op, address, state);
+    }
+
+    private Value emitFloatConvertMemory(FloatConvertNode op, Access access) {
+        switch (op.getOp()) {
+            case D2F:
+                return emitConvert2MemoryOp(Kind.Float, D2F, access);
+            case D2I:
+                return emitConvert2MemoryOp(Kind.Int, D2I, access);
+            case D2L:
+                return emitConvert2MemoryOp(Kind.Long, D2L, access);
+            case F2D:
+                return emitConvert2MemoryOp(Kind.Double, F2D, access);
+            case F2I:
+                return emitConvert2MemoryOp(Kind.Int, F2I, access);
+            case F2L:
+                return emitConvert2MemoryOp(Kind.Long, F2L, access);
+            case I2D:
+                return emitConvert2MemoryOp(Kind.Double, I2D, access);
+            case I2F:
+                return emitConvert2MemoryOp(Kind.Float, I2F, access);
+            case L2D:
+                return emitConvert2MemoryOp(Kind.Double, L2D, access);
+            case L2F:
+                return emitConvert2MemoryOp(Kind.Float, L2F, access);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        Kind kind = null;
+        AMD64Arithmetic op = null;
+        if (fromBits == toBits) {
+            return null;
+        } else if (toBits > 32) {
+            kind = Kind.Long;
+            // sign extend to 64 bits
+            switch (fromBits) {
+                case 8:
+                    op = B2L;
+                    break;
+                case 16:
+                    op = S2L;
+                    break;
+                case 32:
+                    op = I2L;
+                    break;
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        } else {
+            kind = Kind.Int;
+            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
+            switch (fromBits) {
+                case 8:
+                    op = B2I;
+                    break;
+                case 16:
+                    op = S2I;
+                    break;
+                case 32:
+                    return null;
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        }
+        if (kind != null && op != null) {
+            Kind localKind = kind;
+            AMD64Arithmetic localOp = op;
+            return new ComplexMatchResult() {
+                public Value evaluate(NodeLIRBuilder builder) {
+                    return emitConvert2MemoryOp(localKind, localOp, access);
+                }
+            };
+        }
+        return null;
+    }
+
+    private Value emitReinterpretMemory(PlatformKind to, Access access) {
+        Kind from = getMemoryKind(access);
+        assert to != from : "should have been eliminated";
+
+        /*
+         * Conversions between integer to floating point types require moves between CPU and FPU
+         * registers.
+         */
+        switch ((Kind) to) {
+            case Int:
+                switch (from) {
+                    case Float:
+                        return emitConvert2MemoryOp(to, MOV_F2I, access);
+                }
+                break;
+            case Long:
+                switch (from) {
+                    case Double:
+                        return emitConvert2MemoryOp(to, MOV_D2L, access);
+                }
+                break;
+            case Float:
+                switch (from) {
+                    case Int:
+                        return emitConvert2MemoryOp(to, MOV_I2F, access);
+                }
+                break;
+            case Double:
+                switch (from) {
+                    case Long:
+                        return emitConvert2MemoryOp(to, MOV_L2D, access);
+                }
+                break;
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    static Object lock = new Object();
+
+    private AMD64Arithmetic getOp(ValueNode operation, Access access) {
+        Kind memoryKind = getMemoryKind(access);
+        if (operation.getClass() == IntegerAddNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IADD;
+                case Long:
+                    return LADD;
+            }
+        } else if (operation.getClass() == FloatAddNode.class) {
+            switch (memoryKind) {
+                case Float:
+                    return FADD;
+                case Double:
+                    return DADD;
+            }
+        } else if (operation.getClass() == AndNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IAND;
+                case Long:
+                    return LAND;
+            }
+        } else if (operation.getClass() == OrNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IOR;
+                case Long:
+                    return LOR;
+            }
+        } else if (operation.getClass() == XorNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IXOR;
+                case Long:
+                    return LXOR;
+            }
+        } else if (operation.getClass() == IntegerSubNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return ISUB;
+                case Long:
+                    return LSUB;
+            }
+        } else if (operation.getClass() == FloatSubNode.class) {
+            switch (memoryKind) {
+                case Float:
+                    return FSUB;
+                case Double:
+                    return DSUB;
+            }
+        } else if (operation.getClass() == IntegerMulNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IMUL;
+                case Long:
+                    return LMUL;
+            }
+        } else if (operation.getClass() == FloatMulNode.class) {
+            switch (memoryKind) {
+                case Float:
+                    return FMUL;
+                case Double:
+                    return DMUL;
+            }
+        }
+        return null;
+    }
+
+    @MatchRule("(If (IntegerTest=compare Read=access value))")
+    @MatchRule("(If (IntegerTest=compare FloatingRead=access value))")
+    public static class IfIntegerTest extends AMD64MatchGenerator {
+        IfNode root;
+        Access access;
+        ValueNode value;
+
+        @Override
+        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
+            return gen.emitIntegerTestBranchMemory(root, value, access);
+        }
+    }
+
+    @MatchRule("(If (IntegerEquals=compare value Read=access))")
+    @MatchRule("(If (IntegerLessThan=compare value Read=access))")
+    @MatchRule("(If (IntegerBelowThan=compare value Read=access))")
+    @MatchRule("(If (IntegerEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerLessThan=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerBelowThan=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatEquals=compare value Read=access))")
+    @MatchRule("(If (FloatEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatLessThan=compare value Read=access))")
+    @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))")
+    public static class IfCompareMemory extends AMD64MatchGenerator {
+        IfNode root;
+        Access access;
+        ValueNode value;
+        CompareNode compare;
+
+        @Override
+        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
+            return gen.emitCompareBranchMemory(root, compare, value, access);
+        }
+    }
+
+    @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))")
+    public static class RotateLeftConstant extends AMD64MatchGenerator {
+        LeftShiftNode lshift;
+        UnsignedRightShiftNode rshift;
+
+        @Override
+        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
+            if ((lshift.getShiftAmountMask() & (lshift.y().asConstant().asInt() + rshift.y().asConstant().asInt())) == 0) {
+                return builder -> gen.getLIRGeneratorTool().emitRol(gen.operand(lshift.x()), gen.operand(lshift.y()));
+            }
+            return null;
+        }
+
+    }
+
+    @MatchRule("(Or (LeftShift=lshift value (IntegerSub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))")
+    public static class RotateRightVariable extends AMD64MatchGenerator {
+        ValueNode value;
+        ValueNode shiftAmount;
+        ConstantNode delta;
+
+        @Override
+        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
+            if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
+                return builder -> gen.getLIRGeneratorTool().emitRor(gen.operand(value), gen.operand(shiftAmount));
+            }
+            return null;
+        }
+
+    }
+
+    @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (IntegerSub Constant=delta shiftAmount)))")
+    public static class RotateLeftVariable extends AMD64MatchGenerator {
+        ValueNode value;
+        ValueNode shiftAmount;
+        ConstantNode delta;
+
+        @Override
+        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
+            if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
+                return builder -> gen.getLIRGeneratorTool().emitRol(gen.operand(value), gen.operand(shiftAmount));
+            }
+            return null;
+        }
+    }
+
+    @MatchRule("(IntegerAdd value Read=access)")
+    @MatchRule("(IntegerSub value Read=access)")
+    @MatchRule("(IntegerMul value Read=access)")
+    @MatchRule("(FloatAdd value Read=access)")
+    @MatchRule("(FloatSub value Read=access)")
+    @MatchRule("(FloatMul value Read=access)")
+    @MatchRule("(Or value Read=access)")
+    @MatchRule("(Xor value Read=access)")
+    @MatchRule("(And value Read=access)")
+    @MatchRule("(IntegerAdd value FloatingRead=access)")
+    @MatchRule("(IntegerSub value FloatingRead=access)")
+    @MatchRule("(IntegerMul value FloatingRead=access)")
+    @MatchRule("(FloatAdd value FloatingRead=access)")
+    @MatchRule("(FloatSub value FloatingRead=access)")
+    @MatchRule("(FloatMul value FloatingRead=access)")
+    @MatchRule("(Or value FloatingRead=access)")
+    @MatchRule("(Xor value FloatingRead=access)")
+    @MatchRule("(And value FloatingRead=access)")
+    public static class BinaryRead extends AMD64MatchGenerator {
+        BinaryNode root;
+        Access access;
+        ValueNode value;
+
+        @Override
+        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
+            AMD64Arithmetic op = gen.getOp(root, access);
+            if (op != null) {
+                return builder -> gen.getLIRGeneratorTool().emitBinaryMemory(op, gen.getMemoryKind(access), gen.getLIRGeneratorTool().asAllocatable(gen.operand(value)), gen.makeAddress(access),
+                                gen.getState(access));
+            }
+            return null;
+        }
+    }
+
+    @MatchRule("(Write Narrow=narrow value)")
+    public static class WriteNarrow extends AMD64MatchGenerator {
+        WriteNode root;
+        NarrowNode narrow;
+
+        @Override
+        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
+            return new ComplexMatchResult() {
+                @Override
+                public Value evaluate(NodeLIRBuilder builder) {
+                    PlatformKind writeKind = gen.getLIRGeneratorTool().getPlatformKind(root.value().stamp());
+                    Value address = root.location().generateAddress(builder, gen.getLIRGeneratorTool(), gen.operand(root.object()));
+                    Value v = gen.operand(narrow.getInput());
+                    gen.getLIRGeneratorTool().emitStore(writeKind, address, v, gen.state(root));
+                    return null;
+                }
+            };
+        }
+    }
+
+    @MatchRule("(SignExtend Read=access)")
+    @MatchRule("(SignExtend FloatingRead=access)")
+    public static class SignExtend extends AMD64MatchGenerator {
+        Access access;
+        SignExtendNode root;
+
+        @Override
+        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
+            return gen.emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
+        }
+    }
+
+    static abstract class AMD64MatchGenerator implements MatchGenerator {
+        public AMD64MatchGenerator() {
+        }
+
+        public ComplexMatchResult match(NodeLIRBuilder gen) {
+            return match((AMD64NodeLIRBuilder) gen);
+        }
+
+        abstract public ComplexMatchResult match(AMD64NodeLIRBuilder gen);
+    }
+
+    @MatchRule("(ZeroExtend Read=access)")
+    @MatchRule("(ZeroExtend FloatingRead=access)")
+    public static class ZeroExtend extends AMD64MatchGenerator {
+        Access access;
+        ZeroExtendNode root;
+
+        @Override
+        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
+            Kind memoryKind = gen.getMemoryKind(access);
+            if (memoryKind.getBitCount() != root.getInputBits() && !memoryKind.isUnsigned()) {
+                /*
+                 * The memory being read from is signed and smaller than the result size so this is
+                 * a sign extension to inputBits followed by a zero extension to resultBits which
+                 * can't be expressed in a memory operation.
+                 */
+                return null;
+            }
+            return new ComplexMatchResult() {
+                public Value evaluate(NodeLIRBuilder unused) {
+                    return gen.getLIRGeneratorTool().emitZeroExtendMemory(memoryKind == Kind.Short ? Kind.Char : memoryKind, root.getResultBits(), gen.makeAddress(access), gen.getState(access));
+                }
+            };
+        }
+    }
+
+    @MatchRule("(FloatConvert Read=access)")
+    @MatchRule("(FloatConvert FloatingRead=access)")
+    public static class FloatConvert extends AMD64MatchGenerator {
+        Access access;
+        FloatConvertNode root;
+
+        @Override
+        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
+            return new ComplexMatchResult() {
+                public Value evaluate(NodeLIRBuilder builder) {
+                    return gen.emitFloatConvertMemory(root, access);
+                }
+            };
+        }
+    }
+
+    @MatchRule("(Reinterpret Read=access)")
+    @MatchRule("(Reinterpret FloatingRead=access)")
+    public static class Reinterpret extends AMD64MatchGenerator {
+        Access access;
+        ReinterpretNode root;
+
+        @Override
+        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
+            return new ComplexMatchResult() {
+                public Value evaluate(NodeLIRBuilder builder) {
+                    PlatformKind kind = gen.getLIRGeneratorTool().getPlatformKind(root.stamp());
+                    return gen.emitReinterpretMemory(kind, access);
+                }
+            };
+        }
+    }
+
     @Override
     public void visitBreakpointNode(BreakpointNode node) {
         JavaType[] sig = new JavaType[node.arguments().size()];
@@ -103,11 +620,11 @@
 
     @Override
     public void visitInfopointNode(InfopointNode i) {
-        append(new InfopointOp(gen.stateFor(i.getState()), i.reason));
+        append(new InfopointOp(stateFor(i.getState()), i.reason));
     }
 
     @Override
-    public AMD64LIRGenerator getLIRGenerator() {
+    public AMD64LIRGenerator getLIRGeneratorTool() {
         return (AMD64LIRGenerator) gen;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,157 @@
+/*
+ * 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.compiler.common;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+public abstract class FieldIntrospection extends UnsafeAccess {
+
+    /**
+     * Interface used by {@link #rescanAllFieldOffsets(CalcOffset)} to determine the offset (in
+     * bytes) of a field.
+     */
+    public interface CalcOffset {
+
+        long getOffset(Field field);
+    }
+
+    public static class DefaultCalcOffset implements CalcOffset {
+
+        @Override
+        public long getOffset(Field field) {
+            return unsafe.objectFieldOffset(field);
+        }
+    }
+
+    protected static final ConcurrentHashMap<Class<?>, FieldIntrospection> allClasses = new ConcurrentHashMap<>();
+
+    private final Class<?> clazz;
+    protected long[] dataOffsets;
+    protected Map<Long, String> fieldNames;
+    protected Map<Long, Class<?>> fieldTypes;
+
+    public FieldIntrospection(Class<?> clazz) {
+        this.clazz = clazz;
+    }
+
+    public Class<?> getClazz() {
+        return clazz;
+    }
+
+    public static void rescanAllFieldOffsets(CalcOffset calc) {
+        for (FieldIntrospection nodeClass : allClasses.values()) {
+            nodeClass.rescanFieldOffsets(calc);
+        }
+    }
+
+    protected abstract void rescanFieldOffsets(CalcOffset calc);
+
+    public abstract static class BaseFieldScanner {
+
+        private final CalcOffset calc;
+
+        /** The offsets of fields that are not specially handled by subclasses. */
+        public final ArrayList<Long> dataOffsets = new ArrayList<>();
+
+        public final Map<Long, String> fieldNames = new HashMap<>();
+        public final Map<Long, Class<?>> fieldTypes = new HashMap<>();
+
+        protected BaseFieldScanner(CalcOffset calc) {
+            this.calc = calc;
+        }
+
+        public void scan(Class<?> clazz) {
+            Class<?> currentClazz = clazz;
+            do {
+                for (Field field : currentClazz.getDeclaredFields()) {
+                    if (Modifier.isStatic(field.getModifiers())) {
+                        continue;
+                    }
+                    Class<?> type = field.getType();
+                    long offset = calc.getOffset(field);
+
+                    // scanField() may overwrite the name with a customized name.
+                    fieldNames.put(offset, field.getName());
+                    fieldTypes.put(offset, type);
+
+                    scanField(field, type, offset);
+                }
+                currentClazz = currentClazz.getSuperclass();
+            } while (currentClazz.getSuperclass() != Object.class);
+        }
+
+        protected abstract void scanField(Field field, Class<?> type, long offset);
+    }
+
+    protected static void copyInto(long[] dest, long[] src) {
+        assert dest.length == src.length;
+        for (int i = 0; i < dest.length; i++) {
+            dest[i] = src[i];
+        }
+    }
+
+    protected static <T> void copyInto(T[] dest, T[] src) {
+        assert dest.length == src.length;
+        for (int i = 0; i < dest.length; i++) {
+            dest[i] = src[i];
+        }
+    }
+
+    protected static <T> void copyInto(T[] dest, List<T> src) {
+        assert dest.length == src.size();
+        for (int i = 0; i < dest.length; i++) {
+            dest[i] = src.get(i);
+        }
+    }
+
+    protected static <T> T[] arrayUsingSortedOffsets(Map<Long, T> map, long[] sortedOffsets, T[] result) {
+        for (int i = 0; i < sortedOffsets.length; i++) {
+            result[i] = map.get(sortedOffsets[i]);
+        }
+        return result;
+    }
+
+    protected static long[] sortedLongCopy(ArrayList<Long> list1) {
+        Collections.sort(list1);
+        long[] result = new long[list1.size()];
+        for (int i = 0; i < list1.size(); i++) {
+            result[i] = list1.get(i);
+        }
+        return result;
+    }
+
+    protected static long[] sortedLongCopy(ArrayList<Long> list1, ArrayList<Long> list2) {
+        Collections.sort(list1);
+        Collections.sort(list2);
+        long[] result = new long[list1.size() + list2.size()];
+        for (int i = 0; i < list1.size(); i++) {
+            result[i] = list1.get(i);
+        }
+        for (int i = 0; i < list2.size(); i++) {
+            result[list1.size() + i] = list2.get(i);
+        }
+        return result;
+    }
+}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Tue Apr 29 12:43:27 2014 -0700
@@ -187,6 +187,8 @@
 
     // Code generator settings
     @Option(help = "")
+    public static final OptionValue<Boolean> FlowSensitiveReduction = new OptionValue<>(false);
+    @Option(help = "")
     public static final OptionValue<Boolean> ConditionalElimination = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Boolean> UseProfilingInformation = new OptionValue<>(true);
@@ -272,7 +274,9 @@
     @Option(help = "")
     public static final OptionValue<Boolean> OptPushThroughPi = new OptionValue<>(true);
     @Option(help = "Allow backend to emit arithmetic and compares directly against memory.")
-    public static final OptionValue<Boolean> OptFoldMemory = new OptionValue<>(true);
+    public static final OptionValue<Boolean> OptFoldMemory = new OptionValue<>(false);
+    @Option(help = "Allow backend to match complex expressions.")
+    public static final OptionValue<Boolean> MatchExpressions = new OptionValue<>(true);
 
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/UnsafeAccess.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,102 @@
+/*
+ * 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.compiler.common;
+
+import java.lang.reflect.*;
+
+import sun.misc.*;
+
+public class UnsafeAccess {
+
+    /**
+     * An instance of {@link Unsafe} for use within Graal.
+     */
+    public static final Unsafe unsafe = getUnsafe();
+
+    private static Unsafe getUnsafe() {
+        try {
+            // this will fail if Graal is not part of the boot class path
+            return Unsafe.getUnsafe();
+        } catch (SecurityException e) {
+            // nothing to do
+        }
+        try {
+            Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
+            theUnsafeInstance.setAccessible(true);
+            return (Unsafe) theUnsafeInstance.get(Unsafe.class);
+        } catch (Exception e) {
+            // currently we rely on being able to use Unsafe...
+            throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
+        }
+    }
+
+    /**
+     * Copies the contents of a {@link String} to a native memory buffer as a {@code '\0'}
+     * terminated C string. The native memory buffer is allocated via
+     * {@link Unsafe#allocateMemory(long)}. The caller is responsible for releasing the buffer when
+     * it is no longer needed via {@link Unsafe#freeMemory(long)}.
+     * 
+     * @return the native memory pointer of the C string created from {@code s}
+     */
+    public static long createCString(String s) {
+        return writeCString(s, unsafe.allocateMemory(s.length() + 1));
+    }
+
+    /**
+     * Reads a {@code '\0'} terminated C string from native memory and converts it to a
+     * {@link String}.
+     * 
+     * @return a Java string
+     */
+    public static String readCString(long address) {
+        if (address == 0) {
+            return null;
+        }
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0;; i++) {
+            char c = (char) unsafe.getByte(address + i);
+            if (c == 0) {
+                break;
+            }
+            sb.append(c);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Writes the contents of a {@link String} to a native memory buffer as a {@code '\0'}
+     * terminated C string. The caller is responsible for ensuring the buffer is at least
+     * {@code s.length() + 1} bytes long. The caller is also responsible for releasing the buffer
+     * when it is no longer.
+     * 
+     * @return the value of {@code buf}
+     */
+    public static long writeCString(String s, long buf) {
+        int size = s.length();
+        for (int i = 0; i < size; i++) {
+            unsafe.putByte(buf + i, (byte) s.charAt(i));
+        }
+        unsafe.putByte(buf + size, (byte) '\0');
+        return buf;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/calc/FloatConvert.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.calc;
+
+import com.oracle.graal.compiler.common.*;
+
+public enum FloatConvert {
+    F2I,
+    D2I,
+    F2L,
+    D2L,
+    I2F,
+    L2F,
+    D2F,
+    I2D,
+    L2D,
+    F2D;
+
+    public FloatConvert reverse() {
+        switch (this) {
+            case D2F:
+                return F2D;
+            case D2I:
+                return I2D;
+            case D2L:
+                return L2D;
+            case F2D:
+                return D2F;
+            case F2I:
+                return I2F;
+            case F2L:
+                return L2F;
+            case I2D:
+                return D2I;
+            case I2F:
+                return F2I;
+            case L2D:
+                return D2L;
+            case L2F:
+                return F2L;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/CodeGenProviders.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.spi;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+
+/**
+ * A set of providers which are required for LIR and/or code generation. Some may not be present
+ * (i.e., null).
+ */
+public interface CodeGenProviders {
+
+    MetaAccessProvider getMetaAccess();
+
+    CodeCacheProvider getCodeCache();
+
+    ForeignCallsProvider getForeignCalls();
+
+    ConstantReflectionProvider getConstantReflection();
+
+}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/LIRProviders.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.common.spi;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-
-/**
- * A set of providers which are required for LIR and/or code generation. Some may not be present
- * (i.e., null).
- */
-public interface LIRProviders {
-
-    MetaAccessProvider getMetaAccess();
-
-    CodeCacheProvider getCodeCache();
-
-    ForeignCallsProvider getForeignCalls();
-
-    ConstantReflectionProvider getConstantReflection();
-
-}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/LIRTypeTool.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.common.spi;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * This interface can be used to access platform and VM specific kinds.
- */
-public interface LIRTypeTool {
-
-    PlatformKind getIntegerKind(int bits);
-
-    PlatformKind getFloatingKind(int bits);
-
-    PlatformKind getObjectKind();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/PlatformKindTool.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.spi;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * This interface can be used to access platform and VM specific kinds.
+ */
+public interface PlatformKindTool {
+
+    PlatformKind getIntegerKind(int bits);
+
+    PlatformKind getFloatingKind(int bits);
+
+    PlatformKind getObjectKind();
+}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -68,7 +68,7 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
         return tool.getFloatingKind(getBits());
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -40,7 +40,7 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
         throw GraalInternalError.shouldNotReachHere("illegal stamp should not reach backend");
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -29,12 +29,11 @@
 import com.oracle.graal.compiler.common.spi.*;
 
 /**
- * Describes the possible values of a {@link ValueNode} that produces an int or long result.
+ * Describes the possible values of a node that produces an int or long result.
  *
  * The description consists of (inclusive) lower and upper bounds and up (may be set) and down
  * (always set) bit-masks.
  */
-@SuppressWarnings("javadoc")
 public class IntegerStamp extends PrimitiveStamp {
 
     private final long lowerBound;
@@ -79,7 +78,7 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
         return tool.getIntegerKind(getBits());
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.common.type;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -63,7 +62,7 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
         return tool.getObjectKind();
     }
 
@@ -249,7 +248,7 @@
     }
 
     public static boolean isConcreteType(ResolvedJavaType type) {
-        return !(Modifier.isAbstract(type.getModifiers()) && !type.isArray());
+        return !(type.isAbstract() && !type.isArray());
     }
 
     private static ResolvedJavaType meetTypes(ResolvedJavaType a, ResolvedJavaType b) {
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,9 +23,8 @@
 package com.oracle.graal.compiler.common.type;
 
 /**
- * Describes the possible values of a {@link ValueNode} that produces a primitive value as result.
+ * Type describing primitive values.
  */
-@SuppressWarnings("javadoc")
 public abstract class PrimitiveStamp extends Stamp {
 
     private final int bits;
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,7 +26,7 @@
 import com.oracle.graal.compiler.common.spi.*;
 
 /**
- * A stamp is the basis for a type system over the nodes in a graph.
+ * A stamp is the basis for a type system.
  */
 public abstract class Stamp {
 
@@ -54,16 +54,15 @@
      * Gets a platform dependent {@link PlatformKind} that can be used to store a value of this
      * stamp.
      */
-    public abstract PlatformKind getPlatformKind(LIRTypeTool tool);
+    public abstract PlatformKind getPlatformKind(PlatformKindTool tool);
 
     /**
-     * Returns the union of this stamp and the given stamp. Typically used to create stamps for
-     * {@link ValuePhiNode}s.
+     * Returns the union of this stamp and the given stamp. Typically used to create stamps for phi
+     * nodes.
      *
      * @param other The stamp that will enlarge this stamp.
      * @return The union of this stamp and the given stamp.
      */
-    @SuppressWarnings("javadoc")
     public abstract Stamp meet(Stamp other);
 
     /**
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -45,7 +45,7 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
         throw GraalInternalError.shouldNotReachHere("void stamp has no value");
     }
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndAddTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndAddTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,13 +27,10 @@
 
 import org.junit.*;
 
-import sun.misc.*;
-
 import com.oracle.graal.compiler.hsail.test.infra.*;
 
 /**
- * Tests {@link AtomicInteger#getAndAdd(int)} which indirectly tests
- * {@link Unsafe#compareAndSwapInt(Object, long, int, int)}.
+ * Tests {@link AtomicInteger#getAndAdd(int)} which tests HSAIL atomic_add codegen.
  */
 public class AtomicIntGetAndAddTest extends GraalKernelTester {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndSetTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.hsail.test;
+
+import java.util.*;
+import java.util.concurrent.atomic.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Tests {@link AtomicInteger#getAndSet(int)} which tests HSAIL atomic_exch codegen.
+ */
+public class AtomicIntGetAndSetTest extends GraalKernelTester {
+
+    static final int NUM = 1000;
+    @Result public int[] outArray = new int[NUM];
+    AtomicInteger atomicInt = new AtomicInteger(Integer.MAX_VALUE);
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            outArray[i] = -i;
+        }
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+
+        dispatchMethodKernel(NUM);
+        // to complete the circle, replace the initial get value with that of the last executor
+        for (int i = 0; i < NUM; i++) {
+            if (outArray[i] == Integer.MAX_VALUE) {
+                outArray[i] = atomicInt.get();
+            }
+        }
+
+        // note: the actual order of entries in outArray is not predictable
+        // thus we sort before we compare results
+        Arrays.sort(outArray);
+    }
+
+    public void run(int gid) {
+        outArray[gid] = atomicInt.getAndSet(gid);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndAddTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndAddTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,13 +27,10 @@
 
 import org.junit.*;
 
-import sun.misc.*;
-
 import com.oracle.graal.compiler.hsail.test.infra.*;
 
 /**
- * Tests {@link AtomicLong#getAndAdd(long)} which indirectly tests
- * {@link Unsafe#compareAndSwapLong(Object, long, long, long)}.
+ * Tests {@link AtomicLong#getAndAdd(long)} which tests HSAIL atomic_add codegen.
  */
 public class AtomicLongGetAndAddTest extends GraalKernelTester {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndSetTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.hsail.test;
+
+import java.util.*;
+import java.util.concurrent.atomic.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Tests {@link AtomicLong#getAndSet(long)} which tests HSAIL atomic_exch codegen.
+ */
+public class AtomicLongGetAndSetTest extends GraalKernelTester {
+
+    static final int NUM = 1000;
+    @Result public long[] outArray = new long[NUM];
+    AtomicLong atomicLong = new AtomicLong(Long.MAX_VALUE);
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            outArray[i] = -i;
+        }
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+
+        dispatchMethodKernel(NUM);
+        // to complete the circle, replace the initial get value with that of the last executor
+        for (int i = 0; i < NUM; i++) {
+            if (outArray[i] == Long.MAX_VALUE) {
+                outArray[i] = atomicLong.get();
+            }
+        }
+
+        // note: the actual order of entries in outArray is not predictable
+        // thus we sort before we compare results
+        Arrays.sort(outArray);
+    }
+
+    public void run(int gid) {
+        outArray[gid] = atomicLong.getAndSet(gid);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicReferenceGetAndSetTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicReferenceGetAndSetTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -96,7 +96,6 @@
     }
 
     @Test
-    @Ignore
     public void test() {
         testGeneratedHsail();
     }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -118,9 +118,8 @@
         dispatchMethodKernel(size, out, in);
     }
 
-    // Marked to only run on hardware until simulator spill bug is fixed.
-    @Ignore
     @Test
+    @Ignore("until stack slots are supported in deopt")
     public void test() {
         testGeneratedHsail();
     }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -87,9 +87,8 @@
         dispatchMethodKernel(size, out, in);
     }
 
-    // Marked to only run on hardware until simulator spill bug is fixed.
-    @Ignore
     @Test
+    @Ignore("until stack slots are supported in deopt")
     public void test() {
         testGeneratedHsail();
     }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NewStringEqualsTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NewStringEqualsTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -25,11 +25,11 @@
 
 import static com.oracle.graal.debug.Debug.*;
 
-import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
 import com.oracle.graal.debug.*;
 
-import org.junit.Test;
-
 /**
  * Tests creating a String and calling .equals() on it.
  */
@@ -64,14 +64,16 @@
     }
 
     // NYI emitForeignCall charAlignedDisjointArraycopy
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void test() {
         try (DebugConfigScope s = disableIntercept()) {
             testGeneratedHsail();
         }
     }
 
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void testUsingLambdaMethod() {
         try (DebugConfigScope s = disableIntercept()) {
             testGeneratedHsailUsingLambdaMethod();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NonEscapingNewObjWithArrayTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NonEscapingNewObjWithArrayTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,12 +26,12 @@
 import static com.oracle.graal.debug.Debug.*;
 import static com.oracle.graal.debug.DelegatingDebugConfig.Feature.*;
 
-import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import com.oracle.graal.debug.*;
+import java.util.*;
 
-import org.junit.Test;
+import org.junit.*;
 
-import java.util.Arrays;
+import com.oracle.graal.compiler.hsail.test.infra.*;
+import com.oracle.graal.debug.*;
 
 /**
  * Tests non-escaping object creation and calling a method on it.
@@ -78,14 +78,16 @@
     }
 
     // NYI emitForeignCall floatArraycopy
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void test() {
         try (DebugConfigScope s = disableIntercept()) {
             testGeneratedHsail();
         }
     }
 
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void testUsingLambdaMethod() {
         try (DebugConfigScope dcs = setConfig(new DelegatingDebugConfig().disable(INTERCEPT))) {
             testGeneratedHsailUsingLambdaMethod();
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -33,9 +33,9 @@
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
 import com.oracle.graal.lir.hsail.HSAILArithmetic.ConvertOp;
 import com.oracle.graal.lir.hsail.HSAILArithmetic.Op1Stack;
@@ -51,8 +51,6 @@
 import com.oracle.graal.lir.hsail.HSAILMove.MembarOp;
 import com.oracle.graal.lir.hsail.HSAILMove.MoveFromRegOp;
 import com.oracle.graal.lir.hsail.HSAILMove.MoveToRegOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -416,7 +414,7 @@
     }
 
     @Override
-    public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
@@ -439,7 +437,7 @@
     }
 
     @Override
-    public Value emitRem(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
@@ -461,12 +459,12 @@
     }
 
     @Override
-    public Variable emitUDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Variable emitUDiv(Value a, Value b, LIRFrameState state) {
         throw GraalInternalError.unimplemented();
     }
 
     @Override
-    public Variable emitURem(Value a, Value b, DeoptimizingNode deopting) {
+    public Variable emitURem(Value a, Value b, LIRFrameState state) {
         throw GraalInternalError.unimplemented();
     }
 
@@ -684,7 +682,7 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value speculation, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
         append(new ReturnOp(Value.ILLEGAL));
     }
 
@@ -831,7 +829,7 @@
      * Graal generates for any switch construct appearing in Java bytecode.
      */
     @Override
-    protected void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
+    public void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
         emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget);
     }
 
@@ -856,7 +854,7 @@
      * @param key the key that is compared against the key constants in the case statements.
      */
     @Override
-    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
         if ((key.getKind() == Kind.Int) || (key.getKind() == Kind.Long)) {
             // Append the LIR instruction for generating compare and branch instructions.
             append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key));
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -28,6 +28,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
 import com.oracle.graal.nodes.*;
 
@@ -36,7 +37,7 @@
  */
 public abstract class HSAILNodeLIRBuilder extends NodeLIRBuilder {
 
-    public HSAILNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public HSAILNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
@@ -66,7 +67,7 @@
         assert v.stamp() instanceof ObjectStamp;
         Variable obj = newVariable(Kind.Object);
         gen.emitMove(obj, operand(v));
-        append(new HSAILMove.NullCheckOp(obj, gen.state(deopting)));
+        append(new HSAILMove.NullCheckOp(obj, state(deopting)));
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -35,9 +35,9 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.ptx.*;
 import com.oracle.graal.lir.ptx.PTXArithmetic.ConvertOp;
 import com.oracle.graal.lir.ptx.PTXArithmetic.Op1Stack;
@@ -59,9 +59,6 @@
 import com.oracle.graal.lir.ptx.PTXMemOp.StoreReturnValOp;
 import com.oracle.graal.lir.ptx.PTXMove.MoveFromRegOp;
 import com.oracle.graal.lir.ptx.PTXMove.MoveToRegOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -232,25 +229,17 @@
     }
 
     @Override
-    public Variable emitLoad(PlatformKind kind, Value address, Access access) {
+    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
         PTXAddressValue loadAddress = asAddress(address);
         Variable result = newVariable(kind);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
         append(new LoadOp((Kind) kind, result, loadAddress, state));
         return result;
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, Access access) {
+    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
         PTXAddressValue storeAddress = asAddress(address);
         Variable input = load(inputVal);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
         append(new StoreOp((Kind) kind, storeAddress, input, state));
     }
 
@@ -496,7 +485,7 @@
     }
 
     @Override
-    public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
@@ -518,7 +507,7 @@
     }
 
     @Override
-    public Value emitRem(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
@@ -534,12 +523,12 @@
     }
 
     @Override
-    public Variable emitUDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Variable emitUDiv(Value a, Value b, LIRFrameState state) {
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitUDiv()");
     }
 
     @Override
-    public Variable emitURem(Value a, Value b, DeoptimizingNode deopting) {
+    public Variable emitURem(Value a, Value b, LIRFrameState state) {
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitURem()");
     }
 
@@ -751,7 +740,7 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value speculation, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
         append(new ReturnOp(Value.ILLEGAL));
     }
 
@@ -842,7 +831,7 @@
     }
 
     @Override
-    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
         boolean needsTemp = key.getKind() == Kind.Object;
         append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL, nextPredRegNum++));
     }
@@ -860,16 +849,16 @@
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitUnwind()");
     }
 
-    public Variable emitLoadParam(Kind kind, Value address, DeoptimizingNode deopting) {
+    public Variable emitLoadParam(Kind kind, Value address, LIRFrameState state) {
 
         PTXAddressValue loadAddress = asAddress(address);
         Variable result = newVariable(kind);
-        append(new LoadParamOp(kind, result, loadAddress, deopting != null ? state(deopting) : null));
+        append(new LoadParamOp(kind, result, loadAddress, state));
 
         return result;
     }
 
-    public Variable emitLoadReturnAddress(Kind kind, Value address, DeoptimizingNode deopting) {
+    public Variable emitLoadReturnAddress(Kind kind, Value address, LIRFrameState state) {
         PTXAddressValue loadAddress = asAddress(address);
         Variable result;
         switch (kind) {
@@ -882,15 +871,15 @@
             default:
                 result = newVariable(kind);
         }
-        append(new LoadReturnAddrOp(kind, result, loadAddress, deopting != null ? state(deopting) : null));
+        append(new LoadReturnAddrOp(kind, result, loadAddress, state));
 
         return result;
     }
 
-    public void emitStoreReturnValue(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) {
+    public void emitStoreReturnValue(Kind kind, Value address, Value inputVal, LIRFrameState state) {
         PTXAddressValue storeAddress = asAddress(address);
         Variable input = load(inputVal);
-        append(new StoreReturnValOp(kind, storeAddress, input, deopting != null ? state(deopting) : null));
+        append(new StoreReturnValOp(kind, storeAddress, input, state));
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -31,6 +31,7 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.ptx.*;
 import com.oracle.graal.nodes.*;
 
@@ -55,7 +56,7 @@
         }
     }
 
-    public PTXNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public PTXNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
@@ -135,7 +136,7 @@
     @Override
     public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
         assert v.getKind() == Kind.Object;
-        append(new PTXMove.NullCheckOp(gen.load(operand(v)), gen.state(deopting)));
+        append(new PTXMove.NullCheckOp(gen.load(operand(v)), state(deopting)));
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,7 +27,9 @@
 import static com.oracle.graal.lir.sparc.SPARCArithmetic.*;
 import static com.oracle.graal.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.*;
 import static com.oracle.graal.lir.sparc.SPARCCompare.*;
+import static com.oracle.graal.lir.sparc.SPARCControlFlow.*;
 import static com.oracle.graal.lir.sparc.SPARCMathIntrinsicOp.IntrinsicOpcode.*;
+import static com.oracle.graal.lir.sparc.SPARCMove.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -36,31 +38,10 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryCommutative;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegConst;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegReg;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.Op1Stack;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.Op2Stack;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.RemOp;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.Unary2Op;
-import com.oracle.graal.lir.sparc.SPARCCompare.CompareOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.BranchOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.CondMoveOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.FloatCondMoveOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.StrategySwitchOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp;
-import com.oracle.graal.lir.sparc.SPARCMove.LoadAddressOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MembarOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp;
-import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -131,7 +112,7 @@
 
     @Override
     public void emitData(AllocatableValue dst, byte[] data) {
-        throw GraalInternalError.unimplemented();
+        append(new LoadDataAddressOp(dst, data));
     }
 
     @Override
@@ -158,7 +139,7 @@
                 indexRegister = Value.ILLEGAL;
             } else {
                 if (scale != 1) {
-                    Value longIndex = emitSignExtend(index, 32, 64);
+                    Value longIndex = index.getKind() == Kind.Long ? index : emitSignExtend(index, 32, 64);
                     if (CodeUtil.isPowerOf2(scale)) {
                         indexRegister = emitShl(longIndex, Constant.forLong(CodeUtil.log2(scale)));
                     } else {
@@ -186,16 +167,20 @@
         // If we don't have an index register we can use a displacement, otherwise load the
         // displacement into a register and add it to the base.
         if (indexRegister.equals(Value.ILLEGAL)) {
-            // TODO What if displacement if too big?
             displacementInt = (int) finalDisp;
+            assert SPARCAssembler.isSimm13(displacementInt) : displacementInt;
         } else {
             displacementInt = 0;
             if (baseRegister.equals(Value.ILLEGAL)) {
                 baseRegister = load(Constant.forLong(finalDisp));
             } else {
-                Variable longBaseRegister = newVariable(Kind.Long);
-                emitMove(longBaseRegister, baseRegister);  // FIXME get rid of this move
-                baseRegister = emitAdd(longBaseRegister, Constant.forLong(finalDisp));
+                if (finalDisp == 0) {
+                    // Nothing to do. Just use the base register.
+                } else {
+                    Variable longBaseRegister = newVariable(Kind.Long);
+                    emitMove(longBaseRegister, baseRegister);
+                    baseRegister = emitAdd(longBaseRegister, Constant.forLong(finalDisp));
+                }
             }
         }
 
@@ -284,15 +269,16 @@
         Condition finalCondition = mirrored ? cond.mirror() : cond;
 
         Variable result = newVariable(trueValue.getKind());
-        switch (left.getKind().getStackKind()) {
+        Kind kind = left.getKind().getStackKind();
+        switch (kind) {
             case Int:
             case Long:
             case Object:
-                append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue)));
+                append(new CondMoveOp(kind, result, finalCondition, load(trueValue), loadNonConst(falseValue)));
                 break;
             case Float:
             case Double:
-                append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
+                append(new FloatCondMoveOp(kind, result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere("" + left.getKind());
@@ -347,7 +333,8 @@
     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
         emitIntegerTest(left, right);
         Variable result = newVariable(trueValue.getKind());
-        append(new CondMoveOp(result, Condition.EQ, load(trueValue), loadNonConst(falseValue)));
+        Kind kind = left.getKind().getStackKind();
+        append(new CondMoveOp(kind, result, Condition.EQ, load(trueValue), loadNonConst(falseValue)));
         return result;
     }
 
@@ -362,7 +349,7 @@
     }
 
     @Override
-    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
         // a temp is needed for loading long and object constants
         boolean needsTemp = key.getKind() == Kind.Long || key.getKind() == Kind.Object;
         append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL));
@@ -593,7 +580,7 @@
     }
 
     @Override
-    public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind().getStackKind()) {
             case Int:
@@ -615,8 +602,7 @@
     }
 
     @Override
-    public Value emitRem(Value a, Value b, DeoptimizingNode deopting) {
-        LIRFrameState state = state(deopting);
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind().getStackKind()) {
             case Int:
@@ -632,7 +618,7 @@
     }
 
     @Override
-    public Value emitUDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitUDiv(Value a, Value b, LIRFrameState state) {
         // LIRFrameState state = state(deopting);
         switch (a.getKind().getStackKind()) {
             case Int:
@@ -647,7 +633,7 @@
     }
 
     @Override
-    public Value emitURem(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitURem(Value a, Value b, LIRFrameState state) {
         // LIRFrameState state = state(deopting);
         switch (a.getKind().getStackKind()) {
             case Int:
@@ -814,22 +800,23 @@
             return inputVal;
         } else if (toBits > 32) {
             // sign extend to 64 bits
-            if (fromBits == 32) {
-                return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal));
-            } else if (fromBits < 32) {
-                // TODO implement direct x2L sign extension conversions
-                Value intVal = emitSignExtend(inputVal, fromBits, 32);
-                return emitSignExtend(intVal, 32, toBits);
-            } else {
-                throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            switch (fromBits) {
+                case 8:
+                    return emitConvert2Op(Kind.Long, B2L, asAllocatable(inputVal));
+                case 16:
+                    return emitConvert2Op(Kind.Long, S2L, asAllocatable(inputVal));
+                case 32:
+                    return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal));
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
             }
         } else {
             // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
             switch (fromBits) {
                 case 8:
-                    return emitConvert2Op(Kind.Int, I2B, asAllocatable(inputVal));
+                    return emitConvert2Op(Kind.Int, B2I, asAllocatable(inputVal));
                 case 16:
-                    return emitConvert2Op(Kind.Int, I2S, asAllocatable(inputVal));
+                    return emitConvert2Op(Kind.Int, S2I, asAllocatable(inputVal));
                 case 32:
                     return inputVal;
                 default:
@@ -917,7 +904,7 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value speculation, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
         append(new ReturnOp(Value.ILLEGAL));
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
 import com.oracle.graal.nodes.*;
@@ -36,7 +37,7 @@
  */
 public abstract class SPARCNodeLIRBuilder extends NodeLIRBuilder {
 
-    public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
@@ -60,7 +61,7 @@
     @Override
     public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
         assert v.getKind() == Kind.Object;
-        append(new NullCheckOp(gen.load(operand(v)), gen.state(deopting)));
+        append(new NullCheckOp(gen.load(operand(v)), state(deopting)));
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Tue Apr 29 12:43:27 2014 -0700
@@ -52,7 +52,7 @@
  */
 public class CheckGraalInvariants extends GraalTest {
 
-    @LongTest
+    @Test
     public void test() {
         RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class);
         Providers providers = rt.getHostBackend().getProviders();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,23 +22,16 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.nodes.ConstantNode.*;
-import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static org.junit.Assert.*;
-
 import org.junit.*;
 
 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.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
 /**
- * Collection of tests for {@link ConditionalEliminationPhase} including those that triggered bugs
- * in this phase.
+ * Collection of tests for {@link com.oracle.graal.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest extends GraalCompilerTest {
 
@@ -88,174 +81,6 @@
         } while (true);
     }
 
-    /**
-     * This test presents a code pattern that triggered a bug where a (non-eliminated) checkcast
-     * caused an enclosing instanceof (for the same object and target type) to be incorrectly
-     * eliminated.
-     */
-    @Test
-    public void testReanchoringIssue() {
-        Entry end = new Entry("end");
-        EntryWithNext e1 = new EntryWithNext("e1", end);
-        EntryWithNext e2 = new EntryWithNext("e2", e1);
-
-        test("search", e2, "e3", new Entry("e4"));
-    }
-
-    @SuppressWarnings("unused")
-    public static int testNullnessSnippet(Object a, Object b) {
-        if (a == null) {
-            if (a == b) {
-                if (b == null) {
-                    return 1;
-                } else {
-                    return -2;
-                }
-            } else {
-                if (b == null) {
-                    return -3;
-                } else {
-                    return 4;
-                }
-            }
-        } else {
-            if (a == b) {
-                if (b == null) {
-                    return -5;
-                } else {
-                    return 6;
-                }
-            } else {
-                if (b == null) {
-                    return 7;
-                } else {
-                    return 8;
-                }
-            }
-        }
-    }
-
-    @Test
-    public void testNullness() {
-        test("testNullnessSnippet", null, null);
-        test("testNullnessSnippet", null, new Object());
-        test("testNullnessSnippet", new Object(), null);
-        test("testNullnessSnippet", new Object(), new Object());
-
-        StructuredGraph graph = parse("testNullnessSnippet");
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        for (ConstantNode constant : getConstantNodes(graph)) {
-            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
-                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
-            }
-        }
-    }
-
-    @SuppressWarnings("unused")
-    public static int testDisjunctionSnippet(Object a) {
-        try {
-            if (a instanceof Integer) {
-                if (a == null) {
-                    return -1;
-                } else {
-                    return 2;
-                }
-            } else {
-                return 3;
-            }
-        } finally {
-            field = null;
-        }
-    }
-
-    @Test
-    public void testDisjunction() {
-        StructuredGraph graph = parse("testDisjunctionSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        IfNode ifNode = (IfNode) graph.start().next();
-        InstanceOfNode instanceOf = (InstanceOfNode) ifNode.condition();
-        IsNullNode x = graph.unique(new IsNullNode(graph.getParameter(0)));
-        InstanceOfNode y = instanceOf;
-        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(true).apply(graph, new PhaseContext(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        for (ConstantNode constant : getConstantNodes(graph)) {
-            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
-                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
-            }
-        }
-    }
-
-    public static int testInvokeSnippet(Number n) {
-        if (n instanceof Integer) {
-            return n.intValue();
-        } else {
-            return 1;
-        }
-    }
-
-    @Test
-    public void testInvoke() {
-        test("testInvokeSnippet", new Integer(16));
-        StructuredGraph graph = parse("testInvokeSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-
-        InvokeNode invoke = graph.getNodes().filter(InvokeNode.class).first();
-        assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind());
-    }
-
-    public static void testTypeMergingSnippet(Object o, boolean b) {
-        if (b) {
-            if (!(o instanceof Double)) {
-                return;
-            }
-        } else {
-            if (!(o instanceof Integer)) {
-                return;
-            }
-        }
-
-        /*
-         * For this test the conditional elimination has to correctly merge the type information it
-         * has about o, so that it can remove the check on Number.
-         */
-        if (!(o instanceof Number)) {
-            field = o;
-        }
-    }
-
-    @Test
-    public void testTypeMerging() {
-        StructuredGraph graph = parse("testTypeMergingSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-
-        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(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-
-        assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
-    }
-
     public static int testRedundantComparesSnippet(int[] array) {
         if (array == null) {
             return 0;
@@ -272,39 +97,17 @@
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
         new FloatingReadPhase().apply(graph);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        new ConditionalEliminationPhase(getMetaAccess()).apply(graph, context);
         canonicalizer.apply(graph, context);
 
         assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
     }
 
-    public static int testDuplicateNullChecksSnippet(Object a) {
-        if (a == null) {
-            return 2;
-        }
-        try {
-            return ((Integer) a).intValue();
-        } catch (ClassCastException e) {
-            return 0;
+    public static String testInstanceOfCheckCastSnippet(Object e) {
+        if (e instanceof Entry) {
+            return ((Entry) e).name;
         }
-    }
-
-    @Test
-    @Ignore
-    public void testDuplicateNullChecks() {
-        // This tests whether explicit null checks properly eliminate later null guards. Currently
-        // it's failing.
-        StructuredGraph graph = parse("testDuplicateNullChecksSnippet");
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-        PhaseContext context = new PhaseContext(getProviders(), null);
-
-        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
-        canonicalizer.apply(graph, context);
-        new FloatingReadPhase().apply(graph);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        canonicalizer.apply(graph, context);
-
-        assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
+        return null;
     }
 
     @Test
@@ -317,9 +120,10 @@
 
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        new ConditionalEliminationPhase(getMetaAccess()).apply(graph, context);
         canonicalizer.apply(graph, context);
 
         assertEquals(0, graph.getNodes().filter(GuardNode.class).count());
     }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,395 @@
+/*
+ * 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.compiler.test;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugConfig;
+import com.oracle.graal.debug.DebugConfigScope;
+import com.oracle.graal.debug.internal.DebugScope;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.calc.ObjectEqualsNode;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
+import org.junit.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Tests whether {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} actually
+ * performs some graph rewritings that it's supposed to perform.
+ */
+public class FlowSenReduTest extends GraalCompilerTest {
+
+    /*
+     * A previous instanceof makes redundant a follow-up checkcast.
+     */
+    public Object redundantCheckCastSnippet(Number o) {
+        Integer z = null;
+        if (o instanceof Integer) {
+            z = (Integer) o; // this CheckCastNode will be removed
+        }
+        return z;
+    }
+
+    static final Integer i7 = new Integer(7);
+
+    @Test
+    public void redundantCheckCastTest() {
+        assertEquals(i7, redundantCheckCastSnippet(i7));
+        StructuredGraph result = afterFlowSensitiveReduce("redundantCheckCastSnippet");
+        nodeCountEquals(result, CheckCastNode.class, 0);
+        nodeCountEquals(result, InstanceOfNode.class, 1);
+    }
+
+    @SuppressWarnings("unused")
+    public boolean redundantInstanceOfSnippet01(Object o) {
+        if (o != null) {
+            Integer x = (Integer) o;
+            return (o instanceof Number); // this InstanceOfNode will be removed
+        }
+        return false;
+    }
+
+    @Test
+    public void redundantInstanceOfTest01() {
+        String snippet = "redundantInstanceOfSnippet01";
+        assertEquals(true, redundantInstanceOfSnippet01(i7));
+        nodeCountEquals(afterFlowSensitiveReduce(snippet), InstanceOfNode.class, 1);
+    }
+
+    /*
+     * The combination of (previous) non-null-check and checkcast make redundant an instanceof.
+     */
+    @SuppressWarnings("unused")
+    public Object redundantInstanceOfSnippet02(Object o) {
+        Integer x = (Integer) o;
+        if (o != null) {
+            if (o instanceof Number) { // this InstanceOfNode will be removed
+                return o;
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void redundantInstanceOfTest02() {
+        String snippet = "redundantInstanceOfSnippet02";
+        assertEquals(i7, redundantInstanceOfSnippet02(i7));
+        int ioAfter = getNodes(afterFlowSensitiveReduce(snippet), InstanceOfNode.class).size();
+        assertEquals(ioAfter, 1);
+    }
+
+    /*
+     * Once an exact-type has been inferred (due to instanceof final-class) a callsite is
+     * devirtualized.
+     */
+    public int devirtualizationSnippet(Object x, Object y) {
+        boolean c = x instanceof Integer;
+        if (c && x == y) {
+            Number z = (Number) y; // this CheckCastNode will be removed
+            return z.intValue(); // devirtualized into InvokeSpecial on Integer.intValue()
+        }
+        return 0;
+    }
+
+    @Test
+    public void devirtualizationTest() {
+        String snippet = "devirtualizationSnippet";
+        assertEquals(i7, devirtualizationSnippet(i7, i7));
+        nodeCountEquals(afterFlowSensitiveReduce(snippet), CheckCastNode.class, 0);
+
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
+
+        List<InvokeNode> invokeNodes = getNodes(afterFlowSensitiveReduce(snippet), InvokeNode.class);
+        assertEquals(1, invokeNodes.size());
+
+        MethodCallTargetNode target = (MethodCallTargetNode) invokeNodes.get(0).callTarget();
+        assertEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind());
+        assertEquals("HotSpotMethod<Integer.intValue()>", target.targetMethod().toString());
+    }
+
+    /*
+     * At the return statement, the returned value has been inferred to have type j.l.Number. The
+     * instanceof is deemed to always evaluate to false. The interplay with tail-duplication is also
+     * taken into account (resulting in two return statements, each with "false" as input).
+     */
+    @SuppressWarnings("unused")
+    public boolean t5Snippet(Object o, boolean b) {
+        Number z;
+        if (b) {
+            z = (Number) o; // tail duplication of return stmt, which becomes "return false"
+        } else {
+            z = (Integer) o; // tail duplication of return stmt, which becomes "return false"
+        }
+        return o instanceof String; // unreachable
+    }
+
+    @Test
+    public void t5a() {
+        String snippet = "t5Snippet";
+        assertEquals(false, t5Snippet(null, true));
+        StructuredGraph resultGraph = canonicalize(afterFlowSensitiveReduce(snippet));
+        nodeCountEquals(resultGraph, ReturnNode.class, 2);
+
+        List<ReturnNode> returnNodes = getNodes(resultGraph, ReturnNode.class);
+        Iterator<ReturnNode> iter = returnNodes.iterator();
+
+        ConstantNode c1 = (ConstantNode) iter.next().result();
+        ConstantNode c2 = (ConstantNode) iter.next().result();
+
+        assertEquals(c1, c2);
+        assertEquals(0, c1.getValue().asInt());
+    }
+
+    @Test
+    public void t5b() {
+        String snippet = "t5Snippet";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        canonicalize(graph);
+        nodeCountEquals(graph, InstanceOfNode.class, 2);
+    }
+
+    public boolean t6Snippet(Object x, Object y) {
+        if (!(x instanceof String)) {
+            return false;
+        }
+        if (!(y instanceof Number)) {
+            return false;
+        }
+        return x == y; // two known-not-to-conform reference values can't be ==
+    }
+
+    // TODO: two known-not-to-conform reference values can't be ==
+    // but baseCaseObjectEqualsNode doesn't check that as of now.
+    public void t6() {
+        String snippet = "t6Snippet";
+        // visualize(snippet);
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        canonicalize(graph);
+        nodeCountEquals(graph, ObjectEqualsNode.class, 0);
+    }
+
+    /*
+     * A previous instanceof check causes a follow-up instanceof to be deemed unsatisfiable,
+     * resulting in constant-substitution at that usage.
+     */
+    public Object t7Snippet(Object o) {
+        if (o instanceof Number) {
+            if (o instanceof String) { // condition amounts to false
+                return o; // made unreachable
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void t7() {
+        String snippet = "t7Snippet";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        graph = dce(canonicalize(graph));
+        // TODO how to simplify IfNode(false)
+        assertEquals(1, getNodes(graph, InstanceOfNode.class).size());
+
+        List<ReturnNode> returnNodes = getNodes(graph, ReturnNode.class);
+        assertEquals(2, returnNodes.size());
+        Iterator<ReturnNode> iter = returnNodes.iterator();
+
+        ConstantNode c1 = (ConstantNode) iter.next().result();
+        ConstantNode c2 = (ConstantNode) iter.next().result();
+
+        assertEquals(c1, c2);
+        Assert.assertTrue(c1.getValue().isNull());
+    }
+
+    /*
+     * During FlowSensitiveReduction, an unreachable branch doesn't contribute to the merged state.
+     * The resulting ("non-polluted") more precise inferred type after the merge allows
+     * devirtualizing a callsite.
+     */
+    public int devirtualizationSnippet02(Number o) {
+        if (o instanceof Integer) {
+            Number z = o;
+            if (o instanceof Long) {
+                z = o;
+            }
+            /*
+             * devirtualized into InvokeSpecial on Integer.intValue() ie the inferred-type is not
+             * polluted with values from the unreachable branch.
+             */
+            return z.intValue();
+        }
+        return 0;
+    }
+
+    @Test
+    public void devirtualizationTest02() {
+        String snippet = "devirtualizationSnippet02";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+
+        assertEquals(1, getNodes(graph, InvokeNode.class).size());
+
+        List<InvokeNode> invokeNodes = getNodes(graph, InvokeNode.class);
+        assertEquals(1, invokeNodes.size());
+
+        MethodCallTargetNode target = (MethodCallTargetNode) invokeNodes.get(0).callTarget();
+        assertEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind());
+        assertEquals("HotSpotMethod<Integer.intValue()>", target.targetMethod().toString());
+    }
+
+    /*
+     * TODO ClassCastException known to fail --- either Deopt or throw ObjectGetClassNode The latter
+     * might lead to direct jump to EH if present.
+     */
+    @SuppressWarnings("unused")
+    public int t9Snippet(Object o) {
+        try {
+            if (o instanceof Number) {
+                String s = (String) o;
+                /*
+                 * make a long story short: replace the above with throw new ClassCastException (ok,
+                 * actual type of o unknown).
+                 */
+                return 1;
+            }
+        } catch (ClassCastException e) {
+            return 2;
+        }
+        return 3;
+    }
+
+    /*
+     * "Partial evaluation" via canonicalization of an expression (in the last return statement) one
+     * of whose leaf sub-expressions was determined to be constant.
+     */
+    @SuppressWarnings("unused")
+    public Object partialEvalSnippet01(Object o, boolean b) {
+        if (o == null) {
+            return o; // turned into "return null;"
+        } else {
+            Number z;
+            if (b) {
+                z = (Number) o;
+            } else {
+                z = (Integer) o;
+            }
+            return o instanceof String ? this : null; // turned into "return null;"
+        }
+    }
+
+    @Test
+    public void partialEvalTest01() {
+        String snippet = "partialEvalSnippet01";
+
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        canonicalize(graph);
+        dce(graph);
+
+        List<ReturnNode> returnNodes = getNodes(graph, ReturnNode.class);
+        assertEquals(2, returnNodes.size());
+        Iterator<ReturnNode> iter = returnNodes.iterator();
+
+        ValueNode c1 = GraphUtil.unproxify(iter.next().result());
+        ValueNode c2 = GraphUtil.unproxify(iter.next().result());
+        assert !iter.hasNext();
+
+        Assert.assertTrue(c1.isNullConstant());
+        Assert.assertTrue(c2.isNullConstant());
+    }
+
+    public static class C {
+        public int f;
+    }
+
+    /*
+     * A previous (assumed successful) instanceof check is reused later on to remove a checkcast.
+     */
+    public void deduplicateInstanceOfSnippet(Object o) {
+        ((C) o).f = ((C) o).f; // boils down to a single instanceof test
+    }
+
+    @Test
+    public void deduplicateInstanceOfTest() {
+        String snippet = "deduplicateInstanceOfSnippet";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        List<InstanceOfNode> ioNodes = getNodes(graph, InstanceOfNode.class);
+        assertEquals(1, ioNodes.size());
+
+    }
+
+    // ---------------------------------------------
+    // ----------------- UTILITIES -----------------
+    // ---------------------------------------------
+
+    private PhaseContext getPhaseContext() {
+        return new PhaseContext(getProviders(), null);
+    }
+
+    private static StructuredGraph dce(StructuredGraph graph) {
+        new DeadCodeEliminationPhase().apply(graph);
+        return graph;
+    }
+
+    private StructuredGraph canonicalize(StructuredGraph graph) {
+        new CanonicalizerPhase(true).apply(graph, getPhaseContext());
+        return graph;
+    }
+
+    private StructuredGraph flowSensitiveReduce(StructuredGraph graph) {
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, getPhaseContext());
+        return graph;
+    }
+
+    public static <N extends Node> List<N> getNodes(StructuredGraph graph, Class<N> nodeClass) {
+        return graph.getNodes().filter(nodeClass).snapshot();
+    }
+
+    public <N extends Node> void nodeCountEquals(StructuredGraph graph, Class<N> nodeClass, int expected) {
+        assertEquals(expected, getNodes(graph, nodeClass).size());
+    }
+
+    public StructuredGraph afterFlowSensitiveReduce(String snippet) {
+        StructuredGraph before = canonicalize(parse(snippet));
+        // visualize(before, snippet + "-before");
+        StructuredGraph result = flowSensitiveReduce(before);
+        // visualize(result, snippet + "-after");
+        return result;
+    }
+
+    public StructuredGraph visualize(StructuredGraph graph, String title) {
+        DebugConfig debugConfig = DebugScope.getConfig();
+        DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, debugConfig.dumpHandlers(), debugConfig.output());
+        try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
+            Debug.dump(graph, title);
+
+            return graph;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSensitiveReductionTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,293 @@
+/*
+ * 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.compiler.test;
+
+import static com.oracle.graal.nodes.ConstantNode.*;
+import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
+import static org.junit.Assert.*;
+
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
+import org.junit.*;
+
+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.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+
+/**
+ * Collection of tests for {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase}
+ * including those that triggered bugs in this phase.
+ */
+public class FlowSensitiveReductionTest extends GraalCompilerTest {
+
+    public static Object field;
+
+    static class Entry {
+
+        final String name;
+
+        public Entry(String name) {
+            this.name = name;
+        }
+    }
+
+    static class EntryWithNext extends Entry {
+
+        public EntryWithNext(String name, Entry next) {
+            super(name);
+            this.next = next;
+        }
+
+        final Entry next;
+    }
+
+    public static Entry search(Entry start, String name, Entry alternative) {
+        Entry current = start;
+        do {
+            while (current instanceof EntryWithNext) {
+                if (name != null && current.name == name) {
+                    current = null;
+                } else {
+                    Entry next = ((EntryWithNext) current).next;
+                    current = next;
+                }
+            }
+
+            if (current != null) {
+                if (current.name.equals(name)) {
+                    return current;
+                }
+            }
+            if (current == alternative) {
+                return null;
+            }
+            current = alternative;
+
+        } while (true);
+    }
+
+    /**
+     * This test presents a code pattern that triggered a bug where a (non-eliminated) checkcast
+     * caused an enclosing instanceof (for the same object and target type) to be incorrectly
+     * eliminated.
+     */
+    @Test
+    public void testReanchoringIssue() {
+        Entry end = new Entry("end");
+        EntryWithNext e1 = new EntryWithNext("e1", end);
+        EntryWithNext e2 = new EntryWithNext("e2", e1);
+
+        test("search", e2, "e3", new Entry("e4"));
+    }
+
+    @SuppressWarnings("unused")
+    public static int testNullnessSnippet(Object a, Object b) {
+        if (a == null) {
+            if (a == b) {
+                if (b == null) {
+                    return 1;
+                } else {
+                    return -2;
+                }
+            } else {
+                if (b == null) {
+                    return -3;
+                } else {
+                    return 4;
+                }
+            }
+        } else {
+            if (a == b) {
+                if (b == null) {
+                    return -5;
+                } else {
+                    return 6;
+                }
+            } else {
+                if (b == null) {
+                    return 7;
+                } else {
+                    return 8;
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testNullness() {
+        test("testNullnessSnippet", null, null);
+        test("testNullnessSnippet", null, new Object());
+        test("testNullnessSnippet", new Object(), null);
+        test("testNullnessSnippet", new Object(), new Object());
+
+        StructuredGraph graph = parse("testNullnessSnippet");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, context);
+        for (ConstantNode constant : getConstantNodes(graph)) {
+            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
+                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static int testDisjunctionSnippet(Object a) {
+        try {
+            if (a instanceof Integer) {
+                if (a == null) {
+                    return -1;
+                } else {
+                    return 2;
+                }
+            } else {
+                return 3;
+            }
+        } finally {
+            field = null;
+        }
+    }
+
+    @Test
+    public void testDisjunction() {
+        StructuredGraph graph = parse("testDisjunctionSnippet");
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+        IfNode ifNode = (IfNode) graph.start().next();
+        InstanceOfNode instanceOf = (InstanceOfNode) ifNode.condition();
+        IsNullNode x = graph.unique(new IsNullNode(graph.getParameter(0)));
+        InstanceOfNode y = instanceOf;
+        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(true).apply(graph, new PhaseContext(getProviders(), null));
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), null));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+        for (ConstantNode constant : getConstantNodes(graph)) {
+            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
+                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
+            }
+        }
+    }
+
+    public static int testInvokeSnippet(Number n) {
+        if (n instanceof Integer) {
+            return n.intValue();
+        } else {
+            return 1;
+        }
+    }
+
+    @Test
+    public void testInvoke() {
+        test("testInvokeSnippet", new Integer(16));
+        StructuredGraph graph = parse("testInvokeSnippet");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new CanonicalizerPhase(true).apply(graph, context);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+
+        InvokeNode invoke = graph.getNodes().filter(InvokeNode.class).first();
+        assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind());
+    }
+
+    public static void testTypeMergingSnippet(Object o, boolean b) {
+        if (b) {
+            if (!(o instanceof Double)) {
+                return;
+            }
+        } else {
+            if (!(o instanceof Integer)) {
+                return;
+            }
+        }
+
+        /*
+         * For this test the conditional elimination has to correctly merge the type information it
+         * has about o, so that it can remove the check on Number.
+         */
+        if (!(o instanceof Number)) {
+            field = o;
+        }
+    }
+
+    @Test
+    public void testTypeMerging() {
+        StructuredGraph graph = parse("testTypeMergingSnippet");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new CanonicalizerPhase(true).apply(graph, context);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+
+        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");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new CanonicalizerPhase(true).apply(graph, context);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+
+        assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
+    }
+
+    public static int testDuplicateNullChecksSnippet(Object a) {
+        if (a == null) {
+            return 2;
+        }
+        try {
+            return ((Integer) a).intValue();
+        } catch (ClassCastException e) {
+            return 0;
+        }
+    }
+
+    @Test
+    @Ignore
+    public void testDuplicateNullChecks() {
+        // This tests whether explicit null checks properly eliminate later null guards. Currently
+        // it's failing.
+        StructuredGraph graph = parse("testDuplicateNullChecksSnippet");
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+        PhaseContext context = new PhaseContext(getProviders(), null);
+
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        new FloatingReadPhase().apply(graph);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        canonicalizer.apply(graph, context);
+
+        assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -39,7 +39,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.test.*;
 
 /**
  * Test that infopoints in {@link CompilationResult}s have correctly assigned reasons.
@@ -72,7 +71,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void lineInfopoints() {
         final Method method = getMethod("testMethod");
         final StructuredGraph graph = parseDebug(method);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -53,7 +53,7 @@
  * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the
  * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the
  * right thing.
- * 
+ *
  * The scheduling shouldn't depend on FrameStates, which is tested by this class.
  */
 public class MemoryScheduleTest extends GraphScheduleTest {
@@ -247,7 +247,7 @@
     @Test
     public void testLoop5() {
         SchedulePhase schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(7, schedule.getCFG().getBlocks().length);
+        assertEquals(10, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -266,7 +266,7 @@
         StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
         assertEquals(1, graph.getNodes(ReturnNode.class).count());
         ReturnNode ret = graph.getNodes(ReturnNode.class).first();
-        assertTrue(ret.result() instanceof FloatingReadNode);
+        assertTrue(ret.result() + " should be a FloatingReadNode", ret.result() instanceof FloatingReadNode);
         assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
         assertReadWithinAllReturnBlocks(schedule, true);
     }
@@ -585,7 +585,7 @@
     private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode, final MemoryScheduling memsched, final SchedulingStrategy schedulingStrategy) {
         final StructuredGraph graph = parse(snippet);
         try (Scope d = Debug.scope("FloatingReadTest", graph)) {
-            try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS)) {
+            try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) {
                 Assumptions assumptions = new Assumptions(false);
                 HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
                 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.compiler.test;
 
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
@@ -167,8 +168,9 @@
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
         Assumptions assumptions = new Assumptions(false);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+        PhaseContext context = new PhaseContext(getProviders(), assumptions);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, context);
         StructuredGraph referenceGraph = parse(referenceSnippet);
         assertEquals(referenceGraph, graph);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,6 +24,7 @@
 
 import java.io.*;
 
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
@@ -184,7 +185,12 @@
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
         Assumptions assumptions = new Assumptions(false);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        /*
+         * When using FlowSensitiveReductionPhase instead of ConditionalEliminationPhase,
+         * tail-duplication gets activated thus resulting in a graph with more nodes than the
+         * reference graph.
+         */
+        new ConditionalEliminationPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), assumptions));
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
         // a second canonicalizer is needed to process nested MaterializeNodes
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
@@ -239,7 +245,7 @@
         StructuredGraph graph = parse(snippet);
         Assumptions assumptions = new Assumptions(false);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), assumptions));
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
         Debug.dump(graph, "Graph " + snippet);
         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/backend/AllocatorTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -34,13 +34,13 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.schedule.*;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -32,7 +32,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.test.*;
 
 /**
  * In the following tests, the usages of local variable "a" are replaced with the integer constant
@@ -51,7 +50,7 @@
         return f1 + " " + arg1 + " " + arg2 + " " + arg3;
     }
 
-    @LongTest
+    @Test
     public void test1() {
         Method method = getMethod("testMethod");
         final StructuredGraph graph = parse(method);
@@ -74,7 +73,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test3() {
         Method method = getMethod("testMethod");
         final StructuredGraph graph = parse(method);
@@ -88,7 +87,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test4() {
         Method method = getMethod("testMethodVirtual");
         final StructuredGraph graph = parse(method);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,7 +27,7 @@
 import sun.misc.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -38,7 +38,6 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.test.*;
 
 public class InliningTest extends GraalCompilerTest {
 
@@ -73,7 +72,7 @@
         assertInlined(getGraph("invokeMethodOnFieldSnippet", false));
     }
 
-    @LongTest
+    @Test
     public void testStaticBindableInliningIP() {
         assertManyMethodInfopoints(assertInlined(getGraph("invokeConstructorSnippet", true)));
         assertManyMethodInfopoints(assertInlined(getGraph("invokeFinalMethodSnippet", true)));
@@ -82,7 +81,7 @@
     }
 
     @Ignore("would need read elimination/EA before inlining")
-    @LongTest
+    @Test
     public void testDependentStaticBindableInliningIP() {
         assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFinalFieldSnippet", true)));
         assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFieldSnippet", true)));
@@ -180,7 +179,7 @@
         assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", false));
     }
 
-    @LongTest
+    @Test
     public void testClassHierarchyAnalysisIP() {
         assertManyMethodInfopoints(assertInlined(getGraph("invokeLeafClassMethodSnippet", true)));
         assertManyMethodInfopoints(assertInlined(getGraph("invokeConcreteMethodSnippet", true)));
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/nfi/NativeFunctionInterfaceTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/nfi/NativeFunctionInterfaceTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.compiler.test.nfi;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static java.io.File.*;
 import static java.lang.System.*;
 import static org.junit.Assert.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/META-INF/services/javax.annotation.processing.Processor	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,1 @@
+com.oracle.graal.compiler.match.MatchProcessor
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Apr 29 12:43:27 2014 -0700
@@ -35,15 +35,16 @@
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
@@ -207,7 +208,7 @@
         }
     }
 
-    private static void emitBlock(NodeLIRBuilder nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) {
+    private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) {
         if (lirGenRes.getLIR().getLIRforBlock(b) == null) {
             for (Block pred : b.getPredecessors()) {
                 if (!b.isLoopHeader() || !pred.isLoopEnd()) {
@@ -245,8 +246,8 @@
         try (Scope ds = Debug.scope("BackEnd", lir)) {
             FrameMap frameMap = backend.newFrameMap(registerConfig);
             LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMap, stub);
-            LIRGenerator lirGen = backend.newLIRGenerator(cc, lirGenRes);
-            NodeLIRBuilder nodeLirGen = backend.newNodeLIRGenerator(graph, lirGen);
+            LIRGeneratorTool lirGen = backend.newLIRGenerator(cc, lirGenRes);
+            NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen);
 
             try (Scope s = Debug.scope("LIRGen", lirGen)) {
                 for (Block b : linearScanOrder) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,16 +22,15 @@
  */
 package com.oracle.graal.compiler.gen;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.gen.*;
 
 public class BytecodeLIRBuilder {
-    protected final LIRGenerator gen;
+    protected final LIRGeneratorTool gen;
     protected final BytecodeParserTool parser;
 
-    public BytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public BytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         this.gen = gen;
         this.parser = parser;
     }
@@ -53,7 +52,7 @@
         gen.emitIncomingValues(params);
 
         Signature sig = method.getSignature();
-        boolean isStatic = Modifier.isStatic(method.getModifiers());
+        boolean isStatic = method.isStatic();
         for (int i = 0; i < sig.getParameterCount(!isStatic); i++) {
             Value paramValue = params[i];
             assert paramValue.getKind() == sig.getParameterKind(i).getStackKind();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -116,20 +116,33 @@
     }
 
     protected BytecodeFrame computeFrameForState(FrameState state) {
-        int numLocals = state.localsSize();
-        int numStack = state.stackSize();
-        int numLocks = state.locksSize();
+        try {
+            assert state.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI;
+            assert state.bci != BytecodeFrame.UNKNOWN_BCI;
+            assert state.bci != BytecodeFrame.BEFORE_BCI || state.locksSize() == 0;
+            assert state.bci != BytecodeFrame.AFTER_BCI || state.locksSize() == 0;
+            assert state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI || state.locksSize() == 0;
+            assert !(state.method().isSynchronized() && state.bci != BytecodeFrame.BEFORE_BCI && state.bci != BytecodeFrame.AFTER_BCI && state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI) ||
+                            state.locksSize() > 0;
+            assert state.verify();
+
+            int numLocals = state.localsSize();
+            int numStack = state.stackSize();
+            int numLocks = state.locksSize();
 
-        Value[] values = new Value[numLocals + numStack + numLocks];
-        computeLocals(state, numLocals, values);
-        computeStack(state, numLocals, numStack, values);
-        computeLocks(state, values);
+            Value[] values = new Value[numLocals + numStack + numLocks];
+            computeLocals(state, numLocals, values);
+            computeStack(state, numLocals, numStack, values);
+            computeLocks(state, values);
 
-        BytecodeFrame caller = null;
-        if (state.outerFrameState() != null) {
-            caller = computeFrameForState(state.outerFrameState());
+            BytecodeFrame caller = null;
+            if (state.outerFrameState() != null) {
+                caller = computeFrameForState(state.outerFrameState());
+            }
+            return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks);
+        } catch (GraalInternalError e) {
+            throw e.addContext("FrameState: ", state);
         }
-        return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks);
     }
 
     protected void computeLocals(FrameState state, int numLocals, Value[] values) {
@@ -168,39 +181,43 @@
     private static final DebugMetric STATE_CONSTANTS = Debug.metric("StateConstants");
 
     protected Value toValue(ValueNode value) {
-        if (value instanceof VirtualObjectNode) {
-            VirtualObjectNode obj = (VirtualObjectNode) value;
-            EscapeObjectState state = objectStates.get(obj);
-            if (state == null && obj.entryCount() > 0) {
-                // null states occur for objects with 0 fields
-                throw new GraalInternalError("no mapping found for virtual object %s", obj);
-            }
-            if (state instanceof MaterializedObjectState) {
-                return toValue(((MaterializedObjectState) state).materializedValue());
-            } else {
-                assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
-                VirtualObject vobject = virtualObjects.get(value);
-                if (vobject == null) {
-                    vobject = VirtualObject.get(obj.type(), null, virtualObjects.size());
-                    virtualObjects.put(obj, vobject);
+        try {
+            if (value instanceof VirtualObjectNode) {
+                VirtualObjectNode obj = (VirtualObjectNode) value;
+                EscapeObjectState state = objectStates.get(obj);
+                if (state == null && obj.entryCount() > 0) {
+                    // null states occur for objects with 0 fields
+                    throw new GraalInternalError("no mapping found for virtual object %s", obj);
                 }
-                STATE_VIRTUAL_OBJECTS.increment();
-                return vobject;
-            }
-        } else if (value instanceof ConstantNode) {
-            STATE_CONSTANTS.increment();
-            return ((ConstantNode) value).getValue();
+                if (state instanceof MaterializedObjectState) {
+                    return toValue(((MaterializedObjectState) state).materializedValue());
+                } else {
+                    assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
+                    VirtualObject vobject = virtualObjects.get(value);
+                    if (vobject == null) {
+                        vobject = VirtualObject.get(obj.type(), null, virtualObjects.size());
+                        virtualObjects.put(obj, vobject);
+                    }
+                    STATE_VIRTUAL_OBJECTS.increment();
+                    return vobject;
+                }
+            } else if (value instanceof ConstantNode) {
+                STATE_CONSTANTS.increment();
+                return ((ConstantNode) value).getValue();
 
-        } else if (value != null) {
-            STATE_VARIABLES.increment();
-            Value operand = nodeOperands.get(value);
-            assert operand != null && (operand instanceof Variable || operand instanceof Constant) : operand + " for " + value;
-            return operand;
+            } else if (value != null) {
+                STATE_VARIABLES.increment();
+                Value operand = nodeOperands.get(value);
+                assert operand != null && (operand instanceof Variable || operand instanceof Constant) : operand + " for " + value;
+                return operand;
 
-        } else {
-            // return a dummy value because real value not needed
-            STATE_ILLEGALS.increment();
-            return Value.ILLEGAL;
+            } else {
+                // return a dummy value because real value not needed
+                STATE_ILLEGALS.increment();
+                return Value.ILLEGAL;
+            }
+        } catch (GraalInternalError e) {
+            throw e.addContext("toValue: ", value);
         }
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResult.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.gen;
-
-import com.oracle.graal.lir.*;
-
-public interface LIRGenerationResult {
-    FrameMap getFrameMap();
-
-    LIR getLIR();
-
-    boolean hasForeignCall();
-
-    void setForeignCall(boolean b);
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResultBase.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.gen;
-
-import com.oracle.graal.lir.*;
-
-public class LIRGenerationResultBase implements LIRGenerationResult {
-    private final LIR lir;
-    private final FrameMap frameMap;
-    /**
-     * Records whether the code being generated makes at least one foreign call.
-     */
-    private boolean hasForeignCall;
-
-    public LIRGenerationResultBase(LIR lir, FrameMap frameMap) {
-        this.lir = lir;
-        this.frameMap = frameMap;
-    }
-
-    public LIR getLIR() {
-        return lir;
-    }
-
-    /**
-     * Determines whether the code being generated makes at least one foreign call.
-     */
-    public boolean hasForeignCall() {
-        return hasForeignCall;
-    }
-
-    public final void setForeignCall(boolean hasForeignCall) {
-        this.hasForeignCall = hasForeignCall;
-    }
-
-    public final FrameMap getFrameMap() {
-        return frameMap;
-    }
-
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,627 +0,0 @@
-/*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.gen;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.api.meta.Value.*;
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.lir.LIR.*;
-import static com.oracle.graal.lir.LIRValueUtil.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.common.spi.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.NoOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.options.*;
-
-/**
- * This class traverses the HIR instructions and generates LIR instructions from them.
- */
-public abstract class LIRGenerator implements ArithmeticLIRGenerator, LIRGeneratorTool, LIRTypeTool {
-
-    public static class Options {
-        // @formatter:off
-        @Option(help = "Print HIR along side LIR as the latter is generated")
-        public static final OptionValue<Boolean> PrintIRWithLIR = new OptionValue<>(false);
-        @Option(help = "The trace level for the LIR generator")
-        public static final OptionValue<Integer> TraceLIRGeneratorLevel = new OptionValue<>(0);
-        // @formatter:on
-    }
-
-    private final LIRProviders providers;
-    private final CallingConvention cc;
-
-    private DebugInfoBuilder debugInfoBuilder;
-
-    protected AbstractBlock<?> currentBlock;
-    public final int traceLevel;
-    public final boolean printIRWithLIR;
-
-    /**
-     * Handle for an operation that loads a constant into a variable. The operation starts in the
-     * first block where the constant is used but will eventually be
-     * {@linkplain LIRGenerator#insertConstantLoads() moved} to a block dominating all usages of the
-     * constant.
-     */
-    public static class LoadConstant implements Comparable<LoadConstant> {
-        /**
-         * The index of {@link #op} within {@link #block}'s instruction list or -1 if {@code op} is
-         * to be moved to a dominator block.
-         */
-        int index;
-
-        /**
-         * The operation that loads the constant.
-         */
-        private final LIRInstruction op;
-
-        /**
-         * The block that does or will contain {@link #op}. This is initially the block where the
-         * first usage of the constant is seen during LIR generation.
-         */
-        AbstractBlock<?> block;
-
-        /**
-         * The variable into which the constant is loaded.
-         */
-        final Variable variable;
-
-        public LoadConstant(Variable variable, AbstractBlock<?> block, int index, LIRInstruction op) {
-            this.variable = variable;
-            this.block = block;
-            this.index = index;
-            this.op = op;
-        }
-
-        /**
-         * Sorts {@link LoadConstant} objects according to their enclosing blocks. This is used to
-         * group loads per block in {@link LIRGenerator#insertConstantLoads()}.
-         */
-        public int compareTo(LoadConstant o) {
-            if (block.getId() < o.block.getId()) {
-                return -1;
-            }
-            if (block.getId() > o.block.getId()) {
-                return 1;
-            }
-            return 0;
-        }
-
-        @Override
-        public String toString() {
-            return block + "#" + op;
-        }
-
-        /**
-         * Removes the {@link #op} from its original location if it is still at that location.
-         */
-        public void unpin(LIR lir) {
-            if (index >= 0) {
-                // Replace the move with a filler op so that the operation
-                // list does not need to be adjusted.
-                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-                instructions.set(index, new NoOp(null, -1));
-                index = -1;
-            }
-        }
-    }
-
-    Map<Constant, LoadConstant> constantLoads;
-
-    private LIRGenerationResult res;
-
-    /**
-     * Set this before using the LIRGenerator.
-     *
-     * TODO this should be removed
-     */
-    void setDebugInfoBuilder(DebugInfoBuilder builder) {
-        debugInfoBuilder = builder;
-    }
-
-    /**
-     * Checks whether the supplied constant can be used without loading it into a register for store
-     * operations, i.e., on the right hand side of a memory access.
-     *
-     * @param c The constant to check.
-     * @return True if the constant can be used directly, false if the constant needs to be in a
-     *         register.
-     */
-    public abstract boolean canStoreConstant(Constant c, boolean isCompressed);
-
-    public LIRGenerator(LIRProviders providers, CallingConvention cc, LIRGenerationResult res) {
-        this.res = res;
-        this.providers = providers;
-        this.cc = cc;
-        this.traceLevel = Options.TraceLIRGeneratorLevel.getValue();
-        this.printIRWithLIR = Options.PrintIRWithLIR.getValue();
-    }
-
-    /**
-     * Returns true if the redundant move elimination optimization should be done after register
-     * allocation.
-     */
-    public boolean canEliminateRedundantMoves() {
-        return true;
-    }
-
-    @Override
-    public TargetDescription target() {
-        return getCodeCache().getTarget();
-    }
-
-    public LIRProviders getProviders() {
-        return providers;
-    }
-
-    @Override
-    public MetaAccessProvider getMetaAccess() {
-        return providers.getMetaAccess();
-    }
-
-    @Override
-    public CodeCacheProvider getCodeCache() {
-        return providers.getCodeCache();
-    }
-
-    @Override
-    public ForeignCallsProvider getForeignCalls() {
-        return providers.getForeignCalls();
-    }
-
-    /**
-     * Creates a new {@linkplain Variable variable}.
-     *
-     * @param platformKind The kind of the new variable.
-     * @return a new variable
-     */
-    @Override
-    public Variable newVariable(PlatformKind platformKind) {
-        return new Variable(platformKind, res.getLIR().nextVariable());
-    }
-
-    @Override
-    public RegisterAttributes attributes(Register register) {
-        return res.getFrameMap().registerConfig.getAttributesMap()[register.number];
-    }
-
-    @Override
-    public abstract Variable emitMove(Value input);
-
-    public AllocatableValue asAllocatable(Value value) {
-        if (isAllocatableValue(value)) {
-            return asAllocatableValue(value);
-        } else {
-            return emitMove(value);
-        }
-    }
-
-    public Variable load(Value value) {
-        if (!isVariable(value)) {
-            return emitMove(value);
-        }
-        return (Variable) value;
-    }
-
-    public Value loadNonConst(Value value) {
-        if (isConstant(value) && !canInlineConstant((Constant) value)) {
-            return emitMove(value);
-        }
-        return value;
-    }
-
-    /**
-     * Determines if only oop maps are required for the code generated from the LIR.
-     */
-    protected boolean needOnlyOopMaps() {
-        return false;
-    }
-
-    private static FrameState getFrameState(DeoptimizingNode deopt) {
-        if (deopt instanceof DeoptimizingNode.DeoptBefore) {
-            assert !(deopt instanceof DeoptimizingNode.DeoptDuring || deopt instanceof DeoptimizingNode.DeoptAfter);
-            return ((DeoptimizingNode.DeoptBefore) deopt).stateBefore();
-        } else if (deopt instanceof DeoptimizingNode.DeoptDuring) {
-            assert !(deopt instanceof DeoptimizingNode.DeoptAfter);
-            return ((DeoptimizingNode.DeoptDuring) deopt).stateDuring();
-        } else {
-            assert deopt instanceof DeoptimizingNode.DeoptAfter;
-            return ((DeoptimizingNode.DeoptAfter) deopt).stateAfter();
-        }
-    }
-
-    public LIRFrameState state(DeoptimizingNode deopt) {
-        if (!deopt.canDeoptimize()) {
-            return null;
-        }
-        return stateFor(getFrameState(deopt));
-    }
-
-    public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) {
-        if (!deopt.canDeoptimize()) {
-            return null;
-        }
-        return stateForWithExceptionEdge(getFrameState(deopt), exceptionEdge);
-    }
-
-    public LIRFrameState stateFor(FrameState state) {
-        return stateForWithExceptionEdge(state, null);
-    }
-
-    public LIRFrameState stateForWithExceptionEdge(FrameState state, LabelRef exceptionEdge) {
-        if (needOnlyOopMaps()) {
-            return new LIRFrameState(null, null, null);
-        }
-        assert state != null;
-        return getDebugInfoBuilder().build(state, exceptionEdge);
-    }
-
-    /**
-     * Gets the ABI specific operand used to return a value of a given kind from a method.
-     *
-     * @param kind the kind of value being returned
-     * @return the operand representing the ABI defined location used return a value of kind
-     *         {@code kind}
-     */
-    public AllocatableValue resultOperandFor(Kind kind) {
-        if (kind == Kind.Void) {
-            return ILLEGAL;
-        }
-        return res.getFrameMap().registerConfig.getReturnRegister(kind).asValue(kind);
-    }
-
-    public void append(LIRInstruction op) {
-        if (printIRWithLIR && !TTY.isSuppressed()) {
-            TTY.println(op.toStringWithIdPrefix());
-            TTY.println();
-        }
-        assert LIRVerifier.verify(op);
-        res.getLIR().getLIRforBlock(currentBlock).add(op);
-    }
-
-    public boolean hasBlockEnd(AbstractBlock<?> block) {
-        List<LIRInstruction> ops = getResult().getLIR().getLIRforBlock(block);
-        if (ops.size() == 0) {
-            return false;
-        }
-        return ops.get(ops.size() - 1) instanceof BlockEndOp;
-    }
-
-    public final void doBlockStart(AbstractBlock<?> block) {
-        if (printIRWithLIR) {
-            TTY.print(block.toString());
-        }
-
-        currentBlock = block;
-
-        // set up the list of LIR instructions
-        assert res.getLIR().getLIRforBlock(block) == null : "LIR list already computed for this block";
-        res.getLIR().setLIRforBlock(block, new ArrayList<LIRInstruction>());
-
-        append(new LabelOp(new Label(block.getId()), block.isAligned()));
-
-        if (traceLevel >= 1) {
-            TTY.println("BEGIN Generating LIR for block B" + block.getId());
-        }
-    }
-
-    public final void doBlockEnd(AbstractBlock<?> block) {
-
-        if (traceLevel >= 1) {
-            TTY.println("END Generating LIR for block B" + block.getId());
-        }
-
-        currentBlock = null;
-
-        if (printIRWithLIR) {
-            TTY.println();
-        }
-    }
-
-    public void emitIncomingValues(Value[] params) {
-        ((LabelOp) res.getLIR().getLIRforBlock(currentBlock).get(0)).setIncomingValues(params);
-    }
-
-    public abstract void emitJump(LabelRef label);
-
-    public abstract void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
-                    double trueDestinationProbability);
-
-    public abstract void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability);
-
-    public abstract void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
-
-    public abstract Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
-
-    public abstract Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
-
-    protected abstract void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info);
-
-    public static AllocatableValue toStackKind(AllocatableValue value) {
-        if (value.getKind().getStackKind() != value.getKind()) {
-            // We only have stack-kinds in the LIR, so convert the operand kind for values from the
-            // calling convention.
-            if (isRegister(value)) {
-                return asRegister(value).asValue(value.getKind().getStackKind());
-            } else if (isStackSlot(value)) {
-                return StackSlot.get(value.getKind().getStackKind(), asStackSlot(value).getRawOffset(), asStackSlot(value).getRawAddFrameSize());
-            } else {
-                throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-        return value;
-    }
-
-    @Override
-    public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
-        LIRFrameState state = null;
-        if (linkage.canDeoptimize()) {
-            if (info != null) {
-                state = stateFor(getFrameState(info));
-            } else {
-                assert needOnlyOopMaps();
-                state = new LIRFrameState(null, null, null);
-            }
-        }
-
-        // move the arguments into the correct location
-        CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
-        res.getFrameMap().callsMethod(linkageCc);
-        assert linkageCc.getArgumentCount() == args.length : "argument count mismatch";
-        Value[] argLocations = new Value[args.length];
-        for (int i = 0; i < args.length; i++) {
-            Value arg = args[i];
-            AllocatableValue loc = linkageCc.getArgument(i);
-            emitMove(loc, arg);
-            argLocations[i] = loc;
-        }
-        res.setForeignCall(true);
-        emitForeignCall(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state);
-
-        if (isLegal(linkageCc.getReturn())) {
-            return emitMove(linkageCc.getReturn());
-        } else {
-            return null;
-        }
-    }
-
-    protected void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
-        int keyCount = keyConstants.length;
-        SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets);
-        long valueRange = keyConstants[keyCount - 1].asLong() - keyConstants[0].asLong() + 1;
-        double tableSwitchDensity = keyCount / (double) valueRange;
-        /*
-         * This heuristic tries to find a compromise between the effort for the best switch strategy
-         * and the density of a tableswitch. If the effort for the strategy is at least 4, then a
-         * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers
-         * gradually with additional effort.
-         */
-        if (strategy.getAverageEffort() < 4 || tableSwitchDensity < (1 / Math.sqrt(strategy.getAverageEffort()))) {
-            emitStrategySwitch(strategy, value, keyTargets, defaultTarget);
-        } else {
-            int minValue = keyConstants[0].asInt();
-            assert valueRange < Integer.MAX_VALUE;
-            LabelRef[] targets = new LabelRef[(int) valueRange];
-            for (int i = 0; i < valueRange; i++) {
-                targets[i] = defaultTarget;
-            }
-            for (int i = 0; i < keyCount; i++) {
-                targets[keyConstants[i].asInt() - minValue] = keyTargets[i];
-            }
-            emitTableSwitch(minValue, defaultTarget, targets, value);
-        }
-    }
-
-    protected abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
-
-    protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key);
-
-    public CallingConvention getCallingConvention() {
-        return cc;
-    }
-
-    public DebugInfoBuilder getDebugInfoBuilder() {
-        assert debugInfoBuilder != null;
-        return debugInfoBuilder;
-    }
-
-    @Override
-    public void beforeRegisterAllocation() {
-        insertConstantLoads();
-    }
-
-    /**
-     * Moves deferred {@linkplain LoadConstant loads} of constants into blocks dominating all usages
-     * of the constant. Any operations inserted into a block are guaranteed to be immediately prior
-     * to the first control flow instruction near the end of the block.
-     */
-    private void insertConstantLoads() {
-        if (constantLoads != null) {
-            // Remove loads where all usages are in the same block.
-            for (Iterator<Map.Entry<Constant, LoadConstant>> iter = constantLoads.entrySet().iterator(); iter.hasNext();) {
-                LoadConstant lc = iter.next().getValue();
-
-                // Move loads of constant outside of loops
-                if (OptScheduleOutOfLoops.getValue()) {
-                    AbstractBlock<?> outOfLoopDominator = lc.block;
-                    while (outOfLoopDominator.getLoop() != null) {
-                        outOfLoopDominator = outOfLoopDominator.getDominator();
-                    }
-                    if (outOfLoopDominator != lc.block) {
-                        lc.unpin(res.getLIR());
-                        lc.block = outOfLoopDominator;
-                    }
-                }
-
-                if (lc.index != -1) {
-                    assert res.getLIR().getLIRforBlock(lc.block).get(lc.index) == lc.op;
-                    iter.remove();
-                }
-            }
-            if (constantLoads.isEmpty()) {
-                return;
-            }
-
-            // Sorting groups the loads per block.
-            LoadConstant[] groupedByBlock = constantLoads.values().toArray(new LoadConstant[constantLoads.size()]);
-            Arrays.sort(groupedByBlock);
-
-            int groupBegin = 0;
-            while (true) {
-                int groupEnd = groupBegin + 1;
-                AbstractBlock<?> block = groupedByBlock[groupBegin].block;
-                while (groupEnd < groupedByBlock.length && groupedByBlock[groupEnd].block == block) {
-                    groupEnd++;
-                }
-                int groupSize = groupEnd - groupBegin;
-
-                List<LIRInstruction> ops = res.getLIR().getLIRforBlock(block);
-                int lastIndex = ops.size() - 1;
-                assert ops.get(lastIndex) instanceof BlockEndOp;
-                int insertionIndex = lastIndex;
-                for (int i = Math.max(0, lastIndex - MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END); i < lastIndex; i++) {
-                    if (getExceptionEdge(ops.get(i)) != null) {
-                        insertionIndex = i;
-                        break;
-                    }
-                }
-
-                if (groupSize == 1) {
-                    ops.add(insertionIndex, groupedByBlock[groupBegin].op);
-                } else {
-                    assert groupSize > 1;
-                    List<LIRInstruction> moves = new ArrayList<>(groupSize);
-                    for (int i = groupBegin; i < groupEnd; i++) {
-                        moves.add(groupedByBlock[i].op);
-                    }
-                    ops.addAll(insertionIndex, moves);
-                }
-
-                if (groupEnd == groupedByBlock.length) {
-                    break;
-                }
-                groupBegin = groupEnd;
-            }
-            constantLoads = null;
-        }
-    }
-
-    /**
-     * Gets a garbage value for a given kind.
-     */
-    protected Constant zapValueForKind(PlatformKind kind) {
-        long dead = 0xDEADDEADDEADDEADL;
-        switch ((Kind) kind) {
-            case Boolean:
-                return Constant.FALSE;
-            case Byte:
-                return Constant.forByte((byte) dead);
-            case Char:
-                return Constant.forChar((char) dead);
-            case Short:
-                return Constant.forShort((short) dead);
-            case Int:
-                return Constant.forInt((int) dead);
-            case Double:
-                return Constant.forDouble(Double.longBitsToDouble(dead));
-            case Float:
-                return Constant.forFloat(Float.intBitsToFloat((int) dead));
-            case Long:
-                return Constant.forLong(dead);
-            case Object:
-                return Constant.NULL_OBJECT;
-            default:
-                throw new IllegalArgumentException(kind.toString());
-        }
-    }
-
-    /**
-     * Default implementation: Return the Java stack kind for each stamp.
-     */
-    public PlatformKind getPlatformKind(Stamp stamp) {
-        return stamp.getPlatformKind(this);
-    }
-
-    public PlatformKind getIntegerKind(int bits) {
-        if (bits <= 8) {
-            return Kind.Byte;
-        } else if (bits <= 16) {
-            return Kind.Short;
-        } else if (bits <= 32) {
-            return Kind.Int;
-        } else {
-            assert bits <= 64;
-            return Kind.Long;
-        }
-    }
-
-    public PlatformKind getFloatingKind(int bits) {
-        switch (bits) {
-            case 32:
-                return Kind.Float;
-            case 64:
-                return Kind.Double;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public PlatformKind getObjectKind() {
-        return Kind.Object;
-    }
-
-    public abstract void emitBitCount(Variable result, Value operand);
-
-    public abstract void emitBitScanForward(Variable result, Value operand);
-
-    public abstract void emitBitScanReverse(Variable result, Value operand);
-
-    public abstract void emitByteSwap(Variable result, Value operand);
-
-    public abstract void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
-
-    public AbstractBlock<?> getCurrentBlock() {
-        return currentBlock;
-    }
-
-    void setCurrentBlock(AbstractBlock<?> block) {
-        currentBlock = block;
-    }
-
-    public LIRGenerationResult getResult() {
-        return res;
-    }
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.gen;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.lir.LIR.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
 
@@ -35,13 +36,15 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.LIRGenerator.LoadConstant;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGenerator.LoadConstant;
+import com.oracle.graal.lir.gen.LIRGenerator.Options;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
@@ -57,16 +60,18 @@
     private final NodeMap<Value> nodeOperands;
     private final DebugInfoBuilder debugInfoBuilder;
 
-    protected final LIRGenerator gen;
+    protected final LIRGeneratorTool gen;
 
     private ValueNode currentInstruction;
     private ValueNode lastInstructionPrinted; // Debugging only
 
-    public NodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) {
+    private Map<Class<? extends ValueNode>, List<MatchStatement>> matchRules;
+
+    public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         this.gen = gen;
         this.nodeOperands = graph.createNodeMap();
         this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands);
-        gen.setDebugInfoBuilder(debugInfoBuilder);
+        matchRules = MatchRuleRegistry.lookup(getClass());
     }
 
     @SuppressWarnings("hiding")
@@ -112,25 +117,25 @@
                     return setResult(node, value);
                 } else {
                     Variable loadedValue;
-                    if (gen.constantLoads == null) {
-                        gen.constantLoads = new HashMap<>();
+                    if (gen.getConstantLoads() == null) {
+                        gen.setConstantLoads(new HashMap<>());
                     }
-                    LoadConstant load = gen.constantLoads.get(value);
+                    LoadConstant load = gen.getConstantLoads().get(value);
                     assert gen.getCurrentBlock() instanceof Block;
                     if (load == null) {
                         int index = gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).size();
                         loadedValue = gen.emitMove(value);
                         LIRInstruction op = gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).get(index);
-                        gen.constantLoads.put(value, new LoadConstant(loadedValue, gen.getCurrentBlock(), index, op));
+                        gen.getConstantLoads().put(value, new LoadConstant(loadedValue, gen.getCurrentBlock(), index, op));
                     } else {
-                        AbstractBlock<?> dominator = ControlFlowGraph.commonDominator((Block) load.block, (Block) gen.getCurrentBlock());
-                        loadedValue = load.variable;
-                        if (dominator != load.block) {
+                        AbstractBlock<?> dominator = ControlFlowGraph.commonDominator((Block) load.getBlock(), (Block) gen.getCurrentBlock());
+                        loadedValue = load.getVariable();
+                        if (dominator != load.getBlock()) {
                             load.unpin(gen.getResult().getLIR());
                         } else {
-                            assert load.block != gen.getCurrentBlock() || load.index < gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).size();
+                            assert load.getBlock() != gen.getCurrentBlock() || load.getIndex() < gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).size();
                         }
-                        load.block = dominator;
+                        load.setBlock(dominator);
                     }
                     return loadedValue;
                 }
@@ -153,13 +158,25 @@
     @Override
     public Value setResult(ValueNode x, Value operand) {
         assert (!isRegister(operand) || !gen.attributes(asRegister(operand)).isAllocatable());
-        assert nodeOperands == null || nodeOperands.get(x) == null : "operand cannot be set twice";
+        assert nodeOperands != null && (nodeOperands.get(x) == null || nodeOperands.get(x) instanceof ComplexMatchValue) : "operand cannot be set twice";
         assert operand != null && isLegal(operand) : "operand must be legal";
         assert !(x instanceof VirtualObjectNode);
         nodeOperands.set(x, operand);
         return operand;
     }
 
+    /**
+     * Used by the {@link MatchStatement} machinery to override the generation LIR for some
+     * ValueNodes.
+     */
+    public void setMatchResult(ValueNode x, Value operand) {
+        assert operand.equals(Value.INTERIOR_MATCH) || operand instanceof ComplexMatchValue;
+        assert operand instanceof ComplexMatchValue || x.usages().count() == 1 : "interior matches must be single user";
+        assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice";
+        assert !(x instanceof VirtualObjectNode);
+        nodeOperands.set(x, operand);
+    }
+
     public LabelRef getLIRBlock(FixedNode b) {
         assert gen.getResult().getLIR().getControlFlowGraph() instanceof ControlFlowGraph;
         Block result = ((ControlFlowGraph) gen.getResult().getLIR().getControlFlowGraph()).blockFor(b);
@@ -171,7 +188,7 @@
     }
 
     public final void append(LIRInstruction op) {
-        if (gen.printIRWithLIR && !TTY.isSuppressed()) {
+        if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) {
             if (currentInstruction != null && lastInstructionPrinted != currentInstruction) {
                 lastInstructionPrinted = currentInstruction;
                 InstructionPrinter ip = new InstructionPrinter(TTY.out());
@@ -192,34 +209,44 @@
         }
 
         List<ScheduledNode> nodes = blockMap.get(block);
-        int instructionsFolded = 0;
+
+        if (MatchExpressions.getValue()) {
+            // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups
+            // of instructions
+            matchComplexExpressions(nodes);
+        }
+
         for (int i = 0; i < nodes.size(); i++) {
             Node instr = nodes.get(i);
-            if (gen.traceLevel >= 3) {
+            if (Options.TraceLIRGeneratorLevel.getValue() >= 3) {
                 TTY.println("LIRGen for " + instr);
             }
-            if (instructionsFolded > 0) {
-                instructionsFolded--;
-                continue;
-            }
             if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) {
                 // Loading of constants is done lazily by operand()
 
             } else if (instr instanceof ValueNode) {
                 ValueNode valueNode = (ValueNode) instr;
-                if (!hasOperand(valueNode)) {
+                Value operand = getOperand(valueNode);
+                if (operand == null) {
                     if (!peephole(valueNode)) {
-                        instructionsFolded = maybeFoldMemory(nodes, i, valueNode);
-                        if (instructionsFolded == 0) {
-                            try {
-                                doRoot((ValueNode) instr);
-                            } catch (GraalInternalError e) {
-                                throw GraalGraphInternalError.transformAndAddContext(e, instr);
-                            } catch (Throwable e) {
-                                throw new GraalGraphInternalError(e).addContext(instr);
-                            }
+                        try {
+                            doRoot((ValueNode) instr);
+                        } catch (GraalInternalError e) {
+                            throw GraalGraphInternalError.transformAndAddContext(e, instr);
+                        } catch (Throwable e) {
+                            throw new GraalGraphInternalError(e).addContext(instr);
                         }
                     }
+                } else if (Value.INTERIOR_MATCH.equals(operand)) {
+                    // Doesn't need to be evaluated
+                    Debug.log("interior match for %s", valueNode);
+                } else if (operand instanceof ComplexMatchValue) {
+                    Debug.log("complex match for %s", valueNode);
+                    ComplexMatchValue match = (ComplexMatchValue) operand;
+                    operand = match.evaluate(this);
+                    if (operand != null) {
+                        setResult(valueNode, operand);
+                    }
                 } else {
                     // There can be cases in which the result of an instruction is already set
                     // before by other instructions.
@@ -244,156 +271,35 @@
         gen.doBlockEnd(block);
     }
 
-    private static final DebugMetric MemoryFoldSuccess = Debug.metric("MemoryFoldSuccess");
-    private static final DebugMetric MemoryFoldFailed = Debug.metric("MemoryFoldFailed");
-    private static final DebugMetric MemoryFoldFailedNonAdjacent = Debug.metric("MemoryFoldedFailedNonAdjacent");
-    private static final DebugMetric MemoryFoldFailedDifferentBlock = Debug.metric("MemoryFoldedFailedDifferentBlock");
-
-    /**
-     * Subclass can provide helper to fold memory operations into other operations.
-     */
-    public MemoryArithmeticLIRLowerer getMemoryLowerer() {
-        return null;
-    }
-
-    private static final Object LOG_OUTPUT_LOCK = new Object();
-
-    /**
-     * Try to find a sequence of Nodes which can be passed to the backend to look for optimized
-     * instruction sequences using memory. Currently this basically is a read with a single
-     * arithmetic user followed by an possible if use. This should generalized to more generic
-     * pattern matching so that it can be more flexibly used.
-     */
-    private int maybeFoldMemory(List<ScheduledNode> nodes, int i, ValueNode access) {
-        MemoryArithmeticLIRLowerer lowerer = getMemoryLowerer();
-        if (lowerer != null && GraalOptions.OptFoldMemory.getValue() && (access instanceof ReadNode || access instanceof FloatingReadNode) && access.usages().count() == 1 && i + 1 < nodes.size()) {
-            try (Scope s = Debug.scope("MaybeFoldMemory", access)) {
-                // This is all bit hacky since it's happening on the linearized schedule. This needs
-                // to be revisited at some point.
-
-                // Uncast the memory operation.
-                Node use = access.usages().first();
-                if (use instanceof UnsafeCastNode && use.usages().count() == 1) {
-                    use = use.usages().first();
-                }
-
-                // Find a memory lowerable usage of this operation
-                if (use instanceof MemoryArithmeticLIRLowerable) {
-                    ValueNode operation = (ValueNode) use;
-                    if (!nodes.contains(operation)) {
-                        Debug.log("node %1s in different block from %1s", access, operation);
-                        MemoryFoldFailedDifferentBlock.increment();
-                        return 0;
+    protected void matchComplexExpressions(List<ScheduledNode> nodes) {
+        if (matchRules != null) {
+            try (Scope s = Debug.scope("MatchComplexExpressions")) {
+                // Match the nodes in backwards order to encourage longer matches.
+                for (int index = nodes.size() - 1; index >= 0; index--) {
+                    ScheduledNode snode = nodes.get(index);
+                    if (!(snode instanceof ValueNode)) {
+                        continue;
                     }
-                    ValueNode firstOperation = operation;
-                    if (operation instanceof LogicNode) {
-                        if (operation.usages().count() == 1 && operation.usages().first() instanceof IfNode) {
-                            ValueNode ifNode = (ValueNode) operation.usages().first();
-                            if (!nodes.contains(ifNode)) {
-                                MemoryFoldFailedDifferentBlock.increment();
-                                Debug.log("if node %1s in different block from %1s", ifNode, operation);
-                                try (Indent indent = Debug.logAndIndent("checking operations")) {
-                                    int start = nodes.indexOf(access);
-                                    int end = nodes.indexOf(operation);
-                                    for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) {
-                                        Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1));
-                                    }
-                                }
-                                return 0;
-                            } else {
-                                operation = ifNode;
-                            }
-                        }
-                    }
-                    if (Debug.isLogEnabled()) {
-                        synchronized (LOG_OUTPUT_LOCK) {  // Hack to ensure the output is grouped.
-                            try (Indent indent = Debug.logAndIndent("checking operations")) {
-                                int start = nodes.indexOf(access);
-                                int end = nodes.indexOf(operation);
-                                for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) {
-                                    Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1));
-                                }
+                    ValueNode node = (ValueNode) snode;
+                    // See if this node is the root of any MatchStatements
+                    List<MatchStatement> statements = matchRules.get(node.getClass());
+                    if (statements != null) {
+                        for (MatchStatement statement : statements) {
+                            if (statement.generate(this, node, nodes)) {
+                                // Found a match so skip to the next
+                                break;
                             }
                         }
                     }
-                    // Possible lowerable operation in the same block. Check out the dependencies.
-                    int opIndex = nodes.indexOf(operation);
-                    int current = i + 1;
-                    ArrayList<ValueNode> deferred = null;
-                    for (; current < opIndex; current++) {
-                        ScheduledNode node = nodes.get(current);
-                        if (node != firstOperation) {
-                            if (node instanceof LocationNode || node instanceof VirtualObjectNode) {
-                                // nothing to do
-                                continue;
-                            } else if (node instanceof ConstantNode) {
-                                if (deferred == null) {
-                                    deferred = new ArrayList<>(2);
-                                }
-                                // These nodes are collected and the backend is expended to
-                                // evaluate them before generating the lowered form. This
-                                // basically works around unfriendly scheduling of values which
-                                // are defined in a block but not used there.
-                                deferred.add((ValueNode) node);
-                                continue;
-                            } else if (node instanceof UnsafeCastNode) {
-                                UnsafeCastNode cast = (UnsafeCastNode) node;
-                                if (cast.getOriginalNode() == access) {
-                                    continue;
-                                }
-                            }
-
-                            // Unexpected inline node
-                            // Debug.log("unexpected node %1s", node);
-                            break;
-                        }
-                    }
-
-                    if (current == opIndex) {
-                        if (lowerer.memoryPeephole((Access) access, (MemoryArithmeticLIRLowerable) operation, deferred)) {
-                            MemoryFoldSuccess.increment();
-                            // if this operation had multiple access inputs, then previous attempts
-                            // would be marked as failures which is wrong. Try to adjust the
-                            // counters to account for this.
-                            for (Node input : operation.inputs()) {
-                                if (input == access) {
-                                    continue;
-                                }
-                                if (input instanceof Access && nodes.contains(input)) {
-                                    MemoryFoldFailedNonAdjacent.add(-1);
-                                }
-                            }
-                            if (deferred != null) {
-                                // Ensure deferred nodes were evaluated
-                                for (ValueNode node : deferred) {
-                                    assert hasOperand(node);
-                                }
-                            }
-                            return opIndex - i;
-                        } else {
-                            // This isn't true failure, it just means there wasn't match for the
-                            // pattern. Usually that means it's just not supported by the backend.
-                            MemoryFoldFailed.increment();
-                            return 0;
-                        }
-                    } else {
-                        MemoryFoldFailedNonAdjacent.increment();
-                    }
-                } else if (!(use instanceof Access) && !(use instanceof PhiNode) && use.usages().count() == 1) {
-                    // memory usage which isn't considered lowerable. Mostly these are
-                    // uninteresting but it might be worth looking at to ensure that interesting
-                    // nodes are being properly handled.
-                    // Debug.log("usage isn't lowerable %1s", access.usages().first());
                 }
             }
         }
-        return 0;
     }
 
     protected abstract boolean peephole(ValueNode valueNode);
 
     private void doRoot(ValueNode instr) {
-        if (gen.traceLevel >= 2) {
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 2) {
             TTY.println("Emitting LIR for instruction " + instr);
         }
         currentInstruction = instr;
@@ -407,11 +313,7 @@
         if (Debug.isLogEnabled() && node.stamp() instanceof IllegalStamp) {
             Debug.log("This node has invalid type, we are emitting dead code(?): %s", node);
         }
-        if (node instanceof LIRGenLowerable) {
-            ((LIRGenLowerable) node).generate(this);
-        } else if (node instanceof LIRGenResLowerable) {
-            ((LIRGenResLowerable) node).generate(this, gen.getResult());
-        } else if (node instanceof LIRLowerable) {
+        if (node instanceof LIRLowerable) {
             ((LIRLowerable) node).generate(this);
         } else if (node instanceof ArithmeticLIRLowerable) {
             ((ArithmeticLIRLowerable) node).generate(this, gen);
@@ -460,7 +362,7 @@
     }
 
     private void moveToPhi(MergeNode merge, AbstractEndNode pred) {
-        if (gen.traceLevel >= 1) {
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
             TTY.println("MOVE TO PHI from " + pred + " to " + merge);
         }
         PhiResolver resolver = new PhiResolver(gen);
@@ -568,7 +470,7 @@
         if (x instanceof InvokeWithExceptionNode) {
             exceptionEdge = getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge());
         }
-        LIRFrameState callState = gen.stateWithExceptionEdge(x, exceptionEdge);
+        LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge);
 
         Value result = invokeCc.getReturn();
         if (callTarget instanceof DirectCallTargetNode) {
@@ -661,6 +563,45 @@
         return debugInfoBuilder;
     }
 
+    private static FrameState getFrameState(DeoptimizingNode deopt) {
+        if (deopt instanceof DeoptimizingNode.DeoptBefore) {
+            assert !(deopt instanceof DeoptimizingNode.DeoptDuring || deopt instanceof DeoptimizingNode.DeoptAfter);
+            return ((DeoptimizingNode.DeoptBefore) deopt).stateBefore();
+        } else if (deopt instanceof DeoptimizingNode.DeoptDuring) {
+            assert !(deopt instanceof DeoptimizingNode.DeoptAfter);
+            return ((DeoptimizingNode.DeoptDuring) deopt).stateDuring();
+        } else {
+            assert deopt instanceof DeoptimizingNode.DeoptAfter;
+            return ((DeoptimizingNode.DeoptAfter) deopt).stateAfter();
+        }
+    }
+
+    public LIRFrameState state(DeoptimizingNode deopt) {
+        if (!deopt.canDeoptimize()) {
+            return null;
+        }
+        return stateFor(getFrameState(deopt));
+    }
+
+    public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) {
+        if (!deopt.canDeoptimize()) {
+            return null;
+        }
+        return stateForWithExceptionEdge(getFrameState(deopt), exceptionEdge);
+    }
+
+    public LIRFrameState stateFor(FrameState state) {
+        return stateForWithExceptionEdge(state, null);
+    }
+
+    public LIRFrameState stateForWithExceptionEdge(FrameState state, LabelRef exceptionEdge) {
+        if (gen.needOnlyOopMaps()) {
+            return new LIRFrameState(null, null, null);
+        }
+        assert state != null;
+        return getDebugInfoBuilder().build(state, exceptionEdge);
+    }
+
     public void emitOverflowCheckBranch(BeginNode overflowSuccessor, BeginNode next, double probability) {
         gen.emitOverflowCheckBranch(getLIRBlock(overflowSuccessor), getLIRBlock(next), probability);
     }
@@ -686,11 +627,7 @@
     }
 
     @Override
-    public LIRGenerator getLIRGeneratorTool() {
-        return gen;
-    }
-
-    public LIRGenerator getLIRGenerator() {
+    public LIRGeneratorTool getLIRGeneratorTool() {
         return gen;
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Tue Apr 29 12:43:27 2014 -0700
@@ -29,22 +29,23 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * Converts {@link ValuePhiNode} instructions into moves.
- * 
+ *
  * Resolves cycles:
- * 
+ *
  * <pre>
- * 
+ *
  *  r1 := r2  becomes  temp := r1
  *  r2 := r1           r1 := r2
  *                     r2 := temp
  * </pre>
- * 
+ *
  * and orders moves:
- * 
+ *
  * <pre>
  *  r2 := r3  becomes  r1 := r2
  *  r1 := r2           r2 := r3
@@ -103,7 +104,7 @@
         }
     }
 
-    private final LIRGenerator gen;
+    private final LIRGeneratorTool gen;
 
     /**
      * The operand loop header phi for the operand currently being process in {@link #dispose()}.
@@ -120,7 +121,7 @@
      */
     private final HashMap<Value, PhiResolverNode> operandToNodeMap = new HashMap<>();
 
-    public PhiResolver(LIRGenerator gen) {
+    public PhiResolver(LIRGeneratorTool gen) {
         this.gen = gen;
         temp = ILLEGAL;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+
+/*
+ * A closure that can be evaluated to produce the LIR for some complex match. Using a closure
+ * allows normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes
+ * evaluated at the proper time.
+ */
+public interface ComplexMatchResult {
+    Value evaluate(NodeLIRBuilder gen);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+
+/**
+ * A wrapper value for the lazy evaluation of a complex match. There's an intermediate class for the
+ * closure because Value is serializable which is a hassle for the little inner classes which
+ * usually occur here.
+ */
+public class ComplexMatchValue extends Value {
+    /**
+     *
+     */
+    private static final long serialVersionUID = -4734670273590368770L;
+
+    final ComplexMatchResult result;
+
+    public ComplexMatchValue(ComplexMatchResult result) {
+        super(Kind.Illegal);
+        this.result = result;
+    }
+
+    public Value evaluate(NodeLIRBuilder builder) {
+        return result.evaluate(builder);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * Helper class to describe the matchable nodes in the core Graal IR. These could possibly live in
+ * their respective classes but for simplicity in the {@link MatchProcessor} they are grouped here.
+ */
+@MatchableNode(shortName = "Constant", value = ConstantNode.class, inputs = 0)
+@MatchableNode(shortName = "FloatConvert", value = FloatConvertNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(shortName = "FloatSub", value = FloatSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(shortName = "FloatingRead", value = FloatingReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class)
+@MatchableNode(shortName = "If", value = IfNode.class, inputs = 1, adapter = GraalMatchableNodes.IfNodeAdapter.class)
+@MatchableNode(shortName = "IntegerSub", value = IntegerSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(shortName = "LeftShift", value = LeftShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(shortName = "Narrow", value = NarrowNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(shortName = "Read", value = ReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class)
+@MatchableNode(shortName = "Reinterpret", value = ReinterpretNode.class, inputs = 1, adapter = GraalMatchableNodes.ReinterpretNodeAdapter.class)
+@MatchableNode(shortName = "SignExtend", value = SignExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(shortName = "UnsignedRightShift", value = UnsignedRightShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(shortName = "Write", value = WriteNode.class, inputs = 2, adapter = GraalMatchableNodes.WriteNodeAdapter.class)
+@MatchableNode(shortName = "ZeroExtend", value = ZeroExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(shortName = "And", value = AndNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "FloatAdd", value = FloatAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "FloatEquals", value = FloatEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "FloatLessThan", value = FloatLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "FloatMul", value = FloatMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerAdd", value = IntegerAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerBelowThan", value = IntegerBelowThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerEquals", value = IntegerEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerLessThan", value = IntegerLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerMul", value = IntegerMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerTest", value = IntegerTestNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "ObjectEquals", value = ObjectEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "Or", value = OrNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "Xor", value = XorNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+public class GraalMatchableNodes {
+    public static class BinaryNodeAdapter extends MatchNodeAdapter {
+        @Override
+        protected ValueNode getFirstInput(ValueNode node) {
+            return ((BinaryNode) node).x();
+        }
+
+        @Override
+        protected ValueNode getSecondInput(ValueNode node) {
+            return ((BinaryNode) node).y();
+        }
+    }
+
+    public static class WriteNodeAdapter extends MatchNodeAdapter {
+
+        @Override
+        protected ValueNode getFirstInput(ValueNode node) {
+            return ((WriteNode) node).object();
+        }
+
+        @Override
+        protected ValueNode getSecondInput(ValueNode node) {
+            return ((WriteNode) node).value();
+        }
+    }
+
+    public static class ConvertNodeAdapter extends MatchNodeAdapter {
+
+        @Override
+        protected ValueNode getFirstInput(ValueNode node) {
+            return ((ConvertNode) node).getInput();
+        }
+    }
+
+    public static class ReinterpretNodeAdapter extends MatchNodeAdapter {
+
+        @Override
+        protected ValueNode getFirstInput(ValueNode node) {
+            return ((ReinterpretNode) node).value();
+        }
+    }
+
+    public static class IfNodeAdapter extends MatchNodeAdapter {
+
+        @Override
+        protected ValueNode getFirstInput(ValueNode node) {
+            return ((IfNode) node).condition();
+        }
+    }
+
+    public static class ReadNodeAdapter extends MatchNodeAdapter {
+
+        @Override
+        protected ValueNode getFirstInput(ValueNode node) {
+            return ((Access) node).object();
+        }
+    }
+
+    public static class BinaryOpLogicNodeAdapter extends MatchNodeAdapter {
+
+        @Override
+        protected ValueNode getFirstInput(ValueNode node) {
+            return ((BinaryOpLogicNode) node).x();
+        }
+
+        @Override
+        protected ValueNode getSecondInput(ValueNode node) {
+            return ((BinaryOpLogicNode) node).y();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.MatchPattern.Result;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.virtual.*;
+
+/**
+ * Container for state captured during a match.
+ */
+public class MatchContext {
+    private final ArrayList<ValueNode> consumed = new ArrayList<>();
+    private final List<ScheduledNode> nodes;
+    private final ValueNode root;
+    private List<String> names;
+    private List<Class<? extends ValueNode>> types;
+    private List<ValueNode> values;
+    private final MatchStatement rule;
+    private int startIndex;
+    private int endIndex;
+    private final NodeLIRBuilder builder;
+
+    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, ValueNode node, List<ScheduledNode> nodes) {
+        this.builder = builder;
+        this.rule = rule;
+        this.root = node;
+        this.nodes = nodes;
+        // The root should be the last index since all the inputs must be scheduled before.
+        startIndex = endIndex = nodes.indexOf(node);
+    }
+
+    public ValueNode getRoot() {
+        return root;
+    }
+
+    public Result captureNamedValue(String name, Class<? extends ValueNode> type, ValueNode value) {
+        if (names == null) {
+            names = new ArrayList<>(2);
+            values = new ArrayList<>(2);
+            types = new ArrayList<>(2);
+        }
+        int index = names.indexOf(name);
+        if (index == -1) {
+            names.add(name);
+            values.add(value);
+            types.add(type);
+            return Result.OK;
+        } else {
+            if (values.get(index) != value) {
+                return Result.NAMED_VALUE_MISMATCH(value, rule.getPattern());
+            }
+            return Result.OK;
+        }
+    }
+
+    public Result validate() {
+        // Ensure that there's no unsafe work in between these operations.
+        for (int i = startIndex; i <= endIndex; i++) {
+            ScheduledNode node = getNodes().get(i);
+            if (node instanceof ConstantNode || node instanceof LocationNode || node instanceof VirtualObjectNode || node instanceof ParameterNode) {
+                // these can be evaluated lazily so don't worry about them. This should probably be
+                // captured by some interface that indicates that their generate method is empty.
+                continue;
+            } else if (!consumed.contains(node) && node != root) {
+                // This is too verbose for normal logging.
+                // Debug.log("unexpected node %s", node);
+                // for (int j = startIndex; j <= endIndex; j++) {
+                // ScheduledNode theNode = getNodes().get(j);
+                // Debug.log("%s(%s) %1s", (consumed.contains(theNode) || theNode == root) ? "*" :
+                // " ",
+                // theNode.usages().count(), theNode);
+                // }
+                return Result.NOT_SAFE(node, rule.getPattern());
+            }
+        }
+        return Result.OK;
+    }
+
+    /**
+     * Transfers the captured value into the MatchGenerator instance. The reflective information
+     * should really be generated and checking during construction of the MatchStatement but this is
+     * ok for now.
+     */
+    public void transferState(MatchGenerator generator) {
+        try {
+            for (int i = 0; i < names.size(); i++) {
+                String name = names.get(i);
+                try {
+                    Field field = generator.getClass().getDeclaredField(name);
+                    field.setAccessible(true);
+                    field.set(generator, values.get(i));
+                } catch (NoSuchFieldException e) {
+                    // Doesn't exist so the generator doesn't care about the value.
+                }
+            }
+        } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
+            throw new GraalInternalError(e);
+        }
+        try {
+            Field field = generator.getClass().getDeclaredField("root");
+            field.setAccessible(true);
+            field.set(generator, getRoot());
+        } catch (NoSuchFieldException e) {
+            // Doesn't exist
+        } catch (SecurityException | IllegalAccessException | IllegalArgumentException e) {
+            throw new GraalInternalError(e);
+        }
+    }
+
+    public void setResult(ComplexMatchResult result) {
+        setResult(new ComplexMatchValue(result));
+    }
+
+    /**
+     * Mark the interior nodes with INTERIOR_MATCH and set the Value of the root to be the result.
+     * During final LIR generation it will be evaluated to produce the actual LIR value.
+     *
+     * @param result
+     */
+    public void setResult(ComplexMatchValue result) {
+        Debug.log("matched %s %s", rule.getName(), rule.getPattern());
+        // Debug.log("%s", rule.formatMatch(root));
+        for (ValueNode node : consumed) {
+            // All the interior nodes should be skipped during the normal doRoot calls in
+            // NodeLIRBuilder so mark them as interior matches. The root of the match will get a
+            // closure which will be evaluated to produce the final LIR.
+            getBuilder().setMatchResult(node, Value.INTERIOR_MATCH);
+        }
+        getBuilder().setMatchResult(root, result);
+    }
+
+    /**
+     * Mark a node as consumed by the match. Consumed nodes will never be evaluated.
+     *
+     * @return Result.OK if the node can be safely consumed.
+     */
+    public Result consume(ValueNode node) {
+        if (node.usages().count() != 1) {
+            return Result.TOO_MANY_USERS(node, rule.getPattern());
+        }
+
+        if (getBuilder().hasOperand(node)) {
+            return Result.ALREADY_USED(node, rule.getPattern());
+        }
+
+        int index = getNodes().indexOf(node);
+        if (index == -1) {
+            return Result.NOT_IN_BLOCK(node, rule.getPattern());
+        }
+        startIndex = Math.min(startIndex, index);
+        consumed.add(node);
+        return Result.OK;
+    }
+
+    private NodeLIRBuilder getBuilder() {
+        return builder;
+    }
+
+    private List<ScheduledNode> getNodes() {
+        return nodes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.compiler.gen.*;
+
+/**
+ * Code generator for complex match patterns.
+ */
+public interface MatchGenerator {
+    /**
+     * @returns null if the match can't be generated or a {@link ComplexMatchResult} that can be
+     *          evaluated during LIR generation to produce the final LIR value.
+     */
+    ComplexMatchResult match(NodeLIRBuilder gen);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchNodeAdapter.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * Helper class to visit the matchable inputs of a node in a specified order. This may not be needed
+ * in the end since this could probably be done using the inputs iterator but it simplifies things
+ * for the moment.
+ */
+public class MatchNodeAdapter {
+    @SuppressWarnings("unused")
+    protected ValueNode getFirstInput(ValueNode node) {
+        throw new InternalError();
+    }
+
+    @SuppressWarnings("unused")
+    protected ValueNode getSecondInput(ValueNode node) {
+        throw new InternalError();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.nodes.*;
+
+/**
+ * A simple recursive pattern matcher for a DAG of nodes.
+ */
+
+public class MatchPattern {
+
+    enum MatchResultCode {
+        OK,
+        WRONG_CLASS,
+        NAMED_VALUE_MISMATCH,
+        TOO_MANY_USERS,
+        NOT_IN_BLOCK,
+        NOT_SAFE,
+        ALREADY_USED,
+    }
+
+    /**
+     * A descriptive result for match failures. This can be helpful for debugging why a match
+     * doesn't work as expected.
+     */
+    static class Result {
+        final MatchResultCode code;
+        final ScheduledNode node;
+        final MatchPattern matcher;
+
+        Result(MatchResultCode result, ScheduledNode node, MatchPattern matcher) {
+            this.code = result;
+            this.node = node;
+            this.matcher = matcher;
+        }
+
+        static final Result OK = new Result(MatchResultCode.OK, null, null);
+
+        static Result WRONG_CLASS(ValueNode node, MatchPattern matcher) {
+            return new Result(MatchResultCode.WRONG_CLASS, node, matcher);
+        }
+
+        static Result NAMED_VALUE_MISMATCH(ValueNode node, MatchPattern matcher) {
+            return new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher);
+        }
+
+        static Result TOO_MANY_USERS(ValueNode node, MatchPattern matcher) {
+            return new Result(MatchResultCode.TOO_MANY_USERS, node, matcher);
+        }
+
+        static Result NOT_IN_BLOCK(ScheduledNode node, MatchPattern matcher) {
+            return new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher);
+        }
+
+        static Result NOT_SAFE(ScheduledNode node, MatchPattern matcher) {
+            return new Result(MatchResultCode.NOT_SAFE, node, matcher);
+        }
+
+        static Result ALREADY_USED(ValueNode node, MatchPattern matcher) {
+            return new Result(MatchResultCode.ALREADY_USED, node, matcher);
+        }
+
+        @Override
+        public String toString() {
+            if (code == MatchResultCode.OK) {
+                return "OK";
+            }
+            return code + " " + node.toString(Verbosity.Id) + "|" + node.getClass().getSimpleName() + " " + matcher;
+        }
+    }
+
+    /**
+     * The expected type of the node. It must match exactly.
+     */
+    private final Class<? extends ValueNode> nodeClass;
+    /**
+     * An optional name for this node. A name can occur multiple times in a match and that name must
+     * always refer to the same node of the match will fail.
+     */
+    private final String name;
+    /**
+     * An optional pattern for the first input.
+     */
+    private final MatchPattern first;
+    /**
+     * An optional pattern for the second input.
+     */
+    private final MatchPattern second;
+    /**
+     * Helper class to visit the inputs.
+     */
+    private final MatchNodeAdapter adapter;
+    /**
+     * Can there only be one user of the node. Constant nodes can be matched even if there are other
+     * users.
+     */
+    private final boolean singleUser;
+
+    public MatchPattern(String name, boolean singleUser) {
+        this(null, name, null, null, null, singleUser);
+    }
+
+    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser) {
+        this(nodeClass, name, null, null, null, singleUser);
+    }
+
+    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchNodeAdapter adapter, boolean singleUser) {
+        this(nodeClass, name, first, null, adapter, singleUser);
+    }
+
+    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, MatchNodeAdapter adapter, boolean singleUser) {
+        this.nodeClass = nodeClass;
+        this.name = name;
+        this.singleUser = singleUser;
+        this.first = first;
+        this.second = second;
+        this.adapter = adapter;
+    }
+
+    Class<? extends ValueNode> nodeClass() {
+        return nodeClass;
+    }
+
+    Result match(ValueNode node, MatchContext context) {
+        return matchTree(node, context, true);
+    }
+
+    private Result matchTree(ValueNode node, MatchContext context, boolean atRoot) {
+        Result result = Result.OK;
+        if (nodeClass != null && node.getClass() != nodeClass) {
+            return Result.WRONG_CLASS(node, this);
+        }
+        if (singleUser && !atRoot) {
+            result = context.consume(node);
+            if (result != Result.OK) {
+                return result;
+            }
+        }
+
+        if (name != null) {
+            result = context.captureNamedValue(name, nodeClass, node);
+        }
+
+        if (first != null) {
+            result = first.matchTree(adapter.getFirstInput(node), context, false);
+            if (result == Result.OK && second != null) {
+                result = second.matchTree(adapter.getSecondInput(node), context, false);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * For a node starting at root, produce a String showing the inputs that matched against this
+     * rule. It's assumed that a match has already succeeded against this rule, otherwise the
+     * printing may produce exceptions.
+     */
+    public String formatMatch(ValueNode root) {
+        String result = String.format("%s", root);
+        if (first == null && second == null) {
+            return result;
+        } else {
+            return "(" + result + (first != null ? " " + first.formatMatch(adapter.getFirstInput(root)) : "") + (second != null ? " " + second.formatMatch(adapter.getSecondInput(root)) : "") + ")";
+        }
+    }
+
+    @Override
+    public String toString() {
+        if (nodeClass == null) {
+            return name;
+        } else {
+            String pre = first != null || second != null ? "(" : "";
+            String post = first != null || second != null ? ")" : "";
+            String nodeName = nodeClass.getSimpleName();
+            return pre + nodeName + (name != null ? "=\"" + name + "\"" : "") + (first != null ? (" " + first.toString()) : "") + (second != null ? (" " + second.toString()) : "") + post;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,574 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.*;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
+ * generated for each top level class containing at least one such field. These service objects can
+ * be retrieved as follows:
+ *
+ * <pre>
+ *     ServiceLoader<MatchStatementSet> sl = ServiceLoader.loadInstalled(MatchStatementSet.class);
+ *     for (MatchStatementSet rules : sl) {
+ *         ...
+ *     }
+ * </pre>
+ */
+@SupportedAnnotationTypes({"com.oracle.graal.compiler.match.MatchRule", "com.oracle.graal.compiler.match.MatchRules", "com.oracle.graal.compiler.match.MatchableNode"})
+public class MatchProcessor extends AbstractProcessor {
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    private final Set<Element> processedMatchRule = new HashSet<>();
+    private final Set<Element> processedMatchableNode = new HashSet<>();
+
+    private static class RuleParseError extends RuntimeException {
+        private static final long serialVersionUID = 6456128283609257490L;
+
+        RuleParseError(String message) {
+            super(message);
+        }
+    }
+
+    private class RuleParser {
+        final String[] tokens;
+        int current;
+
+        RuleParser(String rule) {
+            Matcher m = tokenizer.matcher(rule);
+            List<String> list = new ArrayList<>();
+            int end = 0;
+            while (m.lookingAt()) {
+                list.add(m.group(1));
+                end = m.end();
+                m.region(m.end(), m.regionEnd());
+            }
+            if (end != m.regionEnd()) {
+                throw new RuleParseError("unexpected tokens :" + rule.substring(m.end(), m.regionEnd()));
+            }
+            tokens = list.toArray(new String[0]);
+        }
+
+        String next() {
+            return tokens[current++];
+        }
+
+        String peek() {
+            return tokens[current];
+        }
+
+        boolean done() {
+            return current == tokens.length;
+        }
+
+        private MatchDescriptor parseSexp() {
+            if (peek().equals("(")) {
+                next();
+                MatchDescriptor descriptor = parseType(true);
+                for (int n = 0; n < descriptor.nodeType.inputs; n++) {
+                    if (peek().equals("(")) {
+                        descriptor.inputs[n] = parseSexp();
+                    } else {
+                        descriptor.inputs[n] = parseType(false);
+                    }
+                }
+                for (int n = 0; n < descriptor.nodeType.inputs; n++) {
+                    if (descriptor.inputs[n] == null) {
+                        throw new RuleParseError("not enough inputs for " + descriptor.name);
+                    }
+                }
+                if (peek().equals(")")) {
+                    next();
+                    return descriptor;
+                }
+            }
+            throw new RuleParseError("didn't swallow sexp at: " + peek());
+        }
+
+        private MatchDescriptor parseType(boolean sexp) {
+            TypeDescriptor type = null;
+            String name = null;
+            if (Character.isUpperCase(peek().charAt(0))) {
+                String token = next();
+                type = types.get(token);
+                if (type == null) {
+                    throw new RuleParseError("unknown node type: " + token);
+                }
+                if (peek().equals("=")) {
+                    next();
+                    name = next();
+                }
+            } else {
+                name = next();
+                type = null;
+            }
+            return new MatchDescriptor(type, name, sexp);
+        }
+
+        ArrayList<String> generateVariants() {
+            MatchDescriptor descriptor = parseSexp();
+            if (!done()) {
+                throw new RuleParseError("didn't consume all tokens");
+            }
+            return descriptor.generateVariants();
+        }
+    }
+
+    static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*");
+
+    static class TypeDescriptor {
+        /**
+         * The name uses in match expressions to refer to this type.
+         */
+        final String shortName;
+        /**
+         * The {@link ValueNode} class represented by this type.
+         */
+        final String nodeClass;
+
+        /**
+         * The {@link ValueNode} class represented by this type.
+         */
+        final String nodePackage;
+
+        /**
+         * Expected number of matchable inputs. Should be less <= 2 at the moment.
+         */
+        final int inputs;
+
+        /**
+         * An adapter class to read the proper matchable inputs of the class.
+         */
+        final String adapter;
+
+        /**
+         * Should swapped variants of this match be generated. The user of the match is expected to
+         * compensate for any ordering differences in compare which are commutative but require
+         * reinterpreting the condition in that case.
+         */
+        final boolean commutative;
+
+        /**
+         * Can multiple users of this node subsume it. Constants can be swallowed into a match even
+         * if there are multiple users.
+         */
+        final boolean cloneable;
+
+        TypeDescriptor(String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) {
+            this.shortName = shortName;
+            this.nodeClass = nodeClass;
+            this.nodePackage = nodePackage;
+            this.inputs = inputs;
+            this.adapter = adapter;
+            this.commutative = commutative;
+            this.cloneable = (nodePackage + "." + nodeClass).equals(ConstantNode.class.getName());
+            assert !commutative || inputs == 2;
+        }
+    }
+
+    HashMap<String, TypeDescriptor> types = new HashMap<>();
+    ArrayList<String> packages = new ArrayList<>();
+
+    private void declareType(String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) {
+        TypeDescriptor descriptor = new TypeDescriptor(shortName, nodeClass, nodePackage, inputs, adapter, commutative);
+        types.put(shortName, descriptor);
+        if (!packages.contains(descriptor.nodePackage)) {
+            packages.add(descriptor.nodePackage);
+        }
+    }
+
+    private static String findPackage(Element type) {
+        Element enclosing = type.getEnclosingElement();
+        while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
+            enclosing = enclosing.getEnclosingElement();
+        }
+        if (enclosing != null && enclosing.getKind() == ElementKind.PACKAGE) {
+            return ((PackageElement) enclosing).getQualifiedName().toString();
+        }
+        throw new GraalInternalError("can't find package for %s", type);
+    }
+
+    static class MatchDescriptor {
+        TypeDescriptor nodeType;
+        String name;
+        MatchDescriptor[] inputs;
+
+        MatchDescriptor(TypeDescriptor nodeType, String name, boolean sexp) {
+            this.nodeType = nodeType;
+            this.name = name;
+            if (sexp) {
+                this.inputs = new MatchDescriptor[nodeType.inputs];
+            } else {
+                this.inputs = new MatchDescriptor[0];
+            }
+        }
+
+        ArrayList<String> generateVariants() {
+            String prefix = formatPrefix();
+            String suffix = formatSuffix();
+            ArrayList<String> variants = new ArrayList<>();
+            if (inputs.length == 2) {
+                // Generate this version and a swapped version
+                for (String first : inputs[0].generateVariants()) {
+                    for (String second : inputs[1].generateVariants()) {
+                        variants.add(prefix + ", " + first + ", " + second + suffix);
+                        if (nodeType.commutative) {
+                            variants.add(prefix + ", " + second + ", " + first + suffix);
+                        }
+                    }
+                }
+            } else if (inputs.length == 1) {
+                for (String first : inputs[0].generateVariants()) {
+                    variants.add(prefix + ", " + first + suffix);
+                }
+            } else {
+                variants.add(prefix + suffix);
+            }
+            return variants;
+        }
+
+        private String formatPrefix() {
+            if (nodeType == null) {
+                return String.format("new MatchPattern(%s, false", name != null ? ("\"" + name + "\"") : "null");
+            } else {
+                return String.format("new MatchPattern(%s.class, %s", nodeType.nodeClass, name != null ? ("\"" + name + "\"") : "null");
+            }
+        }
+
+        private String formatSuffix() {
+            if (nodeType != null) {
+                if (inputs.length != nodeType.inputs) {
+                    return ", true)";
+                } else {
+                    if (nodeType.adapter != null) {
+                        return ", " + nodeType.adapter + "," + !nodeType.cloneable + ")";
+                    }
+                    if (nodeType.cloneable) {
+                        return ", false)";
+                    }
+                }
+            }
+            return ")";
+        }
+
+    }
+
+    private void createFiles(MatchRuleDescriptor info) {
+        String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString();
+        Name topDeclaringClass = info.topDeclaringType.getSimpleName();
+
+        String optionsClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName();
+        Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]);
+
+        Filer filer = processingEnv.getFiler();
+        try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) {
+
+            out.println("// CheckStyle: stop header check");
+            out.println("// GENERATED CONTENT - DO NOT EDIT");
+            out.println("// Source: " + topDeclaringClass + ".java");
+            out.println("package " + pkg + ";");
+            out.println("");
+            out.println("import java.util.*;");
+            out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;");
+            out.println("import " + NodeLIRBuilder.class.getName() + ";");
+            for (String p : packages) {
+                out.println("import " + p + ".*;");
+            }
+            out.println("");
+            out.println("public class " + optionsClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {");
+            String desc = MatchStatement.class.getSimpleName();
+            out.println("    // CheckStyle: stop line length check");
+            out.println("    private static final List<" + desc + "> options = Collections.unmodifiableList(Arrays.asList(");
+
+            int i = 0;
+            for (MatchRuleItem option : info.options) {
+                String optionValue;
+                if (option.field.getModifiers().contains(Modifier.PRIVATE)) {
+                    optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")";
+                } else {
+                    optionValue = option.declaringClass + "." + option.field.getSimpleName();
+                }
+                String name = option.name;
+                Name fieldName = option.field.getSimpleName();
+                String comma = i == info.options.size() - 1 ? "" : ",";
+                out.printf("        new MatchStatement(\"%s\", %s, %s.class)%s\n", fieldName, name, optionValue, comma);
+                i++;
+            }
+            out.println("    ));");
+            out.println("    // CheckStyle: resume line length check");
+            out.println();
+
+            out.println("    public Class<? extends NodeLIRBuilder> forClass() {");
+            out.println("        return " + topDeclaringClass + ".class;");
+            out.println("    }");
+            out.println();
+            out.println("    @Override");
+            out.println("    public List<" + desc + "> statements() {");
+            out.println("        return options;");
+            out.println("    }");
+            out.println("}");
+        }
+
+        try {
+            createProviderFile(pkg, optionsClassName, originatingElements);
+        } catch (IOException e) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType);
+        }
+    }
+
+    private void createProviderFile(String pkg, String providerClassName, Element... originatingElements) throws IOException {
+        String filename = "META-INF/providers/" + pkg + "." + providerClassName;
+        FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, originatingElements);
+        PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8"));
+        writer.println(MatchStatementSet.class.getName());
+        writer.close();
+    }
+
+    protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) {
+        try {
+            // Ensure Unix line endings to comply with Graal code style guide checked by Checkstyle
+            JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements);
+            return new PrintWriter(sourceFile.openWriter()) {
+
+                @Override
+                public void println() {
+                    print("\n");
+                }
+            };
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    static class MatchRuleItem implements Comparable<MatchRuleItem> {
+
+        final String name;
+        final String declaringClass;
+        final TypeElement field;
+
+        public MatchRuleItem(String name, String declaringClass, TypeElement field) {
+            this.name = name;
+            this.declaringClass = declaringClass;
+            this.field = field;
+        }
+
+        @Override
+        public int compareTo(MatchRuleItem other) {
+            return name.compareTo(other.name);
+        }
+
+        @Override
+        public String toString() {
+            return declaringClass + "." + field;
+        }
+    }
+
+    static class MatchRuleDescriptor {
+
+        final TypeElement topDeclaringType;
+        final List<MatchRuleItem> options = new ArrayList<>();
+        final Set<Element> originatingElements = new HashSet<>();
+
+        public MatchRuleDescriptor(TypeElement topDeclaringType) {
+            this.topDeclaringType = topDeclaringType;
+        }
+    }
+
+    private static TypeElement topDeclaringType(Element element) {
+        Element enclosing = element.getEnclosingElement();
+        if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) {
+            assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE;
+            return (TypeElement) element;
+        }
+        return topDeclaringType(enclosing);
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return true;
+        }
+
+        try {
+            // Import default definitions
+            processMatchableNode(processingEnv.getElementUtils().getTypeElement(GraalMatchableNodes.class.getName()));
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodeImport.class)) {
+                // Import any other definitions required by this element
+                String[] imports = element.getAnnotation(MatchableNodeImport.class).value();
+                for (String m : imports) {
+                    TypeElement el = processingEnv.getElementUtils().getTypeElement(m);
+                    processMatchableNode(el);
+                }
+            }
+
+            // Process any local MatchableNode declarations
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNode.class)) {
+                processMatchableNode(element);
+            }
+
+            Map<TypeElement, MatchRuleDescriptor> map = new HashMap<>();
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) {
+                processMatchRule(map, element);
+            }
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchRules.class)) {
+                processMatchRule(map, element);
+            }
+
+            for (MatchRuleDescriptor info : map.values()) {
+                createFiles(info);
+            }
+
+        } catch (Throwable t) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t);
+        }
+
+        return true;
+    }
+
+    /**
+     * Build up the type table to be used during parsing of the MatchRule.
+     */
+    private void processMatchableNode(Element element) {
+        if (!processedMatchableNode.contains(element)) {
+            processedMatchableNode.add(element);
+            TypeElement topDeclaringType = topDeclaringType(element);
+            MatchableNode[] matchables = element.getAnnotationsByType(MatchableNode.class);
+            for (MatchableNode matchable : matchables) {
+                String nodeClass;
+                String nodePackage;
+                String shortName = matchable.shortName();
+                TypeMirror nodeClassMirror = null;
+                try {
+                    matchable.value();
+                } catch (MirroredTypeException e) {
+                    nodeClassMirror = e.getTypeMirror();
+                }
+                if (nodeClassMirror == null) {
+                    throw new GraalInternalError("Can't get mirror for node class %s", element);
+                }
+                if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) {
+                    nodeClass = topDeclaringType.getQualifiedName().toString();
+                } else {
+                    nodeClass = nodeClassMirror.toString();
+                }
+                nodePackage = findPackage(processingEnv.getElementUtils().getTypeElement(nodeClass));
+                assert nodeClass.startsWith(nodePackage);
+                nodeClass = nodeClass.substring(nodePackage.length() + 1);
+
+                TypeMirror nodeAdapterMirror = null;
+                try {
+                    matchable.adapter();
+                } catch (MirroredTypeException e) {
+                    nodeAdapterMirror = e.getTypeMirror();
+                }
+                if (nodeAdapterMirror == null) {
+                    throw new GraalInternalError("Can't get mirror for adapter %s", element);
+                }
+                String nodeAdapter = null;
+                if (!nodeAdapterMirror.toString().equals(MatchableNode.class.getName())) {
+                    nodeAdapter = String.format("new %s()", nodeAdapterMirror.toString());
+                }
+
+                declareType(shortName, nodeClass, nodePackage, matchable.inputs(), nodeAdapter, matchable.commutative());
+            }
+        }
+    }
+
+    private void processMatchRule(Map<TypeElement, MatchRuleDescriptor> map, Element element) {
+        if (!processedMatchRule.contains(element)) {
+            processedMatchRule.add(element);
+            TypeElement topDeclaringType = topDeclaringType(element);
+            MatchRuleDescriptor options = map.get(topDeclaringType);
+            if (options == null) {
+                options = new MatchRuleDescriptor(topDeclaringType);
+                map.put(topDeclaringType, options);
+            }
+            MatchRule[] matchRules = element.getAnnotationsByType(MatchRule.class);
+            for (MatchRule matchRule : matchRules) {
+                processMatchRule(element, options, matchRule);
+            }
+        }
+    }
+
+    private void processMatchRule(Element element, MatchRuleDescriptor info, MatchRule matchRule) {
+        assert element instanceof TypeElement;
+        assert element.getKind() == ElementKind.CLASS;
+        TypeElement field = (TypeElement) element;
+
+        TypeMirror fieldType = field.asType();
+        if (fieldType.getKind() != TypeKind.DECLARED) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + MatchRule.class.getName(), element);
+            return;
+        }
+
+        Element enclosing = element.getEnclosingElement();
+        String declaringClass = "";
+        String separator = "";
+        Set<Element> originatingElementsList = info.originatingElements;
+        originatingElementsList.add(field);
+        while (enclosing != null) {
+            if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
+                if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
+                    String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
+                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, element);
+                    return;
+                }
+                originatingElementsList.add(enclosing);
+                declaringClass = enclosing.getSimpleName() + separator + declaringClass;
+                separator = ".";
+            } else {
+                assert enclosing.getKind() == ElementKind.PACKAGE;
+            }
+            enclosing = enclosing.getEnclosingElement();
+        }
+
+        String rule = matchRule.value();
+        try {
+            ArrayList<String> matches = new RuleParser(rule).generateVariants();
+            for (String match : matches) {
+                info.options.add(new MatchRuleItem(match, declaringClass, field));
+            }
+        } catch (RuleParseError e) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), element);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * This annotation declares a textual pattern for matching an HIR DAG. It's an s-expression with a
+ * node followed by its inputs. Node types are always uppercase and lowercase words are the names of
+ * nodes.
+ *
+ * <pre>
+ *   NAME := [a-z][a-zA-Z0-9]*
+ *   NODETYPE := [A-Z][a-zA-Z0-9]*
+ *   NODEORNAME :=  NODE [ = NAME ] | NAME
+ *   EXPRESSION := ( NODEORNAME [ EXPRESSION | NODEORNAME [ EXPRESSION | NODEORNAME ] )
+ * </pre>
+ *
+ * All matched nodes except the root of the match and {@link ConstantNode}s must have a single user.
+ * All matched nodes must be in the same block.
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Repeatable(value = MatchRules.class)
+public @interface MatchRule {
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.nodes.*;
+
+public class MatchRuleRegistry {
+
+    private static final HashMap<Class<? extends NodeLIRBuilder>, Map<Class<? extends ValueNode>, List<MatchStatement>>> registry = new HashMap<>();
+
+    /**
+     * Collect all the {@link MatchStatement}s defined by the superclass chain of theClass.
+     *
+     * @param theClass
+     * @return the set of {@link MatchStatement}s applicable to theClass.
+     */
+    public synchronized static Map<Class<? extends ValueNode>, List<MatchStatement>> lookup(Class<? extends NodeLIRBuilder> theClass) {
+        Map<Class<? extends ValueNode>, List<MatchStatement>> result = registry.get(theClass);
+
+        if (result == null) {
+            HashMap<Class<? extends NodeLIRBuilder>, List<MatchStatement>> localRules = new HashMap<>();
+            ServiceLoader<MatchStatementSet> sl = ServiceLoader.loadInstalled(MatchStatementSet.class);
+            for (MatchStatementSet rules : sl) {
+                localRules.put(rules.forClass(), rules.statements());
+            }
+
+            // Walk the class hierarchy collecting lists and merge them together. The subclass
+            // rules are first which gives them preference over earlier rules.
+            Map<Class<? extends ValueNode>, List<MatchStatement>> rules = new HashMap<>();
+            Class<?> currentClass = theClass;
+            do {
+                List<MatchStatement> statements = localRules.get(currentClass);
+                if (statements != null) {
+                    for (MatchStatement statement : statements) {
+                        Class<? extends ValueNode> nodeClass = statement.getPattern().nodeClass();
+                        List<MatchStatement> current = rules.get(nodeClass);
+                        if (current == null) {
+                            current = new ArrayList<>();
+                            rules.put(nodeClass, current);
+                        }
+                        current.add(statement);
+                    }
+                }
+                currentClass = currentClass.getSuperclass();
+            } while (currentClass != NodeLIRBuilder.class);
+            registry.put(theClass, rules);
+            assert registry.get(theClass) == rules;
+            result = rules;
+        }
+
+        if (result.size() == 0) {
+            return null;
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+/**
+ * The repeatable representation of {@link MatchRule}. Should never be used directly.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MatchRules {
+    MatchRule[] value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.MatchPattern.Result;
+import com.oracle.graal.nodes.*;
+
+/**
+ * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace
+ * one or more {@link ValueNode}s with a single {@link Value}.
+ */
+
+public class MatchStatement {
+    private final String name;
+    private final MatchPattern pattern;
+    private final Class<? extends MatchGenerator> generatorClass;
+
+    public MatchStatement(String name, MatchPattern pattern) {
+        this.name = name;
+        this.pattern = pattern;
+        this.generatorClass = null;
+    }
+
+    public MatchStatement(String name, MatchPattern pattern, Class<? extends MatchGenerator> generator) {
+        this.name = name;
+        this.pattern = pattern;
+        this.generatorClass = generator;
+    }
+
+    /**
+     * Attempt to match the current statement against a Node.
+     *
+     * @param builder the current builder instance.
+     * @param node the node to be matched
+     * @param nodes the nodes in the current block
+     * @return true if the statement matched something and set a {@link ComplexMatchResult} to be
+     *         evaluated by the NodeLIRBuilder.
+     */
+    public boolean generate(NodeLIRBuilder builder, ValueNode node, List<ScheduledNode> nodes) {
+        MatchContext context = new MatchContext(builder, this, node, nodes);
+        Result result = pattern.match(node, context);
+        if (result == Result.OK) {
+            result = context.validate();
+        }
+        if (result == Result.OK) {
+            MatchGenerator generator = null;
+            try {
+                generator = generatorClass.newInstance();
+                // Transfer values into gen
+                context.transferState(generator);
+                ComplexMatchResult value = generator.match(builder);
+                if (value != null) {
+                    context.setResult(value);
+                    return true;
+                }
+            } catch (InstantiationException | IllegalAccessException e) {
+                throw new GraalInternalError(e);
+            }
+        } else {
+            // This is fairly verbose for normal usage.
+            // if (result.code != MatchResultCode.WRONG_CLASS) {
+            // // Don't bother logging if it's just the wrong shape.
+            // Debug.log("while matching %s|%s %s %s %s", context.getRoot().toString(Verbosity.Id),
+            // context.getRoot().getClass().getSimpleName(), getName(), result, node.graph());
+            // }
+        }
+        return false;
+    }
+
+    public String formatMatch(ValueNode root) {
+        return pattern.formatMatch(root);
+    }
+
+    public MatchPattern getPattern() {
+        return pattern;
+    }
+
+    public String getName() {
+        return name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.gen.*;
+
+public interface MatchStatementSet {
+    /**
+     * @return the {@link NodeLIRBuilder} subclass which defined this set of {@link MatchStatement}
+     *         instances.
+     */
+    public Class<? extends NodeLIRBuilder> forClass();
+
+    /**
+     * @return the {@link MatchStatement}s available with this {@link NodeLIRBuilder} subclass.
+     */
+    public List<MatchStatement> statements();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * Describes the properties of a node for use when building a {@link MatchPattern}s.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Repeatable(value = MatchableNodes.class)
+public @interface MatchableNode {
+
+    /**
+     * The {@link ValueNode} subclass this annotation describes. These annotations might work better
+     * if they were directly on the node being described but that may complicate the annotation
+     * processing.
+     */
+    Class<? extends ValueNode> value();
+
+    /**
+     * The name used in match patterns. Defaults to class.getSimpleName() with the word Node removed
+     * from the end.
+     */
+    String shortName() default "";
+
+    /**
+     * The number of matchable inputs, which may be less than the real number of inputs.
+     */
+    int inputs() default 0;
+
+    /**
+     * A helper class to visit the inputs in a specified order. Should be a subclass of
+     * {@link MatchNodeAdapter}.
+     */
+    Class<?> adapter() default MatchableNode.class;
+
+    /**
+     * Can a pattern be matched with the operands swapped. This will cause swapped versions of
+     * patterns to be automatically generated.
+     */
+    boolean commutative() default false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodeImport.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+/**
+ * A list of classes which contain one or more {@link MatchableNode} annotations describing nodes
+ * that may be used in match expressions. Those {@link MatchableNode} declarations are parsed before
+ * processing any {@link MatchRule}s.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MatchableNodeImport {
+    String[] value() default {};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodes.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+/**
+ * The repeatable representation of {@link MatchableNode}. Should never be used directly.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MatchableNodes {
+    MatchableNode[] value() default {};
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Apr 29 12:43:27 2014 -0700
@@ -30,6 +30,7 @@
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.cfs.IterativeFlowSensitiveReductionPhase;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
@@ -57,9 +58,14 @@
                 appendPhase(new InliningPhase(canonicalizer));
                 appendPhase(new DeadCodeEliminationPhase());
 
-                if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
+                boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue();
+                if (reduceOrEliminate && OptCanonicalizer.getValue()) {
                     appendPhase(canonicalizer);
-                    appendPhase(new IterativeConditionalEliminationPhase(canonicalizer));
+                    if (FlowSensitiveReduction.getValue()) {
+                        appendPhase(new IterativeFlowSensitiveReductionPhase(canonicalizer));
+                    } else {
+                        appendPhase(new IterativeConditionalEliminationPhase(canonicalizer));
+                    }
                 }
             }
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Tue Apr 29 12:43:27 2014 -0700
@@ -51,9 +51,7 @@
         }
 
         if (OptFloatingReads.getValue()) {
-            IncrementalCanonicalizerPhase<MidTierContext> incCanonicalizer = new IncrementalCanonicalizerPhase<>(canonicalizer);
-            incCanonicalizer.appendPhase(new FloatingReadPhase());
-            appendPhase(incCanonicalizer);
+            appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new FloatingReadPhase()));
             if (OptReadElimination.getValue()) {
                 appendPhase(new ReadEliminationPhase());
             }
@@ -84,7 +82,7 @@
 
         appendPhase(new LoopSafepointInsertionPhase());
 
-        appendPhase(new GuardLoweringPhase());
+        appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new GuardLoweringPhase()));
 
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER));
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Tue Apr 29 12:43:27 2014 -0700
@@ -30,7 +30,9 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 
@@ -71,17 +73,17 @@
      */
     public abstract FrameMap newFrameMap(RegisterConfig registerConfig);
 
-    public abstract LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
+    public abstract LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
 
     public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub);
 
-    public abstract NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen);
+    public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen);
 
     /**
      * @param gen the LIRGenerator the BytecodeLIRBuilder should use
      * @param parser the bytecode parser the BytecodeLIRBuilder should use
      */
-    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         throw GraalInternalError.unimplemented("Baseline compilation is not available for this Backend!");
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +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.compiler.target;
-
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to
- * {@link LIRGenerator} and {@link LIRInstruction}.
- */
-public interface LIRGenLowerable {
-
-    void generate(NodeLIRBuilder generator);
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenResLowerable.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +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.compiler.target;
-
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to
- * {@link LIRGenerationResult} and {@link LIRInstruction}.
- */
-public interface LIRGenResLowerable {
-
-    void generate(NodeLIRBuilderTool generator, LIRGenerationResult genRes);
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FieldIntrospection.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +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.graph;
-
-import java.lang.reflect.*;
-import java.util.*;
-import java.util.concurrent.*;
-
-public abstract class FieldIntrospection extends UnsafeAccess {
-
-    /**
-     * Interface used by {@link #rescanAllFieldOffsets(CalcOffset)} to determine the offset (in
-     * bytes) of a field.
-     */
-    public interface CalcOffset {
-
-        long getOffset(Field field);
-    }
-
-    public static class DefaultCalcOffset implements CalcOffset {
-
-        @Override
-        public long getOffset(Field field) {
-            return unsafe.objectFieldOffset(field);
-        }
-    }
-
-    protected static final ConcurrentHashMap<Class<?>, FieldIntrospection> allClasses = new ConcurrentHashMap<>();
-
-    protected final Class<?> clazz;
-    protected long[] dataOffsets;
-    protected Map<Long, String> fieldNames;
-    protected Map<Long, Class<?>> fieldTypes;
-
-    public FieldIntrospection(Class<?> clazz) {
-        this.clazz = clazz;
-    }
-
-    public static void rescanAllFieldOffsets(CalcOffset calc) {
-        for (FieldIntrospection nodeClass : allClasses.values()) {
-            nodeClass.rescanFieldOffsets(calc);
-        }
-    }
-
-    protected abstract void rescanFieldOffsets(CalcOffset calc);
-
-    public abstract static class BaseFieldScanner {
-
-        private final CalcOffset calc;
-
-        /** The offsets of fields that are not specially handled by subclasses. */
-        public final ArrayList<Long> dataOffsets = new ArrayList<>();
-
-        public final Map<Long, String> fieldNames = new HashMap<>();
-        public final Map<Long, Class<?>> fieldTypes = new HashMap<>();
-
-        protected BaseFieldScanner(CalcOffset calc) {
-            this.calc = calc;
-        }
-
-        protected void scan(Class<?> clazz) {
-            Class<?> currentClazz = clazz;
-            do {
-                for (Field field : currentClazz.getDeclaredFields()) {
-                    if (Modifier.isStatic(field.getModifiers())) {
-                        continue;
-                    }
-                    Class<?> type = field.getType();
-                    long offset = calc.getOffset(field);
-
-                    // scanField() may overwrite the name with a customized name.
-                    fieldNames.put(offset, field.getName());
-                    fieldTypes.put(offset, type);
-
-                    scanField(field, type, offset);
-                }
-                currentClazz = currentClazz.getSuperclass();
-            } while (currentClazz.getSuperclass() != Object.class);
-        }
-
-        protected abstract void scanField(Field field, Class<?> type, long offset);
-    }
-
-    protected static void copyInto(long[] dest, long[] src) {
-        assert dest.length == src.length;
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src[i];
-        }
-    }
-
-    protected static <T> void copyInto(T[] dest, T[] src) {
-        assert dest.length == src.length;
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src[i];
-        }
-    }
-
-    protected static <T> void copyInto(T[] dest, List<T> src) {
-        assert dest.length == src.size();
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src.get(i);
-        }
-    }
-
-    protected static <T> T[] arrayUsingSortedOffsets(Map<Long, T> map, long[] sortedOffsets, T[] result) {
-        for (int i = 0; i < sortedOffsets.length; i++) {
-            result[i] = map.get(sortedOffsets[i]);
-        }
-        return result;
-    }
-
-    protected static long[] sortedLongCopy(ArrayList<Long> list1) {
-        Collections.sort(list1);
-        long[] result = new long[list1.size()];
-        for (int i = 0; i < list1.size(); i++) {
-            result[i] = list1.get(i);
-        }
-        return result;
-    }
-
-    protected static long[] sortedLongCopy(ArrayList<Long> list1, ArrayList<Long> list2) {
-        Collections.sort(list1);
-        Collections.sort(list2);
-        long[] result = new long[list1.size() + list2.size()];
-        for (int i = 0; i < list1.size(); i++) {
-            result[i] = list1.get(i);
-        }
-        for (int i = 0; i < list2.size(); i++) {
-            result[list1.size() + i] = list2.get(i);
-        }
-        return result;
-    }
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Apr 29 12:43:27 2014 -0700
@@ -184,7 +184,6 @@
 
     class NodeUsageIterator implements Iterator<Node> {
 
-        private final int expectedModCount = usageModCount();
         int index = -1;
         Node current;
 
@@ -207,12 +206,10 @@
         }
 
         public boolean hasNext() {
-            assert expectedModCount == usageModCount();
             return current != null;
         }
 
         public Node next() {
-            assert expectedModCount == usageModCount();
             Node result = current;
             if (result == null) {
                 throw new NoSuchElementException();
@@ -676,7 +673,7 @@
             NodeClassIterator iter = usage.inputs().iterator();
             while (iter.hasNext()) {
                 Position pos = iter.nextPosition();
-                if (pos.getInputType(usage) == type) {
+                if (pos.getInputType(usage) == type && pos.get(usage) == this) {
                     pos.set(usage, other);
                 }
             }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Apr 29 12:43:27 2014 -0700
@@ -179,10 +179,10 @@
             this.iterableId = nextIterableId++;
             List<NodeClass> existingClasses = new LinkedList<>();
             for (FieldIntrospection nodeClass : allClasses.values()) {
-                if (clazz.isAssignableFrom(nodeClass.clazz)) {
+                if (clazz.isAssignableFrom(nodeClass.getClazz())) {
                     existingClasses.add((NodeClass) nodeClass);
                 }
-                if (nodeClass.clazz.isAssignableFrom(clazz) && IterableNodeType.class.isAssignableFrom(nodeClass.clazz)) {
+                if (nodeClass.getClazz().isAssignableFrom(clazz) && IterableNodeType.class.isAssignableFrom(nodeClass.getClazz())) {
                     NodeClass superNodeClass = (NodeClass) nodeClass;
                     superNodeClass.iterableIds = Arrays.copyOf(superNodeClass.iterableIds, superNodeClass.iterableIds.length + 1);
                     superNodeClass.iterableIds[superNodeClass.iterableIds.length - 1] = this.iterableId;
@@ -207,7 +207,7 @@
     @Override
     protected void rescanFieldOffsets(CalcOffset calc) {
         FieldScanner scanner = new FieldScanner(calc);
-        scanner.scan(clazz);
+        scanner.scan(getClazz());
         assert directInputCount == scanner.inputOffsets.size();
         copyInto(inputOffsets, sortedLongCopy(scanner.inputOffsets, scanner.inputListOffsets));
         assert directSuccessorCount == scanner.successorOffsets.size();
@@ -324,7 +324,7 @@
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
-        str.append("NodeClass ").append(clazz.getSimpleName()).append(" [");
+        str.append("NodeClass ").append(getClazz().getSimpleName()).append(" [");
         for (int i = 0; i < inputOffsets.length; i++) {
             str.append(i == 0 ? "" : ", ").append(inputOffsets[i]);
         }
@@ -972,7 +972,7 @@
         int index = startIndex;
         while (index < inputOffsets.length) {
             NodeList<Node> list = getNodeList(node, inputOffsets[index]);
-            assert list != null : clazz;
+            assert list != null : getClazz();
             putNodeList(node, inputOffsets[index], updateInputListCopy(list, node, duplicationReplacement));
             index++;
         }
@@ -982,7 +982,7 @@
         int index = startIndex;
         while (index < successorOffsets.length) {
             NodeList<Node> list = getNodeList(node, successorOffsets[index]);
-            assert list != null : clazz;
+            assert list != null : getClazz();
             putNodeList(node, successorOffsets[index], updateSuccListCopy(list, node, duplicationReplacement));
             index++;
         }
@@ -1039,7 +1039,7 @@
     }
 
     public NodeClassIterable getInputIterable(final Node node) {
-        assert clazz.isInstance(node);
+        assert getClazz().isInstance(node);
         return new NodeClassIterable() {
 
             @Override
@@ -1059,7 +1059,7 @@
     }
 
     public NodeClassIterable getSuccessorIterable(final Node node) {
-        assert clazz.isInstance(node);
+        assert getClazz().isInstance(node);
         return new NodeClassIterable() {
 
             @Override
@@ -1092,7 +1092,7 @@
         }
         while (index < inputOffsets.length) {
             NodeList<Node> list = getNodeList(node, inputOffsets[index]);
-            assert list != null : clazz;
+            assert list != null : getClazz();
             if (list.replaceFirst(old, other)) {
                 return true;
             }
@@ -1115,7 +1115,7 @@
         }
         while (index < successorOffsets.length) {
             NodeList<Node> list = getNodeList(node, successorOffsets[index]);
-            assert list != null : clazz + " " + successorOffsets[index] + " " + node;
+            assert list != null : getClazz() + " " + successorOffsets[index] + " " + node;
             if (list.replaceFirst(old, other)) {
                 return true;
             }
@@ -1172,7 +1172,7 @@
      * @param newNode the node to which the inputs should be copied.
      */
     public void copyInputs(Node node, Node newNode) {
-        assert node.getClass() == clazz && newNode.getClass() == clazz;
+        assert node.getClass() == getClazz() && newNode.getClass() == getClazz();
 
         int index = 0;
         while (index < directInputCount) {
@@ -1194,7 +1194,7 @@
      * @param newNode the node to which the successors should be copied.
      */
     public void copySuccessors(Node node, Node newNode) {
-        assert node.getClass() == clazz && newNode.getClass() == clazz;
+        assert node.getClass() == getClazz() && newNode.getClass() == getClazz();
 
         int index = 0;
         while (index < directSuccessorCount) {
@@ -1213,7 +1213,7 @@
     }
 
     public boolean inputsEqual(Node node, Node other) {
-        assert node.getClass() == clazz && other.getClass() == clazz;
+        assert node.getClass() == getClazz() && other.getClass() == getClazz();
         int index = 0;
         while (index < directInputCount) {
             if (getNode(other, inputOffsets[index]) != getNode(node, inputOffsets[index])) {
@@ -1232,7 +1232,7 @@
     }
 
     public boolean successorsEqual(Node node, Node other) {
-        assert node.getClass() == clazz && other.getClass() == clazz;
+        assert node.getClass() == getClazz() && other.getClass() == getClazz();
         int index = 0;
         while (index < directSuccessorCount) {
             if (getNode(other, successorOffsets[index]) != getNode(node, successorOffsets[index])) {
@@ -1251,7 +1251,7 @@
     }
 
     public boolean inputContains(Node node, Node other) {
-        assert node.getClass() == clazz;
+        assert node.getClass() == getClazz();
 
         int index = 0;
         while (index < directInputCount) {
@@ -1271,7 +1271,7 @@
     }
 
     public boolean successorContains(Node node, Node other) {
-        assert node.getClass() == clazz;
+        assert node.getClass() == getClazz();
 
         int index = 0;
         while (index < directSuccessorCount) {
@@ -1353,7 +1353,7 @@
     }
 
     public Class<?> getJavaClass() {
-        return clazz;
+        return getClazz();
     }
 
     /**
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/UnsafeAccess.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +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.graph;
-
-import java.lang.reflect.*;
-
-import sun.misc.*;
-
-public class UnsafeAccess {
-
-    /**
-     * An instance of {@link Unsafe} for use within Graal.
-     */
-    public static final Unsafe unsafe = getUnsafe();
-
-    private static Unsafe getUnsafe() {
-        try {
-            // this will fail if Graal is not part of the boot class path
-            return Unsafe.getUnsafe();
-        } catch (SecurityException e) {
-            // nothing to do
-        }
-        try {
-            Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
-            theUnsafeInstance.setAccessible(true);
-            return (Unsafe) theUnsafeInstance.get(Unsafe.class);
-        } catch (Exception e) {
-            // currently we rely on being able to use Unsafe...
-            throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
-        }
-    }
-
-    /**
-     * Copies the contents of a {@link String} to a native memory buffer as a {@code '\0'}
-     * terminated C string. The native memory buffer is allocated via
-     * {@link Unsafe#allocateMemory(long)}. The caller is responsible for releasing the buffer when
-     * it is no longer needed via {@link Unsafe#freeMemory(long)}.
-     * 
-     * @return the native memory pointer of the C string created from {@code s}
-     */
-    public static long createCString(String s) {
-        return writeCString(s, unsafe.allocateMemory(s.length() + 1));
-    }
-
-    /**
-     * Reads a {@code '\0'} terminated C string from native memory and converts it to a
-     * {@link String}.
-     * 
-     * @return a Java string
-     */
-    public static String readCString(long address) {
-        if (address == 0) {
-            return null;
-        }
-        StringBuffer sb = new StringBuffer();
-        for (int i = 0;; i++) {
-            char c = (char) unsafe.getByte(address + i);
-            if (c == 0) {
-                break;
-            }
-            sb.append(c);
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Writes the contents of a {@link String} to a native memory buffer as a {@code '\0'}
-     * terminated C string. The caller is responsible for ensuring the buffer is at least
-     * {@code s.length() + 1} bytes long. The caller is also responsible for releasing the buffer
-     * when it is no longer.
-     * 
-     * @return the value of {@code buf}
-     */
-    public static long writeCString(String s, long buf) {
-        int size = s.length();
-        for (int i = 0; i < size; i++) {
-            unsafe.putByte(buf + i, (byte) s.charAt(i));
-        }
-        unsafe.putByte(buf + size, (byte) '\0');
-        return buf;
-    }
-}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,6 @@
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import sun.misc.*;
@@ -48,7 +46,9 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 
 /**
  * HotSpot AMD64 specific backend.
@@ -72,7 +72,7 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new AMD64HotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
@@ -82,12 +82,12 @@
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new AMD64HotSpotNodeLIRBuilder(graph, lirGen);
     }
 
     @Override
-    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         return new AMD64HotSpotBytecodeLIRBuilder(gen, parser);
 
     }
@@ -264,7 +264,7 @@
      */
     public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, RegisterConfig regConfig, HotSpotVMConfig config, Label verifiedEntry) {
         HotSpotProviders providers = getProviders();
-        if (installedCodeOwner != null && !isStatic(installedCodeOwner.getModifiers())) {
+        if (installedCodeOwner != null && !installedCodeOwner.isStatic()) {
             MarkId.recordMark(crb, MarkId.UNVERIFIED_ENTRY);
             CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, getTarget(), false);
             Register inlineCacheKlass = rax; // see definition of IC_Klass in
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Apr 29 12:43:27 2014 -0700
@@ -159,7 +159,7 @@
         return new HotSpotSnippetReflectionProvider();
     }
 
-    protected AMD64HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
+    protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
         return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
     }
 
@@ -189,15 +189,15 @@
         } else {
             /*
              * System V Application Binary Interface, AMD64 Architecture Processor Supplement
-             *
+             * 
              * Draft Version 0.96
-             *
+             * 
              * http://www.uclibc.org/docs/psABI-x86_64.pdf
-             *
+             * 
              * 3.2.1
-             *
+             * 
              * ...
-             *
+             * 
              * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12
              * through %r15 "belong" to the calling function and the called function is required to
              * preserve their values. In other words, a called function must preserve these
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,17 +24,16 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.amd64.AMD64HotSpotLIRGenerator.SaveRbp;
 import com.oracle.graal.lir.StandardOp.NoOp;
+import com.oracle.graal.lir.gen.*;
 
 public class AMD64HotSpotBytecodeLIRBuilder extends BytecodeLIRBuilder {
 
-    public AMD64HotSpotBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public AMD64HotSpotBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         super(gen, parser);
     }
 
@@ -72,7 +71,7 @@
         gen.append(getSaveRbp().placeholder);
 
         Signature sig = method.getSignature();
-        boolean isStatic = Modifier.isStatic(method.getModifiers());
+        boolean isStatic = method.isStatic();
         for (int i = 0; i < sig.getParameterCount(!isStatic); i++) {
             Value paramValue = params[i];
             assert paramValue.getKind() == sig.getParameterKind(i).getStackKind();
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java	Tue Apr 29 12:43:27 2014 -0700
@@ -25,10 +25,10 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.gen.*;
 
 public class AMD64HotSpotLIRGenerationResult extends LIRGenerationResultBase {
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,27 +26,28 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import java.util.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
-import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.LoadCompressedPointer;
-import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.StoreCompressedConstantOp;
-import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.StoreCompressedPointer;
+import com.oracle.graal.hotspot.data.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.StandardOp.NoOp;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
 import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
@@ -55,8 +56,8 @@
 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 
 /**
  * LIR generator specialized for AMD64 HotSpot.
@@ -64,6 +65,7 @@
 public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator {
 
     final HotSpotVMConfig config;
+    private HotSpotLockStack lockStack;
 
     protected AMD64HotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) {
         super(providers, cc, lirGenRes);
@@ -130,7 +132,17 @@
 
     @Override
     public StackSlot getLockSlot(int lockDepth) {
-        return ((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack().makeLockSlot(lockDepth);
+        return getLockStack().makeLockSlot(lockDepth);
+    }
+
+    private HotSpotLockStack getLockStack() {
+        assert lockStack != null;
+        return lockStack;
+    }
+
+    protected void setLockStack(HotSpotLockStack lockStack) {
+        assert this.lockStack == null;
+        this.lockStack = lockStack;
     }
 
     private Register findPollOnReturnScratchRegister() {
@@ -159,7 +171,7 @@
     }
 
     @Override
-    protected boolean needOnlyOopMaps() {
+    public boolean needOnlyOopMaps() {
         // Stubs only need oop maps
         return ((AMD64HotSpotLIRGenerationResult) getResult()).getStub() != null;
     }
@@ -245,7 +257,7 @@
     }
 
     @Override
-    public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
         HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
         boolean destroysRegisters = hotspotLinkage.destroysRegisters();
 
@@ -260,9 +272,10 @@
         }
 
         Variable result;
-        DeoptimizingNode deoptInfo = null;
+        // TODO (je) check if we can remove this
+        LIRFrameState deoptInfo = null;
         if (hotspotLinkage.canDeoptimize()) {
-            deoptInfo = info;
+            deoptInfo = state;
             assert deoptInfo != null || getStub() != null;
             assert hotspotLinkage.needsJavaFrameAnchor();
         }
@@ -273,7 +286,8 @@
             result = super.emitForeignCall(hotspotLinkage, deoptInfo, args);
             append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
         } else {
-            result = super.emitForeignCall(hotspotLinkage, deoptInfo, args);
+            assert deoptInfo == null;
+            result = super.emitForeignCall(hotspotLinkage, null, args);
         }
 
         if (destroysRegisters) {
@@ -371,9 +385,9 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value speculation, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
         moveDeoptValuesToThread(actionAndReason, speculation);
-        append(new AMD64DeoptimizeOp(state(deopting)));
+        append(new AMD64DeoptimizeOp(state));
     }
 
     @Override
@@ -397,13 +411,6 @@
     }
 
     /**
-     * Returns whether or not the input access should be (de)compressed.
-     */
-    private boolean isCompressedOperation(PlatformKind kind, Access access) {
-        return access != null && access.isCompressible() && ((kind == Kind.Long && config.useCompressedClassPointers) || (kind == Kind.Object && config.useCompressedOops));
-    }
-
-    /**
      * @return a compressed version of the incoming constant
      */
     protected static Constant compress(Constant c, CompressEncoding encoding) {
@@ -444,85 +451,25 @@
     }
 
     @Override
-    public Variable emitLoad(PlatformKind kind, Value address, Access access) {
+    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
         AMD64AddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(toStackKind(kind));
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
-        /**
-         * Currently, the (de)compression of pointers applies conditionally to some objects (oops,
-         * kind==Object) and some addresses (klass pointers, kind==Long). Initially, the input
-         * operation is checked to discover if it has been tagged as a potential "compression"
-         * candidate. Consequently, depending on the appropriate kind, the specific (de)compression
-         * functions are being called.
-         */
-        if (isCompressedOperation(kind, access)) {
-            if (kind == Kind.Object) {
-                append(new LoadCompressedPointer(Kind.Object, result, getProviders().getRegisters().getHeapBaseRegister().asValue(), loadAddress, state, config.getOopEncoding()));
-            } else if (kind == Kind.Long) {
-                Variable scratch = config.getKlassEncoding().base != 0 ? newVariable(Kind.Long) : null;
-                append(new LoadCompressedPointer(Kind.Long, result, scratch, loadAddress, state, config.getKlassEncoding()));
-            } else {
-                throw GraalInternalError.shouldNotReachHere("can't handle: " + access);
-            }
-        } else {
-            append(new LoadOp(getMemoryKind(kind), result, loadAddress, state));
-        }
+        append(new LoadOp(getMemoryKind(kind), result, loadAddress, state));
         return result;
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, Access access) {
+    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
         AMD64AddressValue storeAddress = asAddressValue(address);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
-        boolean isCompressed = isCompressedOperation(kind, access);
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
-            if (canStoreConstant(c, isCompressed)) {
-                if (isCompressed) {
-                    if (c.getKind() == Kind.Object) {
-                        append(new StoreCompressedConstantOp(Kind.Object, storeAddress, c, state));
-                    } else if (c.getKind() == Kind.Long) {
-                        // It's always a good idea to directly store compressed constants since they
-                        // have to be materialized as 64 bits encoded otherwise.
-                        Constant value = compress(c, config.getKlassEncoding());
-                        append(new StoreCompressedConstantOp(Kind.Long, storeAddress, value, state));
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere("can't handle: " + access);
-                    }
-                    return;
-                } else {
-                    append(new StoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
-                    return;
-                }
+            if (canStoreConstant(c, false)) {
+                append(new StoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
+                return;
             }
         }
         Variable input = load(inputVal);
-        if (isCompressed) {
-            if (kind == Kind.Object) {
-                if (input.getKind() == Kind.Object) {
-                    Variable scratch = newVariable(Kind.Long);
-                    Register heapBaseReg = getProviders().getRegisters().getHeapBaseRegister();
-                    append(new StoreCompressedPointer(Kind.Object, storeAddress, input, scratch, state, config.getOopEncoding(), heapBaseReg));
-                } else {
-                    // the input oop is already compressed
-                    append(new StoreOp(input.getKind(), storeAddress, input, state));
-                }
-            } else if (kind == Kind.Long) {
-                Variable scratch = newVariable(Kind.Long);
-                Register heapBaseReg = getProviders().getRegisters().getHeapBaseRegister();
-                append(new StoreCompressedPointer(Kind.Long, storeAddress, input, scratch, state, config.getKlassEncoding(), heapBaseReg));
-            } else {
-                append(new StoreOp(getMemoryKind(kind), storeAddress, input, state));
-            }
-        } else {
-            append(new StoreOp(getMemoryKind(kind), storeAddress, input, state));
-        }
+        append(new StoreOp(getMemoryKind(kind), storeAddress, input, state));
     }
 
     @Override
@@ -601,6 +548,14 @@
         return result;
     }
 
+    public static Register asNarrowReg(Value value) {
+        if (value.getPlatformKind() != NarrowOopStamp.NarrowOop) {
+            throw new InternalError("needed NarrowOop got: " + value.getKind());
+        } else {
+            return asRegister(value);
+        }
+    }
+
     public Value emitAtomicReadAndWrite(Value address, Value newValue) {
         PlatformKind kind = newValue.getPlatformKind();
         Kind memKind = getMemoryKind(kind);
@@ -610,4 +565,59 @@
         return result;
     }
 
+    public static class CompareMemoryCompressedOp extends AMD64LIRInstruction {
+        @Alive({COMPOSITE}) protected AMD64AddressValue x;
+        @Use({CONST, REG}) protected Value y;
+        @State protected LIRFrameState state;
+
+        public CompareMemoryCompressedOp(AMD64AddressValue x, Value y, LIRFrameState state) {
+            assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops;
+            this.x = x;
+            this.y = y;
+            this.state = state;
+        }
+
+        @Override
+        protected void verify() {
+            assert y instanceof Constant || y.getPlatformKind() == NarrowOopStamp.NarrowOop;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            if (y instanceof Constant) {
+                Constant constant = (Constant) y;
+                if (constant.isNull()) {
+                    masm.cmpl(x.toAddress(), 0);
+                } else {
+                    if (y.getKind() == Kind.Object) {
+                        crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(constant), true));
+                    } else if (y.getKind() == Kind.Long) {
+                        crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(constant), true));
+                    } else {
+                        throw GraalInternalError.shouldNotReachHere();
+                    }
+                    masm.cmpl(x.toAddress(), 0xdeaddead);
+                }
+            } else {
+                masm.cmpl(asNarrowReg(y), x.toAddress());
+            }
+        }
+    }
+
+    protected void emitCompareBranchMemoryCompressed(Value left, Value right, Condition cond, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability, LIRFrameState state) {
+        boolean mirrored = false;
+        if (left instanceof AMD64AddressValue) {
+            append(new CompareMemoryCompressedOp((AMD64AddressValue) left, right, state));
+        } else {
+            assert right instanceof AMD64AddressValue;
+            append(new CompareMemoryCompressedOp((AMD64AddressValue) right, left, state));
+            mirrored = true;
+        }
+
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+    }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -31,7 +31,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.amd64.*;
 
-public class AMD64HotSpotLoweringProvider extends HotSpotLoweringProvider {
+public class AMD64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
 
     private AMD64ConvertSnippets.Templates convertSnippets;
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.hotspot.amd64;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.compiler.amd64.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.data.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
-import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Specialized code gen for comparison with compressed memory.
- */
-
-public class AMD64HotSpotMemoryPeephole extends AMD64MemoryPeephole {
-    public static class CompareMemoryCompressedOp extends AMD64LIRInstruction {
-        @Alive({COMPOSITE}) protected AMD64AddressValue x;
-        @Use({CONST}) protected Value y;
-        @State protected LIRFrameState state;
-
-        public CompareMemoryCompressedOp(AMD64AddressValue x, Constant y, LIRFrameState state) {
-            assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops;
-            this.x = x;
-            this.y = y;
-            this.state = state;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            Constant constant = (Constant) y;
-            if (constant.isNull()) {
-                masm.cmpl(x.toAddress(), 0);
-            } else {
-                if (y.getKind() == Kind.Object) {
-                    crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(constant), true));
-                } else if (y.getKind() == Kind.Long) {
-                    crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(constant), true));
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-                if (state != null) {
-                    crb.recordImplicitException(masm.position(), state);
-                }
-                masm.cmpl(x.toAddress(), 0xdeaddead);
-            }
-        }
-    }
-
-    AMD64HotSpotMemoryPeephole(AMD64NodeLIRBuilder gen) {
-        super(gen);
-    }
-
-    @Override
-    protected Kind getMemoryKind(Access access) {
-        PlatformKind kind = gen.getLIRGenerator().getPlatformKind(access.asNode().stamp());
-        if (kind == NarrowOopStamp.NarrowOop) {
-            return Kind.Int;
-        } else {
-            return (Kind) kind;
-        }
-    }
-
-    @Override
-    protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
-                    double trueLabelProbability) {
-        if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
-            ValueNode other = selectOtherInput(left, right, access);
-            Kind kind = getMemoryKind(access);
-
-            if (other.isConstant() && kind == Kind.Object && access.isCompressible()) {
-                ensureEvaluated(other);
-                gen.append(new CompareMemoryCompressedOp(makeAddress(access), other.asConstant(), getState(access)));
-                Condition finalCondition = right == access ? cond.mirror() : cond;
-                gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
-                return true;
-            }
-        }
-
-        return super.emitCompareBranchMemory(left, right, access, cond, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
-    }
-}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,15 +26,15 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.compiler.amd64.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
@@ -45,17 +45,61 @@
 import com.oracle.graal.lir.StandardOp.NoOp;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
 /**
  * LIR generator specialized for AMD64 HotSpot.
  */
+@MatchableNodeImport({"com.oracle.graal.hotspot.nodes.HotSpotMatchableNodes"})
 public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) {
+    private static ValueNode filterCompression(ValueNode node) {
+        ValueNode result = node;
+        while (result instanceof CompressionNode) {
+            result = ((CompressionNode) result).getInput();
+        }
+        return result;
+    }
+
+    private void emitCompareCompressedMemory(IfNode ifNode, ValueNode valueNode, Access access, CompareNode compare) {
+        Value value;
+        // This works by embedding the compressed form for constants, so force a constant instead of
+        // respecting what operand() would return.
+        if (valueNode.isConstant()) {
+            value = valueNode.asConstant();
+        } else {
+            value = gen.load(operand(valueNode));
+        }
+        AMD64AddressValue address = makeAddress(access);
+
+        Condition cond = compare.condition();
+        Value left;
+        Value right;
+        if (access == filterCompression(compare.x())) {
+            left = value;
+            right = address;
+        } else {
+            assert access == filterCompression(compare.y());
+            left = address;
+            right = value;
+            cond = cond.mirror();
+        }
+
+        LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+        LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+        double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+        getGen().emitCompareBranchMemoryCompressed(left, right, cond, trueLabel, falseLabel, trueLabelProbability, getState(access));
+    }
+
+    public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         super(graph, gen);
-        memoryPeephole = new AMD64HotSpotMemoryPeephole(this);
+        assert gen instanceof AMD64HotSpotLIRGenerator;
+        assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
+        ((AMD64HotSpotLIRGenerator) gen).setLockStack(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());
     }
 
     private AMD64HotSpotLIRGenerator getGen() {
@@ -107,7 +151,7 @@
 
     @Override
     public void visitSafepointNode(SafepointNode i) {
-        LIRFrameState info = gen.state(i);
+        LIRFrameState info = state(i);
         append(new AMD64HotSpotSafepointOp(info, getGen().config, this));
     }
 
@@ -119,7 +163,7 @@
         } else {
             assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special;
             HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target();
-            assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method.";
+            assert !resolvedMethod.isAbstract() : "Cannot make direct call to abstract method.";
             append(new AMD64HotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
         }
     }
@@ -199,4 +243,40 @@
         gen.emitMove(result, raxLocal);
         setResult(x, result);
     }
+
+    /**
+     * Helper class to convert the NodeLIRBuilder into the current subclass.
+     */
+    static abstract class AMD64HotSpotMatchGenerator implements MatchGenerator {
+        public AMD64HotSpotMatchGenerator() {
+        }
+
+        public ComplexMatchResult match(NodeLIRBuilder gen) {
+            return match((AMD64HotSpotNodeLIRBuilder) gen);
+        }
+
+        abstract public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen);
+    }
+
+    @MatchRule("(If (ObjectEquals=compare Constant=value (Compression Read=access)))")
+    @MatchRule("(If (ObjectEquals=compare Constant=value (Compression FloatingRead=access)))")
+    @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression Read=access)))")
+    @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression FloatingRead=access)))")
+    public static class IfCompareMemory extends AMD64HotSpotMatchGenerator {
+        IfNode root;
+        Access access;
+        ValueNode value;
+        CompareNode compare;
+
+        @Override
+        public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen) {
+            if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
+                return builder -> {
+                    gen.emitCompareCompressedMemory(root, value, access, compare);
+                    return null;
+                };
+            }
+            return null;
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,12 +27,11 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRGenLowerable {
+public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
 
     private final Constant functionPointer;
     @Input private final NodeInputList<ValueNode> args;
@@ -44,7 +43,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder generator) {
+    public void generate(NodeLIRBuilderTool generator) {
         AMD64NodeLIRBuilder gen = (AMD64NodeLIRBuilder) generator;
         Value[] parameter = new Value[args.count()];
         JavaType[] parameterTypes = new JavaType[args.count()];
@@ -55,7 +54,7 @@
         ResolvedJavaType returnType = stamp().javaType(gen.getLIRGeneratorTool().getMetaAccess());
         CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(Type.NativeCall, returnType, parameterTypes,
                         generator.getLIRGeneratorTool().target(), false);
-        ((AMD64LIRGenerator) gen.getLIRGeneratorTool()).emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
+        gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
         if (this.getKind() != Kind.Void) {
             generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
         }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Tue Apr 29 12:43:27 2014 -0700
@@ -49,7 +49,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.gpu.*;
@@ -61,6 +60,7 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizingOp;
 import com.oracle.graal.lir.hsail.HSAILMove.AtomicReadAndAddOp;
@@ -69,6 +69,7 @@
 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.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
@@ -301,9 +302,8 @@
         for (CodeAnnotation annotation : hostCode.getAnnotations()) {
             result.addAnnotation(annotation);
         }
-        CompilationResult.Mark[] noMarks = {};
         for (Mark mark : hostCode.getMarks()) {
-            result.recordMark(mark.pcOffset, mark.id, noMarks);
+            result.recordMark(mark.pcOffset, mark.id);
         }
         for (ExceptionHandler handler : hostCode.getExceptionHandlers()) {
             result.recordExceptionHandler(handler.pcOffset, handler.handlerPos);
@@ -375,7 +375,7 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new HSAILHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
@@ -385,7 +385,7 @@
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new HSAILHotSpotNodeLIRBuilder(graph, lirGen);
     }
 
@@ -468,7 +468,7 @@
         // We're subtracting 1 because we're not making the final gid as a parameter.
 
         int nonConstantParamCount = sigParamCount - 1;
-        boolean isStatic = (Modifier.isStatic(method.getModifiers()));
+        boolean isStatic = (method.isStatic());
         // Determine if this is an object lambda.
         boolean isObjectLambda = true;
 
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Tue Apr 29 12:43:27 2014 -0700
@@ -36,6 +36,10 @@
 @ServiceProvider(HotSpotBackendFactory.class)
 public class HSAILHotSpotBackendFactory implements HotSpotBackendFactory {
 
+    protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
+        return new HSAILHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
+    }
+
     @Override
     public HSAILHotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotBackend hostBackend) {
         HotSpotProviders host = hostBackend.getProviders();
@@ -45,7 +49,7 @@
         HSAILHotSpotCodeCacheProvider codeCache = new HSAILHotSpotCodeCacheProvider(runtime, createTarget());
         ConstantReflectionProvider constantReflection = host.getConstantReflection();
         HotSpotForeignCallsProvider foreignCalls = new HSAILHotSpotForeignCallsProvider(runtime, metaAccess, codeCache);
-        LoweringProvider lowerer = new HSAILHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
+        HotSpotLoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers);
         // Replacements cannot have speculative optimizations since they have
         // to be valid for the entire run of the VM.
         Assumptions assumptions = new Assumptions(false);
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerationResult.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerationResult.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,8 @@
 
 import java.util.*;
 
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizingOp;
 
 public class HSAILHotSpotLIRGenerationResult extends LIRGenerationResultBase {
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,14 +24,11 @@
 package com.oracle.graal.hotspot.hsail;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.hsail.HSAILControlFlow.*;
-import static com.oracle.graal.lir.hsail.HSAILMove.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.hsail.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
@@ -39,9 +36,19 @@
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.CondMoveOp;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizeOp;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCall1ArgOp;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCall2ArgOp;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCallNoArgOp;
+import com.oracle.graal.lir.hsail.HSAILMove.CompareAndSwapOp;
+import com.oracle.graal.lir.hsail.HSAILMove.LoadOp;
+import com.oracle.graal.lir.hsail.HSAILMove.MoveFromRegOp;
+import com.oracle.graal.lir.hsail.HSAILMove.MoveToRegOp;
+import com.oracle.graal.lir.hsail.HSAILMove.StoreConstantOp;
+import com.oracle.graal.lir.hsail.HSAILMove.StoreOp;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -85,22 +92,11 @@
         return config.narrowKlassBase;
     }
 
-    private static boolean isCompressCandidate(Access access) {
-        return access != null && access.isCompressible();
-    }
-
     @Override
     public boolean canStoreConstant(Constant c, boolean isCompressed) {
         return true;
     }
 
-    /**
-     * Returns whether or not the input access should be (de)compressed.
-     */
-    private boolean isCompressedOperation(PlatformKind kind, Access access) {
-        return access != null && access.isCompressible() && ((kind == Kind.Long && config.useCompressedClassPointers) || (kind == Kind.Object && config.useCompressedOops));
-    }
-
     private static Kind getMemoryKind(PlatformKind kind) {
         if (kind == NarrowOopStamp.NarrowOop) {
             return Kind.Int;
@@ -110,20 +106,10 @@
     }
 
     @Override
-    public Variable emitLoad(PlatformKind kind, Value address, Access access) {
+    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
         HSAILAddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(kind);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
-        if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) {
-            Variable scratch = newVariable(Kind.Long);
-            append(new LoadCompressedPointer(Kind.Object, result, scratch, loadAddress, state, getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment()));
-        } else if (isCompressCandidate(access) && config.useCompressedClassPointers && kind == Kind.Long) {
-            Variable scratch = newVariable(Kind.Long);
-            append(new LoadCompressedPointer(Kind.Object, result, scratch, loadAddress, state, getNarrowKlassBase(), getNarrowKlassShift(), getLogKlassAlignment()));
-        } else if (kind == NarrowOopStamp.NarrowOop) {
+        if (kind == NarrowOopStamp.NarrowOop) {
             append(new LoadOp(Kind.Int, result, loadAddress, state));
         } else {
             append(new LoadOp(getMemoryKind(kind), result, loadAddress, state));
@@ -132,43 +118,17 @@
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, Access access) {
+    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
         HSAILAddressValue storeAddress = asAddressValue(address);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
-        boolean isCompressed = isCompressedOperation(kind, access);
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
-            if (canStoreConstant(c, isCompressed)) {
-                if (isCompressed) {
-                    if ((c.getKind() == Kind.Object) && c.isNull()) {
-                        // Constant value = c.isNull() ? c : compress(c, config.getOopEncoding());
-                        append(new StoreConstantOp(Kind.Int, storeAddress, Constant.forInt(0), state));
-                    } else if (c.getKind() == Kind.Long) {
-                        // It's always a good idea to directly store compressed constants since they
-                        // have to be materialized as 64 bits encoded otherwise.
-                        Constant value = compress(c, config.getKlassEncoding());
-                        append(new StoreConstantOp(Kind.Int, storeAddress, value, state));
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere("can't handle: " + access);
-                    }
-                    return;
-                } else {
-                    append(new StoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
-                    return;
-                }
+            if (canStoreConstant(c, false)) {
+                append(new StoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
+                return;
             }
         }
         Variable input = load(inputVal);
-        if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) {
-            Variable scratch = newVariable(Kind.Long);
-            append(new StoreCompressedPointer(Kind.Object, storeAddress, input, scratch, state, getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment()));
-        } else if (isCompressCandidate(access) && config.useCompressedClassPointers && kind == Kind.Long) {
-            Variable scratch = newVariable(Kind.Long);
-            append(new StoreCompressedPointer(Kind.Object, storeAddress, input, scratch, state, getNarrowKlassBase(), getNarrowKlassShift(), getLogKlassAlignment()));
-        } else if (kind == NarrowOopStamp.NarrowOop) {
+        if (kind == NarrowOopStamp.NarrowOop) {
             append(new StoreOp(Kind.Int, storeAddress, input, state));
         } else {
             append(new StoreOp(getMemoryKind(kind), storeAddress, input, state));
@@ -191,6 +151,7 @@
         return nodeResult;
     }
 
+    @Override
     public Value emitAtomicReadAndAdd(Value address, Value delta) {
         PlatformKind kind = delta.getPlatformKind();
         Kind memKind = getMemoryKind(kind);
@@ -201,8 +162,18 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, DeoptimizingNode deopting) {
-        emitDeoptimizeInner(actionAndReason, state(deopting), "emitDeoptimize");
+    public Value emitAtomicReadAndWrite(Value address, Value newValue) {
+        PlatformKind kind = newValue.getPlatformKind();
+        Kind memKind = getMemoryKind(kind);
+        Variable result = newVariable(kind);
+        HSAILAddressValue addressValue = asAddressValue(address);
+        append(new HSAILMove.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue)));
+        return result;
+    }
+
+    @Override
+    public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) {
+        emitDeoptimizeInner(actionAndReason, state, "emitDeoptimize");
     }
 
     /***
@@ -220,7 +191,7 @@
      * emitting a comment as to what Foreign call they would have made.
      */
     @Override
-    public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
         Variable result = newVariable(Kind.Object);  // linkage.getDescriptor().getResultType());
 
         // to make the LIRVerifier happy, we move any constants into registers
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -37,7 +37,7 @@
 
 import java.util.HashMap;
 
-public class HSAILHotSpotLoweringProvider extends HotSpotLoweringProvider {
+public class HSAILHotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
 
     private HSAILNewObjectSnippets.Templates hsailNewObjectSnippets;
 
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,7 +27,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.hsail.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
@@ -35,6 +34,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
 import com.oracle.graal.lir.hsail.HSAILMove.CompareAndSwapOp;
 import com.oracle.graal.nodes.*;
@@ -44,7 +44,7 @@
  */
 public class HSAILHotSpotNodeLIRBuilder extends HSAILNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    public HSAILHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public HSAILHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
@@ -105,7 +105,7 @@
     public void visitSafepointNode(SafepointNode i) {
         HotSpotVMConfig config = getGen().config;
         if (config.useHSAILSafepoints == true) {
-            LIRFrameState info = gen.state(i);
+            LIRFrameState info = state(i);
             HSAILHotSpotSafepointOp safepoint = new HSAILHotSpotSafepointOp(info, config, this);
             ((HSAILHotSpotLIRGenerationResult) getGen().getResult()).addDeopt(safepoint);
             append(safepoint);
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Tue Apr 29 12:43:27 2014 -0700
@@ -38,7 +38,6 @@
 import com.oracle.graal.asm.ptx.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.gpu.*;
@@ -50,10 +49,12 @@
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 import com.oracle.graal.lir.StandardOp.LabelOp;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.ptx.*;
 import com.oracle.graal.lir.ptx.PTXControlFlow.PTXPredicatedLIRInstruction;
 import com.oracle.graal.lir.ptx.PTXMemOp.LoadReturnAddrOp;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -355,12 +356,12 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new PTXHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new PTXHotSpotNodeLIRBuilder(graph, lirGen);
     }
 
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,12 +26,12 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.ptx.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.gen.*;
 
 /**
  * LIR generator specialized for PTX HotSpot.
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,10 +24,10 @@
 package com.oracle.graal.hotspot.ptx;
 
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.ptx.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -35,7 +35,7 @@
  */
 public class PTXHotSpotNodeLIRBuilder extends PTXNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    protected PTXHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    protected PTXHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -31,8 +31,6 @@
 import static com.oracle.graal.hotspot.ptx.PTXWrapperBuilder.LaunchArg.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -61,8 +59,8 @@
  * <li>PINNED: a buffer into which the address of pinned objects is saved.</li>
  * <li>OBJECT_OFFSETS: the offsets of the object values in PARAMS.</li>
  * </ul>
- * 
- * 
+ *
+ *
  * The PARAMS buffer is the {@code CU_LAUNCH_PARAM_BUFFER_POINTER} buffer passed in the
  * {@code extra} argument to the {@code cuLaunchKernel} function. This buffer contains the
  * parameters to the call. The buffer is word aligned and each parameter is aligned in the buffer
@@ -74,13 +72,13 @@
  * The object pointers in PARAMS are specified by OBJECT_OFFSETS.
  * <p>
  * As a concrete example, for a kernel whose Java method signature is:
- * 
+ *
  * <pre>
  *     static int kernel(int p1, short p2, Object p3, long p4)
  * </pre>
- * 
+ *
  * the graph created is shown below as psuedo-code:
- * 
+ *
  * <pre>
  *     int kernel_wrapper(int p1, short p2, oop p3, long p4) {
  *         address kernelAddr = kernel.start;
@@ -121,7 +119,7 @@
     /**
      * The size of the buffer holding the kernel parameters and the extra word for storing the
      * pointer to device memory for the return value.
-     * 
+     *
      * @see LaunchArg#ParametersAndReturnValueBufferSize
      */
     int bufSize;
@@ -152,7 +150,7 @@
 
     /**
      * Creates the graph implementing the CPU to GPU transition.
-     * 
+     *
      * @param method a method that has been compiled to GPU binary code
      * @param kernel the installed GPU binary for {@code method}
      * @see PTXWrapperBuilder
@@ -163,7 +161,7 @@
         int intSize = Integer.SIZE / Byte.SIZE;
         Kind wordKind = providers.getCodeCache().getTarget().wordKind;
         Signature sig = method.getSignature();
-        boolean isStatic = isStatic(method.getModifiers());
+        boolean isStatic = method.isStatic();
         int sigCount = sig.getParameterCount(false);
         javaParameters = new ParameterNode[(!isStatic ? 1 : 0) + sigCount];
         javaParameterOffsetsInKernelParametersBuffer = new int[javaParameters.length];
@@ -300,7 +298,7 @@
 
     /**
      * Computes offset and size of space in PARAMS for a Java parameter.
-     * 
+     *
      * @param kind the kind of the parameter
      * @param javaParametersIndex the index of the Java parameter
      */
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java	Tue Apr 29 12:43:27 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,11 +35,14 @@
 
     public SPARCDeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(providers, target, linkage);
-        registerConfig = new SPARCHotSpotRegisterConfig(target, new Register[]{o0, o1, o2, o3, o4, o5, o7, l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, f0, f1, f2, f3, f4, f5, f6, f7});
+        // This is basically the maximum we can spare. All other G and O register are used.
+        Register[] allocatable = new Register[]{g1, g3, g4, g5, o0, o1, o2, o3, o4};
+        registerConfig = new SPARCHotSpotRegisterConfig(target, allocatable);
     }
 
     @Override
     public RegisterConfig getRegisterConfig() {
         return registerConfig;
     }
+
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,6 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.sparc.SPARC.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import sun.misc.*;
@@ -46,7 +44,6 @@
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.RestoreWindow;
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.hotspot.meta.*;
@@ -54,8 +51,10 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 
 /**
  * HotSpot SPARC specific backend.
@@ -79,12 +78,17 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+        return new SPARCHotSpotLIRGenerationResult(lir, frameMap, stub);
+    }
+
+    @Override
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new SPARCHotSpotNodeLIRBuilder(graph, lirGen);
     }
 
@@ -191,17 +195,12 @@
     }
 
     @Override
-    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
-        return new LIRGenerationResultBase(lir, frameMap);
-    }
-
-    @Override
     public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
         SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
         FrameMap frameMap = crb.frameMap;
         RegisterConfig regConfig = frameMap.registerConfig;
         HotSpotVMConfig config = getRuntime().getConfig();
-        Label unverifiedStub = installedCodeOwner == null || isStatic(installedCodeOwner.getModifiers()) ? null : new Label();
+        Label unverifiedStub = installedCodeOwner == null || installedCodeOwner.isStatic() ? null : new Label();
 
         // Emit the prefix
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,9 +48,8 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-
         // Save last Java frame.
-        new Add(stackPointer, new SPARCAddress(stackPointer, 0).getDisplacement(), g4).emit(masm);
+        new Add(stackPointer, STACK_BIAS, g4).emit(masm);
         new Stx(g4, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
 
         // Save the thread register when calling out to the runtime.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+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.sparc.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Emits code that enters a stack frame which is tailored to call the C++ method
+ * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
+final class SPARCHotSpotEnterUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+
+    private final Register thread;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Temp(REG) AllocatableValue scratch;
+
+    SPARCHotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue scratch) {
+        this.thread = thread;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.scratch = scratch;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        final int totalFrameSize = crb.frameMap.totalFrameSize();
+        Register framePcRegister = asRegister(framePc);
+        Register senderSpRegister = asRegister(senderSp);
+        Register scratchRegister = asRegister(scratch);
+
+        // Save final sender SP to O5_savedSP.
+        new Mov(senderSpRegister, o5).emit(masm);
+
+        // Load final frame PC.
+        new Mov(framePcRegister, o7).emit(masm);
+
+        // Allocate a full sized frame.
+        new Save(sp, -totalFrameSize, sp).emit(masm);
+
+        new Mov(i0, o0).emit(masm);
+        new Mov(i1, o1).emit(masm);
+        new Mov(i2, o2).emit(masm);
+        new Mov(i3, o3).emit(masm);
+        new Mov(i4, o4).emit(masm);
+
+        // Set up last Java values.
+        new Add(sp, STACK_BIAS, scratchRegister).emit(masm);
+        new Stx(scratchRegister, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
+
+        // Clear last Java PC.
+        new Stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)).emit(masm);
+
+        /*
+         * Safe thread register manually since we are not using LEAF_SP for {@link
+         * DeoptimizationStub#UNPACK_FRAMES}.
+         */
+        new Mov(thread, l7).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java	Tue Apr 29 12:43:27 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,14 +22,49 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.gen.*;
+
+public class SPARCHotSpotLIRGenerationResult extends LIRGenerationResultBase {
+
+    /**
+     * The slot reserved for storing the original return address when a frame is marked for
+     * deoptimization. The return address slot in the callee is overwritten with the address of a
+     * deoptimization stub.
+     */
+    private StackSlot deoptimizationRescueSlot;
+    private final Object stub;
 
-public interface SPARCHotSpotLIRGenerationResult extends LIRGenerationResult {
+    /**
+     * Map from debug infos that need to be updated with callee save information to the operations
+     * that provide the information.
+     */
+    private Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = new HashMap<>();
+
+    public SPARCHotSpotLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+        super(lir, frameMap);
+        this.stub = stub;
+    }
 
-    StackSlot getDeoptimizationRescueSlot();
+    StackSlot getDeoptimizationRescueSlot() {
+        return deoptimizationRescueSlot;
+    }
+
+    public final void setDeoptimizationRescueSlot(StackSlot deoptimizationRescueSlot) {
+        this.deoptimizationRescueSlot = deoptimizationRescueSlot;
+    }
 
-    Stub getStub();
+    Stub getStub() {
+        return (Stub) stub;
+    }
+
+    Map<LIRFrameState, SaveRegistersOp> getCalleeSaveInfo() {
+        return calleeSaveInfo;
+    }
 
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,11 +24,12 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
+import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.sparc.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
@@ -36,16 +37,17 @@
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
 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.extended.*;
 
 public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator {
 
     final HotSpotVMConfig config;
+    private HotSpotLockStack lockStack;
 
     public SPARCHotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) {
         super(providers, cc, lirGenRes);
@@ -66,11 +68,21 @@
 
     @Override
     public StackSlot getLockSlot(int lockDepth) {
-        return ((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack().makeLockSlot(lockDepth);
+        return getLockStack().makeLockSlot(lockDepth);
+    }
+
+    private HotSpotLockStack getLockStack() {
+        assert lockStack != null;
+        return lockStack;
+    }
+
+    protected void setLockStack(HotSpotLockStack lockStack) {
+        assert this.lockStack == null;
+        this.lockStack = lockStack;
     }
 
     @Override
-    protected boolean needOnlyOopMaps() {
+    public boolean needOnlyOopMaps() {
         // Stubs only need oop maps
         return getStub() != null;
     }
@@ -80,12 +92,13 @@
     }
 
     @Override
-    public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
         HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
         Variable result;
-        DeoptimizingNode deoptInfo = null;
+        // TODO (je) check if this can be removed
+        LIRFrameState deoptInfo = null;
         if (hotspotLinkage.canDeoptimize()) {
-            deoptInfo = info;
+            deoptInfo = state;
             assert deoptInfo != null || getStub() != null;
         }
 
@@ -142,9 +155,9 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value speculation, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
         moveDeoptValuesToThread(actionAndReason, speculation);
-        append(new SPARCDeoptimizeOp(state(deopting)));
+        append(new SPARCDeoptimizeOp(state));
     }
 
     @Override
@@ -158,14 +171,10 @@
     }
 
     @Override
-    public Variable emitLoad(PlatformKind kind, Value address, Access access) {
+    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
         SPARCAddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(kind);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
-        if (isCompressCandidate(access)) {
+        if (isCompressCandidate(null)) {
             if (config.useCompressedOops && kind == Kind.Object) {
                 // append(new LoadCompressedPointer(kind, result, loadAddress, access != null ?
                 // state(access) :
@@ -188,19 +197,15 @@
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, Access access) {
+    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
         SPARCAddressValue storeAddress = asAddressValue(address);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
-            if (canStoreConstant(c, isCompressCandidate(access))) {
+            if (canStoreConstant(c, isCompressCandidate(null))) {
                 if (inputVal.getKind() == Kind.Object) {
-                    append(new StoreConstantOp((Kind) kind, storeAddress, c, state, config.useCompressedOops && isCompressCandidate(access)));
+                    append(new StoreConstantOp((Kind) kind, storeAddress, c, state, config.useCompressedOops && isCompressCandidate(null)));
                 } else if (inputVal.getKind() == Kind.Long) {
-                    append(new StoreConstantOp((Kind) kind, storeAddress, c, state, config.useCompressedClassPointers && isCompressCandidate(access)));
+                    append(new StoreConstantOp((Kind) kind, storeAddress, c, state, config.useCompressedClassPointers && isCompressCandidate(null)));
                 } else {
                     append(new StoreConstantOp((Kind) kind, storeAddress, c, state, false));
                 }
@@ -208,7 +213,7 @@
             }
         }
         Variable input = load(inputVal);
-        if (isCompressCandidate(access)) {
+        if (isCompressCandidate(null)) {
             if (config.useCompressedOops && kind == Kind.Object) {
                 // if (input.getKind() == Kind.Object) {
                 // Variable scratch = newVariable(Kind.Long);
@@ -261,38 +266,78 @@
         throw GraalInternalError.unimplemented();
     }
 
+    /**
+     * @param savedRegisters the registers saved by this operation which may be subject to pruning
+     * @param savedRegisterLocations the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be pruned
+     */
+    protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlot[] savedRegisterLocations, boolean supportsRemove) {
+        SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
+        append(save);
+        return save;
+    }
+
     public SaveRegistersOp emitSaveAllRegisters() {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        // We save all registers that were not saved by the save instruction.
+        // @formatter:off
+        Register[] savedRegisters = {
+                        // CPU
+                        g1, g3, g4, g5,
+                        // FPU
+                        f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
+                        f8,  f9,  f10, f11, f12, f13, f14, f15,
+                        f16, f17, f18, f19, f20, f21, f22, f23,
+                        f24, f25, f26, f27, f28, f29, f30, f31
+        };
+        // @formatter:on
+        StackSlot[] savedRegisterLocations = new StackSlot[savedRegisters.length];
+        for (int i = 0; i < savedRegisters.length; i++) {
+            PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
+            assert kind != Kind.Illegal;
+            StackSlot spillSlot = getResult().getFrameMap().allocateSpillSlot(kind);
+            savedRegisterLocations[i] = spillSlot;
+        }
+        return emitSaveRegisters(savedRegisters, savedRegisterLocations, false);
     }
 
     public void emitLeaveCurrentStackFrame() {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        append(new SPARCHotSpotLeaveCurrentStackFrameOp());
     }
 
     public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        append(new SPARCHotSpotLeaveDeoptimizedStackFrameOp());
     }
 
     public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable scratchVariable = newVariable(getHostWordKind());
+        append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable));
     }
 
     public void emitLeaveUnpackFramesStackFrame() {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new SPARCHotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset()));
     }
 
     public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        Variable frameSizeVariable = load(frameSize);
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable initialInfoVariable = load(initialInfo);
+        append(new SPARCHotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable));
     }
 
     public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP);
+
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
+        Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
+        append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister));
+        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(Kind.Long), trapRequest);
+        append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister));
+
+        return result;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pops the current frame off the stack.
+ */
+@Opcode("LEAVE_CURRENT_STACK_FRAME")
+final class SPARCHotSpotLeaveCurrentStackFrameOp extends SPARCHotSpotEpilogueOp {
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Save O registers over restore.
+        new Mov(o0, i0).emit(masm);
+        new Mov(o1, i1).emit(masm);
+        new Mov(o2, i2).emit(masm);
+        new Mov(o3, i3).emit(masm);
+        new Mov(o4, i4).emit(masm);
+
+        leaveFrame(crb);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pops the current frame off the stack including the return address.
+ */
+@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
+final class SPARCHotSpotLeaveDeoptimizedStackFrameOp extends SPARCHotSpotEpilogueOp {
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Save O registers over restore.
+        new Mov(o0, i0).emit(masm);
+        new Mov(o1, i1).emit(masm);
+        new Mov(o2, i2).emit(masm);
+        new Mov(o3, i3).emit(masm);
+        new Mov(o4, i4).emit(masm);
+
+        new RestoreWindow().emit(masm);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.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.asm.sparc.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Emits code that leaves a stack frame which is tailored to call the C++ method
+ * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
+final class SPARCHotSpotLeaveUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+
+    private final Register thread;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    private final int threadJavaFrameAnchorFlagsOffset;
+
+    SPARCHotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset) {
+        this.thread = thread;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.threadJavaFrameAnchorFlagsOffset = threadJavaFrameAnchorFlagsOffset;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        /*
+         * Safe thread register manually since we are not using LEAF_SP for {@link
+         * DeoptimizationStub#UNPACK_FRAMES}.
+         */
+        new Mov(l7, thread).emit(masm);
+
+        // Clear last Java frame values.
+        new Stx(g0, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
+        new Stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)).emit(masm);
+        new Stw(g0, new SPARCAddress(thread, threadJavaFrameAnchorFlagsOffset)).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLoweringProvider.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLoweringProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -30,7 +30,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class SPARCHotSpotLoweringProvider extends HotSpotLoweringProvider {
+public class SPARCHotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
 
     public SPARCHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
         super(runtime, metaAccess, foreignCalls, registers);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,6 @@
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
@@ -37,6 +35,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.lir.sparc.SPARCMove.CompareAndSwapOp;
 import com.oracle.graal.nodes.*;
@@ -44,8 +43,11 @@
 
 public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
+        assert gen instanceof SPARCHotSpotLIRGenerator;
+        assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
+        ((SPARCHotSpotLIRGenerator) gen).setLockStack(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());
     }
 
     @Override
@@ -60,7 +62,7 @@
 
     @Override
     public void visitSafepointNode(SafepointNode i) {
-        LIRFrameState info = gen.state(i);
+        LIRFrameState info = state(i);
         append(new SPARCHotSpotSafepointOp(info, getGen().config, gen));
     }
 
@@ -100,7 +102,7 @@
         } else {
             assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special;
             HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target();
-            assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method.";
+            assert !resolvedMethod.isAbstract() : "Cannot make direct call to abstract method.";
             append(new SPARCHotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+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.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pushes an interpreter frame to the stack.
+ */
+@Opcode("PUSH_INTERPRETER_FRAME")
+final class SPARCHotSpotPushInterpreterFrameOp extends SPARCLIRInstruction {
+
+    @Alive(REG) AllocatableValue frameSize;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Alive(REG) AllocatableValue initialInfo;
+
+    SPARCHotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo) {
+        this.frameSize = frameSize;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.initialInfo = initialInfo;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        final Register frameSizeRegister = asRegister(frameSize);
+        final Register framePcRegister = asRegister(framePc);
+        final Register senderSpRegister = asRegister(senderSp);
+
+        // Save sender SP to O5_savedSP.
+        new Mov(senderSpRegister, o5).emit(masm);
+
+        new Neg(frameSizeRegister).emit(masm);
+        new Save(sp, frameSizeRegister, sp).emit(masm);
+
+        new Mov(i0, o0).emit(masm);
+        new Mov(i1, o1).emit(masm);
+        new Mov(i2, o2).emit(masm);
+        new Mov(i3, o3).emit(masm);
+        new Mov(i4, o4).emit(masm);
+
+        // NOTE: Don't touch I5 as it contains valuable saved SP!
+
+        // Move frame's new PC into i7
+        new Mov(framePcRegister, i7).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Tue Apr 29 12:43:27 2014 -0700
@@ -98,25 +98,27 @@
 
     private static Register[] initAllocatable(boolean reserveForHeapBase) {
         Register[] registers = null;
-        // @formatter:off
         if (reserveForHeapBase) {
-            registers = new Register[] {
+            // @formatter:off
+            registers = new Register[]{
                         // TODO this is not complete
                         o0, o1, o2, o3, o4, o5, /*o6,*/ o7,
                         l0, l1, l2, l3, l4, l5, l6, l7,
                         i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/
                         f0, f1, f2, f3, f4, f5, f6, f7
-                      };
+            };
+            // @formatter:on
         } else {
-            registers = new Register[] {
+            // @formatter:off
+            registers = new Register[]{
                         // TODO this is not complete
                         o0, o1, o2, o3, o4, o5, /*o6,*/ o7,
                         l0, l1, l2, l3, l4, l5, l6, l7,
                         i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/
                         f0, f1, f2, f3, f4, f5, f6, f7
-                      };
+            };
+            // @formatter:on
         }
-       // @formatter:on
 
         if (RegisterPressure.getValue() != null) {
             String[] names = RegisterPressure.getValue().split(",");
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -33,8 +33,10 @@
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.nodes.spi.*;
+
+import edu.umd.cs.findbugs.annotations.*;
 
 /**
  * Emits a safepoint poll.
@@ -43,7 +45,7 @@
 public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction {
 
     @State protected LIRFrameState state;
-    @Temp({OperandFlag.REG}) private AllocatableValue temp;
+    @SuppressFBWarnings(value = "BC_IMPOSSIBLE_CAST", justification = "changed by the register allocator") @Temp({OperandFlag.REG}) private AllocatableValue temp;
 
     private final HotSpotVMConfig config;
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotResolvedJavaFieldTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotResolvedJavaFieldTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.meta.HotSpotResolvedObjectType.*;
-import static java.lang.reflect.Modifier.*;
 
 import java.lang.reflect.*;
 
@@ -79,7 +78,7 @@
     public void testIsInObject() {
         for (Field f : String.class.getDeclaredFields()) {
             HotSpotResolvedJavaField rf = (HotSpotResolvedJavaField) runtime().getHostProviders().getMetaAccess().lookupJavaField(f);
-            Assert.assertEquals(rf.toString(), rf.isInObject("a string"), !isStatic(rf.getModifiers()));
+            Assert.assertEquals(rf.toString(), rf.isInObject("a string"), !rf.isStatic());
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Tue Apr 29 12:43:27 2014 -0700
@@ -32,7 +32,6 @@
 
 import java.io.*;
 import java.lang.management.*;
-import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
@@ -364,7 +363,6 @@
      */
     private void printCompilation() {
         final boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
-        final int mod = method.getModifiers();
         String compilerName = "";
         if (HotSpotCIPrintCompilerName.getValue()) {
             compilerName = "Graal:";
@@ -381,9 +379,9 @@
             compLevelString = "";
         }
         boolean hasExceptionHandlers = method.getExceptionHandlers().length > 0;
-        TTY.println(String.format("%s%7d %4d %c%c%c%c%c %s      %s %s(%d bytes)", compilerName, backend.getRuntime().compilerToVm.getTimeStamp(), id, isOSR ? '%' : ' ',
-                        Modifier.isSynchronized(mod) ? 's' : ' ', hasExceptionHandlers ? '!' : ' ', blocking ? 'b' : ' ', Modifier.isNative(mod) ? 'n' : ' ', compLevelString,
-                        MetaUtil.format("%H::%n(%p)", method), isOSR ? "@ " + entryBCI + " " : "", method.getCodeSize()));
+        TTY.println(String.format("%s%7d %4d %c%c%c%c%c %s      %s %s(%d bytes)", compilerName, backend.getRuntime().compilerToVm.getTimeStamp(), id, isOSR ? '%' : ' ', method.isSynchronized() ? 's'
+                        : ' ', hasExceptionHandlers ? '!' : ' ', blocking ? 'b' : ' ', method.isNative() ? 'n' : ' ', compLevelString, MetaUtil.format("%H::%n(%p)", method), isOSR ? "@ " + entryBCI +
+                        " " : "", method.getCodeSize()));
     }
 
     private InstalledCode installMethod(final CompilationResult compResult) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.Options.*;
 
 import java.lang.reflect.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Tue Apr 29 12:43:27 2014 -0700
@@ -63,7 +63,7 @@
             try (Scope s = Debug.scope("RegisterReplacements", new DebugDumpScope("RegisterReplacements"))) {
                 ServiceLoader<ReplacementsProvider> sl = ServiceLoader.loadInstalled(ReplacementsProvider.class);
                 for (ReplacementsProvider replacementsProvider : sl) {
-                    replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, replacements, providers.getCodeCache().getTarget());
+                    replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, providers.getSnippetReflection(), replacements, providers.getCodeCache().getTarget());
                 }
                 if (BootstrapReplacements.getValue()) {
                     for (ResolvedJavaMethod method : replacements.getAllReplacements()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,11 +24,10 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.lir.gen.*;
 
 /**
  * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,8 @@
  */
 package com.oracle.graal.hotspot;
 
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSymbol.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSymbol.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.io.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -794,6 +794,7 @@
     // offsets, ...
     @HotSpotVMFlag(name = "StackShadowPages") @Stable public int stackShadowPages;
     @HotSpotVMFlag(name = "UseStackBanging") @Stable public boolean useStackBanging;
+    @HotSpotVMConstant(name = "STACK_BIAS") @Stable public int stackBias;
 
     @HotSpotVMField(name = "oopDesc::_mark", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int markOffset;
     @HotSpotVMField(name = "oopDesc::_metadata._klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int hubOffset;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVmSymbols.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVmSymbols.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import sun.misc.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Tue Apr 29 12:43:27 2014 -0700
@@ -345,7 +345,7 @@
 
     private void enqueue(Method m) throws Throwable {
         JavaMethod javaMethod = runtime.getHostProviders().getMetaAccess().lookupJavaMethod(m);
-        assert !Modifier.isAbstract(((HotSpotResolvedJavaMethod) javaMethod).getModifiers()) && !Modifier.isNative(((HotSpotResolvedJavaMethod) javaMethod).getModifiers()) : javaMethod;
+        assert !((HotSpotResolvedJavaMethod) javaMethod).isAbstract() && !((HotSpotResolvedJavaMethod) javaMethod).isNative() : javaMethod;
         compileMethod((HotSpotResolvedJavaMethod) javaMethod, StructuredGraph.INVOCATION_ENTRY_BCI, false);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Tue Apr 29 12:43:27 2014 -0700
@@ -99,7 +99,6 @@
 
     private static final boolean DUMP_STATIC = false;
 
-    public static String excludedClassPrefix = null;
     public static boolean enabled = false;
 
     public static final ConcurrentHashMap<String, Integer> indexes = new ConcurrentHashMap<>();
@@ -108,14 +107,23 @@
     public static final ArrayList<AtomicLong> staticCounters = new ArrayList<>();
 
     @SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block")
-    public static int getIndex(DynamicCounterNode counter) {
+    private static int getIndex(DynamicCounterNode counter) {
         if (!enabled) {
             throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName());
         }
-        String name = counter.getName();
+        String name;
         String group = counter.getGroup();
-        name = counter.isWithContext() && counter.graph().method() != null ? name + " @ " + counter.graph().graphId() + ":" + MetaUtil.format("%h.%n", counter.graph().method()) + "#" + group : name +
-                        "#" + group;
+        if (counter.isWithContext()) {
+            StructuredGraph graph = counter.graph();
+            name = counter.getName() + " @ " + graph.graphId() + ":" + (graph.method() == null ? "" : MetaUtil.format("%h.%n", graph.method()));
+            if (graph.name != null) {
+                name += " (" + graph.name + ")";
+            }
+            name += "#" + group;
+
+        } else {
+            name = counter.getName() + "#" + group;
+        }
         Integer index = indexes.get(name);
         if (index == null) {
             synchronized (BenchmarkCounters.class) {
@@ -135,7 +143,7 @@
         return index;
     }
 
-    public static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) {
+    private static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) {
         if (!groups.isEmpty()) {
             out.println("====== dynamic counters (" + staticCounters.size() + " in total) ======");
             for (String group : new TreeSet<>(groups)) {
@@ -152,7 +160,7 @@
         }
     }
 
-    public static synchronized void clear(long[] counters) {
+    private static synchronized void clear(long[] counters) {
         delta = counters;
     }
 
@@ -228,7 +236,7 @@
         return (counter * 200 + 1) / sum / 2;
     }
 
-    public abstract static class CallbackOutputStream extends OutputStream {
+    private abstract static class CallbackOutputStream extends OutputStream {
 
         protected final PrintStream delegate;
         private final byte[][] patterns;
@@ -281,25 +289,30 @@
         final class BenchmarkCountersOutputStream extends CallbackOutputStream {
 
             private long startTime;
+            private boolean running;
             private boolean waitingForEnd;
 
             private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) {
-                super(delegate, new String[]{start, end, "\n"});
+                super(delegate, new String[]{"\n", end, start});
             }
 
             @Override
             protected void patternFound(int index) {
                 switch (index) {
-                    case 0:
+                    case 2:
                         startTime = System.nanoTime();
                         BenchmarkCounters.clear(compilerToVM.collectCounters());
+                        running = true;
                         break;
                     case 1:
-                        waitingForEnd = true;
+                        if (running) {
+                            waitingForEnd = true;
+                        }
                         break;
-                    case 2:
+                    case 0:
                         if (waitingForEnd) {
                             waitingForEnd = false;
+                            running = false;
                             BenchmarkCounters.dump(delegate, (System.nanoTime() - startTime) / 1000000000d, compilerToVM.collectCounters(), 100);
                         }
                         break;
@@ -321,7 +334,6 @@
                     throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: err|out");
                 }
             }
-            excludedClassPrefix = "Lcom/oracle/graal/";
             enabled = true;
         }
         if (Options.GenericDynamicCounters.getValue()) {
@@ -363,26 +375,24 @@
 
     public static void lower(DynamicCounterNode counter, HotSpotRegistersProvider registers, HotSpotVMConfig config, Kind wordKind) {
         StructuredGraph graph = counter.graph();
-        if (excludedClassPrefix == null || (counter.graph().method() != null && !counter.graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix))) {
 
-            ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false));
+        ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false));
 
-            int index = BenchmarkCounters.getIndex(counter);
-            if (index >= config.graalCountersSize) {
-                throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")");
-            }
-            ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, config.graalCountersThreadOffset, graph);
-            ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false));
-            ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph);
-            ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false));
-            IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement()));
-            WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false));
+        int index = BenchmarkCounters.getIndex(counter);
+        if (index >= config.graalCountersSize) {
+            throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")");
+        }
+        ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, wordKind, config.graalCountersThreadOffset, graph);
+        ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false));
+        ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph);
+        ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false));
+        IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement()));
+        WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false));
 
-            graph.addBeforeFixed(counter, thread);
-            graph.addBeforeFixed(counter, readArray);
-            graph.addBeforeFixed(counter, read);
-            graph.addBeforeFixed(counter, write);
-        }
+        graph.addBeforeFixed(counter, thread);
+        graph.addBeforeFixed(counter, readArray);
+        graph.addBeforeFixed(counter, read);
+        graph.addBeforeFixed(counter, write);
         graph.removeFixed(counter);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,1028 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.meta;
+
+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.compiler.common.GraalOptions.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
+import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.debug.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.nodes.type.*;
+import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.extended.*;
+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.virtual.*;
+import com.oracle.graal.replacements.*;
+
+/**
+ * HotSpot implementation of {@link LoweringProvider}.
+ */
+public class DefaultHotSpotLoweringProvider implements HotSpotLoweringProvider {
+
+    protected final HotSpotGraalRuntime runtime;
+    protected final MetaAccessProvider metaAccess;
+    protected final ForeignCallsProvider foreignCalls;
+    protected final HotSpotRegistersProvider registers;
+
+    protected CheckCastDynamicSnippets.Templates checkcastDynamicSnippets;
+    protected InstanceOfSnippets.Templates instanceofSnippets;
+    protected NewObjectSnippets.Templates newObjectSnippets;
+    protected MonitorSnippets.Templates monitorSnippets;
+    protected WriteBarrierSnippets.Templates writeBarrierSnippets;
+    protected BoxingSnippets.Templates boxingSnippets;
+    protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
+    protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
+
+    public DefaultHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
+        this.runtime = runtime;
+        this.metaAccess = metaAccess;
+        this.foreignCalls = foreignCalls;
+        this.registers = registers;
+    }
+
+    public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
+        TargetDescription target = providers.getCodeCache().getTarget();
+        checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target);
+        instanceofSnippets = new InstanceOfSnippets.Templates(providers, target);
+        newObjectSnippets = new NewObjectSnippets.Templates(providers, target);
+        monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking);
+        writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
+        boxingSnippets = new BoxingSnippets.Templates(providers, providers.getSnippetReflection(), target);
+        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
+        unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
+        providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        StructuredGraph graph = (StructuredGraph) n.graph();
+
+        if (n instanceof ArrayLengthNode) {
+            lowerArrayLengthNode((ArrayLengthNode) n, tool);
+        } else if (n instanceof Invoke) {
+            lowerInvoke((Invoke) n, tool, graph);
+        } else if (n instanceof LoadFieldNode) {
+            lowerLoadFieldNode((LoadFieldNode) n, tool);
+        } else if (n instanceof StoreFieldNode) {
+            lowerStoreFieldNode((StoreFieldNode) n, tool);
+        } else if (n instanceof CompareAndSwapNode) {
+            lowerCompareAndSwapNode((CompareAndSwapNode) n);
+        } else if (n instanceof AtomicReadAndWriteNode) {
+            lowerAtomicReadAndWriteNode((AtomicReadAndWriteNode) n);
+        } else if (n instanceof LoadIndexedNode) {
+            lowerLoadIndexedNode((LoadIndexedNode) n, tool);
+        } else if (n instanceof StoreIndexedNode) {
+            lowerStoreIndexedNode((StoreIndexedNode) n, tool);
+        } else if (n instanceof UnsafeLoadNode) {
+            lowerUnsafeLoadNode((UnsafeLoadNode) n, tool);
+        } else if (n instanceof UnsafeStoreNode) {
+            lowerUnsafeStoreNode((UnsafeStoreNode) n);
+        } else if (n instanceof JavaReadNode) {
+            lowerJavaReadNode((JavaReadNode) n);
+        } else if (n instanceof JavaWriteNode) {
+            lowerJavaWriteNode((JavaWriteNode) n);
+        } else if (n instanceof LoadHubNode) {
+            lowerLoadHubNode((LoadHubNode) n);
+        } else if (n instanceof LoadMethodNode) {
+            lowerLoadMethodNode((LoadMethodNode) n);
+        } else if (n instanceof StoreHubNode) {
+            lowerStoreHubNode((StoreHubNode) n, graph);
+        } else if (n instanceof CommitAllocationNode) {
+            lowerCommitAllocationNode((CommitAllocationNode) n, tool);
+        } else if (n instanceof OSRStartNode) {
+            lowerOSRStartNode((OSRStartNode) n);
+        } else if (n instanceof DynamicCounterNode) {
+            lowerDynamicCounterNode((DynamicCounterNode) n);
+        } else if (n instanceof BytecodeExceptionNode) {
+            lowerBytecodeExceptionNode((BytecodeExceptionNode) n);
+        } else if (n instanceof CheckCastDynamicNode) {
+            checkcastDynamicSnippets.lower((CheckCastDynamicNode) n, tool);
+        } else if (n instanceof InstanceOfNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                instanceofSnippets.lower((InstanceOfNode) n, tool);
+            }
+        } else if (n instanceof InstanceOfDynamicNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
+            }
+        } else if (n instanceof NewInstanceNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewInstanceNode) n, registers, tool);
+            }
+        } else if (n instanceof DynamicNewInstanceNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((DynamicNewInstanceNode) n, registers, tool);
+            }
+        } else if (n instanceof NewArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewArrayNode) n, registers, tool);
+            }
+        } else if (n instanceof DynamicNewArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((DynamicNewArrayNode) n, registers, tool);
+            }
+        } else if (n instanceof MonitorEnterNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                monitorSnippets.lower((MonitorEnterNode) n, registers, tool);
+            }
+        } else if (n instanceof MonitorExitNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                monitorSnippets.lower((MonitorExitNode) n, tool);
+            }
+        } else if (n instanceof G1PreWriteBarrier) {
+            writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1PostWriteBarrier) {
+            writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1ReferentFieldReadBarrier) {
+            writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool);
+        } else if (n instanceof SerialWriteBarrier) {
+            writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
+        } else if (n instanceof SerialArrayRangeWriteBarrier) {
+            writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
+        } else if (n instanceof G1ArrayRangePreWriteBarrier) {
+            writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1ArrayRangePostWriteBarrier) {
+            writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool);
+        } else if (n instanceof NewMultiArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewMultiArrayNode) n, tool);
+            }
+        } else if (n instanceof ExceptionObjectNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                lowerExceptionObjectNode((ExceptionObjectNode) n, tool);
+            }
+        } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
+            // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
+            // zero and the MIN_VALUE / -1 cases.
+        } else if (n instanceof BoxNode) {
+            boxingSnippets.lower((BoxNode) n, tool);
+        } else if (n instanceof UnboxNode) {
+            boxingSnippets.lower((UnboxNode) n, tool);
+        } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode) {
+            /* No lowering, we generate LIR directly for these nodes. */
+        } else {
+            throw GraalInternalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
+        }
+    }
+
+    private void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) {
+        StructuredGraph graph = arrayLengthNode.graph();
+        ValueNode array = arrayLengthNode.array();
+        ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, graph),
+                        StampFactory.positiveInt(), BarrierType.NONE, false));
+        arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool));
+        graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
+    }
+
+    private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) {
+        if (invoke.callTarget() instanceof MethodCallTargetNode) {
+            MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+            NodeInputList<ValueNode> parameters = callTarget.arguments();
+            ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
+            GuardingNode receiverNullCheck = null;
+            if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !StampTool.isObjectNonNull(receiver)) {
+                receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
+                invoke.setGuard(receiverNullCheck);
+            }
+            JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
+
+            LoweredCallTargetNode loweredCallTarget = null;
+            if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
+
+                HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
+                if (!hsMethod.getDeclaringClass().isInterface()) {
+                    if (hsMethod.isInVirtualMethodTable()) {
+                        int vtableEntryOffset = hsMethod.vtableEntryOffset();
+                        assert vtableEntryOffset > 0;
+                        Kind wordKind = runtime.getTarget().wordKind;
+                        ValueNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
+
+                        ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
+                        // We use LocationNode.ANY_LOCATION for the reads that access the
+                        // compiled code entry as HotSpot does not guarantee they are final
+                        // values.
+                        ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph),
+                                        StampFactory.forKind(wordKind), BarrierType.NONE, false));
+
+                        loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
+                                        CallingConvention.Type.JavaCall));
+
+                        graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
+                        graph.addAfterFixed(metaspaceMethod, compiledEntry);
+                    }
+                }
+            }
+
+            if (loweredCallTarget == null) {
+                loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
+                                callTarget.invokeKind()));
+            }
+            callTarget.replaceAndDelete(loweredCallTarget);
+        }
+    }
+
+    private Stamp loadStamp(Stamp stamp, Kind kind) {
+        return loadStamp(stamp, kind, true);
+    }
+
+    private Stamp loadStamp(Stamp stamp, Kind kind, boolean compressible) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+                return StampTool.narrowingConversion(stamp, 8);
+
+            case Char:
+            case Short:
+                return StampTool.narrowingConversion(stamp, 16);
+
+            case Object:
+                if (compressible && runtime.getConfig().useCompressedOops) {
+                    return new NarrowOopStamp((ObjectStamp) stamp, runtime.getConfig().getOopEncoding());
+                }
+        }
+        return stamp;
+    }
+
+    public ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value) {
+        return implicitLoadConvert(graph, kind, value, true);
+    }
+
+    private ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
+        switch (kind) {
+            case Byte:
+            case Short:
+                return graph.unique(new SignExtendNode(value, 32));
+
+            case Boolean:
+            case Char:
+                return graph.unique(new ZeroExtendNode(value, 32));
+
+            case Object:
+                if (compressible && runtime.getConfig().useCompressedOops) {
+                    return CompressionNode.uncompress(value, runtime.getConfig().getOopEncoding());
+                }
+        }
+        return value;
+    }
+
+    private void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
+        StructuredGraph graph = loadField.graph();
+        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
+        ValueNode object = loadField.isStatic() ? ConstantNode.forConstant(HotSpotObjectConstant.forObject(field.getDeclaringClass().mirror()), metaAccess, graph) : loadField.object();
+        assert loadField.getKind() != Kind.Illegal;
+        BarrierType barrierType = getFieldLoadBarrierType(field);
+
+        Stamp loadStamp = loadStamp(loadField.stamp(), field.getKind());
+        ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadStamp, barrierType, false));
+        ValueNode readValue = implicitLoadConvert(graph, field.getKind(), memoryRead);
+
+        loadField.replaceAtUsages(readValue);
+        graph.replaceFixed(loadField, memoryRead);
+
+        memoryRead.setGuard(createNullCheck(object, memoryRead, tool));
+
+        if (loadField.isVolatile()) {
+            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
+            graph.addBeforeFixed(memoryRead, preMembar);
+            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
+            graph.addAfterFixed(memoryRead, postMembar);
+        }
+    }
+
+    public ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value) {
+        return implicitStoreConvert(graph, kind, value, true);
+    }
+
+    private ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+                return graph.unique(new NarrowNode(value, 8));
+            case Char:
+            case Short:
+                return graph.unique(new NarrowNode(value, 16));
+            case Object:
+                if (compressible && runtime.getConfig().useCompressedOops) {
+                    return CompressionNode.compress(value, runtime.getConfig().getOopEncoding());
+                }
+        }
+        return value;
+    }
+
+    private void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
+        StructuredGraph graph = storeField.graph();
+        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
+        ValueNode object = storeField.isStatic() ? ConstantNode.forConstant(HotSpotObjectConstant.forObject(field.getDeclaringClass().mirror()), metaAccess, graph) : storeField.object();
+        BarrierType barrierType = getFieldStoreBarrierType(storeField);
+
+        ValueNode value = implicitStoreConvert(graph, storeField.field().getKind(), storeField.value());
+        WriteNode memoryWrite = graph.add(new WriteNode(object, value, createFieldLocation(graph, field, false), barrierType, false));
+        memoryWrite.setStateAfter(storeField.stateAfter());
+        graph.replaceFixedWithFixed(storeField, memoryWrite);
+        memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool));
+        FixedWithNextNode last = memoryWrite;
+        FixedWithNextNode first = memoryWrite;
+
+        if (storeField.isVolatile()) {
+            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+            graph.addBeforeFixed(first, preMembar);
+            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
+            graph.addAfterFixed(last, postMembar);
+        }
+    }
+
+    private void lowerCompareAndSwapNode(CompareAndSwapNode cas) {
+        StructuredGraph graph = cas.graph();
+        Kind valueKind = cas.getValueKind();
+        LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), valueKind, cas.displacement(), cas.offset(), graph, 1);
+
+        ValueNode expectedValue = implicitStoreConvert(graph, valueKind, cas.expected(), true);
+        ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue(), true);
+
+        LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, expectedValue, newValue, getCompareAndSwapBarrierType(cas), false));
+        atomicNode.setStateAfter(cas.stateAfter());
+        graph.replaceFixedWithFixed(cas, atomicNode);
+    }
+
+    private void lowerAtomicReadAndWriteNode(AtomicReadAndWriteNode n) {
+        StructuredGraph graph = n.graph();
+        Kind valueKind = n.getValueKind();
+        LocationNode location = IndexedLocationNode.create(n.getLocationIdentity(), valueKind, 0, n.offset(), graph, 1);
+
+        ValueNode newValue = implicitStoreConvert(graph, valueKind, n.newValue());
+
+        LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(n.object(), location, newValue, getAtomicReadAndWriteBarrierType(n), false));
+        memoryRead.setStateAfter(n.stateAfter());
+
+        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead);
+
+        n.replaceAtUsages(readValue);
+        graph.replaceFixedWithFixed(n, memoryRead);
+    }
+
+    private void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) {
+        StructuredGraph graph = loadIndexed.graph();
+        Kind elementKind = loadIndexed.elementKind();
+        LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
+
+        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
+        ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadStamp, BarrierType.NONE, false));
+        ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
+
+        memoryRead.setGuard(createBoundsCheck(loadIndexed, tool));
+
+        loadIndexed.replaceAtUsages(readValue);
+        graph.replaceFixed(loadIndexed, memoryRead);
+    }
+
+    private void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
+        StructuredGraph graph = storeIndexed.graph();
+        GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
+        Kind elementKind = storeIndexed.elementKind();
+        LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false);
+
+        ValueNode value = storeIndexed.value();
+        ValueNode array = storeIndexed.array();
+
+        CheckCastNode checkcastNode = null;
+        CheckCastDynamicNode checkcastDynamicNode = null;
+        if (elementKind == Kind.Object && !StampTool.isObjectAlwaysNull(value)) {
+            // Store check!
+            ResolvedJavaType arrayType = StampTool.typeOrNull(array);
+            if (arrayType != null && StampTool.isExactType(array)) {
+                ResolvedJavaType elementType = arrayType.getComponentType();
+                if (!MetaUtil.isJavaLangObject(elementType)) {
+                    checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true));
+                    graph.addBeforeFixed(storeIndexed, checkcastNode);
+                    value = checkcastNode;
+                }
+            } else {
+                Kind wordKind = runtime.getTarget().wordKind;
+                ValueNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck);
+                LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, runtime.getConfig().arrayClassElementOffset, graph);
+                /*
+                 * Anchor the read of the element klass to the cfg, because it is only valid when
+                 * arrayClass is an object class, which might not be the case in other parts of the
+                 * compiled method.
+                 */
+                FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed)));
+                checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
+                graph.addBeforeFixed(storeIndexed, checkcastDynamicNode);
+                value = checkcastDynamicNode;
+            }
+        }
+        BarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
+        WriteNode memoryWrite = graph.add(new WriteNode(array, implicitStoreConvert(graph, elementKind, value), arrayLocation, barrierType, false));
+        memoryWrite.setGuard(boundsCheck);
+        memoryWrite.setStateAfter(storeIndexed.stateAfter());
+        graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
+
+        // Lower the associated checkcast node.
+        if (checkcastNode != null) {
+            checkcastNode.lower(tool);
+        } else if (checkcastDynamicNode != null) {
+            checkcastDynamicSnippets.lower(checkcastDynamicNode, tool);
+        }
+    }
+
+    private ReadNode createUnsafeRead(StructuredGraph graph, UnsafeLoadNode load, GuardingNode guard) {
+        boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
+        Kind readKind = load.accessKind();
+        LocationNode location = createLocation(load);
+        Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible);
+        ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, loadStamp, guard, BarrierType.NONE, false));
+        ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, compressible);
+        load.replaceAtUsages(readValue);
+        return memoryRead;
+    }
+
+    private void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) {
+        StructuredGraph graph = load.graph();
+        if (load.getGuardingCondition() != null) {
+            ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition()));
+            ReadNode memoryRead = createUnsafeRead(graph, load, valueAnchorNode);
+            graph.replaceFixedWithFixed(load, valueAnchorNode);
+            graph.addAfterFixed(valueAnchorNode, memoryRead);
+        } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
+            assert load.getKind() != Kind.Illegal;
+            if (addReadBarrier(load)) {
+                unsafeLoadSnippets.lower(load, tool);
+            } else {
+                ReadNode memoryRead = createUnsafeRead(graph, load, null);
+                // An unsafe read must not float outside its block otherwise
+                // it may float above an explicit null check on its object.
+                memoryRead.setGuard(BeginNode.prevBegin(load));
+                graph.replaceFixedWithFixed(load, memoryRead);
+            }
+        }
+    }
+
+    private void lowerUnsafeStoreNode(UnsafeStoreNode store) {
+        StructuredGraph graph = store.graph();
+        LocationNode location = createLocation(store);
+        ValueNode object = store.object();
+        BarrierType barrierType = getUnsafeStoreBarrierType(store);
+        boolean compressible = store.value().getKind() == Kind.Object;
+        Kind valueKind = store.accessKind();
+        ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible);
+        WriteNode write = graph.add(new WriteNode(object, value, location, barrierType, false));
+        write.setStateAfter(store.stateAfter());
+        graph.replaceFixedWithFixed(store, write);
+    }
+
+    private void lowerJavaReadNode(JavaReadNode read) {
+        StructuredGraph graph = read.graph();
+
+        Kind valueKind = read.location().getValueKind();
+        Stamp loadStamp = loadStamp(read.stamp(), valueKind, read.isCompressible());
+        ReadNode memoryRead = graph.add(new ReadNode(read.object(), read.location(), loadStamp, read.getBarrierType(), false));
+        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead, read.isCompressible());
+
+        memoryRead.setGuard(read.getGuard());
+
+        read.replaceAtUsages(readValue);
+        graph.replaceFixed(read, memoryRead);
+    }
+
+    private void lowerJavaWriteNode(JavaWriteNode write) {
+        StructuredGraph graph = write.graph();
+
+        Kind valueKind = write.location().getValueKind();
+        ValueNode value = implicitStoreConvert(graph, valueKind, write.value(), write.isCompressible());
+
+        WriteNode memoryWrite = graph.add(new WriteNode(write.object(), value, write.location(), write.getBarrierType(), false, write.isInitialization()));
+        memoryWrite.setStateAfter(write.stateAfter());
+        graph.replaceFixedWithFixed(write, memoryWrite);
+
+        memoryWrite.setGuard(write.getGuard());
+    }
+
+    private void lowerLoadHubNode(LoadHubNode loadHub) {
+        StructuredGraph graph = loadHub.graph();
+        if (graph.getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) {
+            Kind wordKind = runtime.getTarget().wordKind;
+            assert loadHub.getKind() == wordKind;
+            ValueNode object = loadHub.object();
+            GuardingNode guard = loadHub.getGuard();
+            ValueNode hub = createReadHub(graph, wordKind, object, guard);
+            graph.replaceFloating(loadHub, hub);
+        }
+    }
+
+    private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
+        StructuredGraph graph = loadMethodNode.graph();
+        ResolvedJavaMethod method = loadMethodNode.getMethod();
+        ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method);
+        graph.replaceFixed(loadMethodNode, metaspaceMethod);
+    }
+
+    private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) {
+        WriteNode hub = createWriteHub(graph, runtime.getTarget().wordKind, storeHub.getObject(), storeHub.getValue());
+        graph.replaceFixed(storeHub, hub);
+    }
+
+    private void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
+        StructuredGraph graph = commit.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
+            BitSet omittedValues = new BitSet();
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+                FixedWithNextNode newObject;
+                if (virtual instanceof VirtualInstanceNode) {
+                    newObject = graph.add(new NewInstanceNode(virtual.type(), true));
+                } else {
+                    newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true));
+                }
+                graph.addBeforeFixed(commit, newObject);
+                allocations[objIndex] = newObject;
+                for (int i = 0; i < entryCount; i++) {
+                    ValueNode value = commit.getValues().get(valuePos);
+                    if (value instanceof VirtualObjectNode) {
+                        value = allocations[commit.getVirtualObjects().indexOf(value)];
+                    }
+                    if (value == null) {
+                        omittedValues.set(valuePos);
+                    } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
+                        // Constant.illegal is always the defaultForKind, so it is skipped
+                        Kind valueKind = value.getKind();
+                        Kind entryKind = virtual.entryKind(i);
+
+                        // Truffle requires some leniency in terms of what can be put where:
+                        Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind;
+                        assert valueKind.getStackKind() == entryKind.getStackKind() ||
+                                        (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode));
+                        ConstantLocationNode location;
+                        BarrierType barrierType;
+                        if (virtual instanceof VirtualInstanceNode) {
+                            ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
+                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, ((HotSpotResolvedJavaField) field).offset(), graph);
+                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
+                        } else {
+                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(entryKind) + i * getScalingFactor(entryKind), graph);
+                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE;
+                        }
+                        WriteNode write = new WriteNode(newObject, implicitStoreConvert(graph, entryKind, value), location, barrierType, false);
+                        graph.addAfterFixed(newObject, graph.add(write));
+                    }
+                    valuePos++;
+
+                }
+            }
+            valuePos = 0;
+
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+                ValueNode newObject = allocations[objIndex];
+                for (int i = 0; i < entryCount; i++) {
+                    if (omittedValues.get(valuePos)) {
+                        ValueNode value = commit.getValues().get(valuePos);
+                        assert value instanceof VirtualObjectNode;
+                        ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
+                        if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
+                            assert virtual.entryKind(i) == Kind.Object && allocValue.getKind() == Kind.Object;
+                            WriteNode write;
+                            if (virtual instanceof VirtualInstanceNode) {
+                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
+                                write = new WriteNode(newObject, implicitStoreConvert(graph, Kind.Object, allocValue), createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i),
+                                                true), BarrierType.IMPRECISE, false);
+                            } else {
+                                write = new WriteNode(newObject, implicitStoreConvert(graph, Kind.Object, allocValue), createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph),
+                                                true), BarrierType.PRECISE, false);
+                            }
+                            graph.addBeforeFixed(commit, graph.add(write));
+                        }
+                    }
+                    valuePos++;
+                }
+            }
+
+            finishAllocatedObjects(tool, commit, allocations);
+            graph.removeFixed(commit);
+        }
+    }
+
+    private void lowerOSRStartNode(OSRStartNode osrStart) {
+        StructuredGraph graph = osrStart.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            StartNode newStart = graph.add(new StartNode());
+            ParameterNode buffer = graph.unique(new ParameterNode(0, StampFactory.forKind(runtime.getTarget().wordKind)));
+            ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
+            migrationEnd.setStateAfter(osrStart.stateAfter());
+
+            newStart.setNext(migrationEnd);
+            FixedNode next = osrStart.next();
+            osrStart.setNext(null);
+            migrationEnd.setNext(next);
+            graph.setStart(newStart);
+
+            // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
+            int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
+            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
+                int size = HIRFrameStateBuilder.stackSlots(osrLocal.getKind());
+                int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
+                IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.getKind(), offset, ConstantNode.forLong(0, graph), graph, 1);
+                ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false));
+                osrLocal.replaceAndDelete(load);
+                graph.addBeforeFixed(migrationEnd, load);
+            }
+            osrStart.replaceAtUsages(newStart);
+            osrStart.safeDelete();
+        }
+    }
+
+    private void lowerDynamicCounterNode(DynamicCounterNode n) {
+        StructuredGraph graph = n.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+            BenchmarkCounters.lower(n, registers, runtime.getConfig(), runtime.getTarget().wordKind);
+        }
+    }
+
+    static final class Exceptions {
+        protected static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException;
+        protected static final NullPointerException cachedNullPointerException;
+
+        static {
+            cachedArrayIndexOutOfBoundsException = new ArrayIndexOutOfBoundsException();
+            cachedArrayIndexOutOfBoundsException.setStackTrace(new StackTraceElement[0]);
+            cachedNullPointerException = new NullPointerException();
+            cachedNullPointerException.setStackTrace(new StackTraceElement[0]);
+        }
+    }
+
+    public static final class RuntimeCalls {
+        public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", NullPointerException.class);
+        public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class);
+    }
+
+    private void lowerBytecodeExceptionNode(BytecodeExceptionNode node) {
+        StructuredGraph graph = node.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
+            if (OmitHotExceptionStacktrace.getValue()) {
+                Throwable exception;
+                if (node.getExceptionClass() == NullPointerException.class) {
+                    exception = Exceptions.cachedNullPointerException;
+                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
+                    exception = Exceptions.cachedArrayIndexOutOfBoundsException;
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+                FloatingNode exceptionNode = ConstantNode.forConstant(HotSpotObjectConstant.forObject(exception), metaAccess, graph);
+                graph.replaceFixedWithFloating(node, exceptionNode);
+
+            } else {
+                ForeignCallDescriptor descriptor;
+                if (node.getExceptionClass() == NullPointerException.class) {
+                    descriptor = RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION;
+                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
+                    descriptor = RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION;
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+
+                ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, descriptor, node.stamp(), node.getArguments()));
+                graph.replaceFixedWithFixed(node, foreignCallNode);
+            }
+        }
+    }
+
+    private void lowerExceptionObjectNode(ExceptionObjectNode n, LoweringTool tool) {
+        LocationIdentity locationsKilledByInvoke = ((InvokeWithExceptionNode) n.predecessor()).getLocationIdentity();
+        BeginNode entry = n.graph().add(new KillingBeginNode(locationsKilledByInvoke));
+        LoadExceptionObjectNode loadException = n.graph().add(new LoadExceptionObjectNode(StampFactory.declaredNonNull(metaAccess.lookupJavaType(Throwable.class))));
+
+        loadException.setStateAfter(n.stateAfter());
+        n.replaceAtUsages(InputType.Value, loadException);
+        n.graph().replaceFixedWithFixed(n, entry);
+        entry.graph().addAfterFixed(entry, loadException);
+
+        exceptionObjectSnippets.lower(loadException, registers, tool);
+    }
+
+    public static void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
+        StructuredGraph graph = commit.graph();
+        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+            FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
+            allocations[objIndex] = anchor;
+            graph.addBeforeFixed(commit, anchor);
+        }
+        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+            for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
+                MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
+                graph.addBeforeFixed(commit, enter);
+                enter.lower(tool);
+            }
+        }
+        for (Node usage : commit.usages().snapshot()) {
+            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+            int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
+            graph.replaceFloating(addObject, allocations[index]);
+        }
+    }
+
+    private static LocationNode createLocation(UnsafeAccessNode access) {
+        return createLocation(access.offset(), access.getLocationIdentity(), access.accessKind());
+    }
+
+    private static LocationNode createLocation(ValueNode offsetNode, LocationIdentity locationIdentity, Kind accessKind) {
+        ValueNode offset = offsetNode;
+        if (offset.isConstant()) {
+            long offsetValue = offset.asConstant().asLong();
+            return ConstantLocationNode.create(locationIdentity, accessKind, offsetValue, offset.graph());
+        }
+
+        long displacement = 0;
+        int indexScaling = 1;
+        boolean signExtend = false;
+        if (offset instanceof SignExtendNode) {
+            SignExtendNode extend = (SignExtendNode) offset;
+            if (extend.getResultBits() == 64) {
+                signExtend = true;
+                offset = extend.getInput();
+            }
+        }
+        if (offset instanceof IntegerAddNode) {
+            IntegerAddNode integerAddNode = (IntegerAddNode) offset;
+            if (integerAddNode.y() instanceof ConstantNode) {
+                displacement = integerAddNode.y().asConstant().asLong();
+                offset = integerAddNode.x();
+            }
+        }
+
+        if (offset instanceof LeftShiftNode) {
+            LeftShiftNode leftShiftNode = (LeftShiftNode) offset;
+            if (leftShiftNode.y() instanceof ConstantNode) {
+                long shift = leftShiftNode.y().asConstant().asLong();
+                if (shift >= 1 && shift <= 3) {
+                    if (shift == 1) {
+                        indexScaling = 2;
+                    } else if (shift == 2) {
+                        indexScaling = 4;
+                    } else {
+                        indexScaling = 8;
+                    }
+                    offset = leftShiftNode.x();
+                }
+            }
+        }
+        if (signExtend) {
+            // If we were using sign extended values before restore the sign extension.
+            offset = offset.graph().addOrUnique(new SignExtendNode(offset, 64));
+        }
+        return IndexedLocationNode.create(locationIdentity, accessKind, displacement, offset, offset.graph(), indexScaling);
+    }
+
+    private static boolean addReadBarrier(UnsafeLoadNode load) {
+        if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getKind() == Kind.Object && load.accessKind() == Kind.Object &&
+                        !StampTool.isObjectAlwaysNull(load.object())) {
+            ResolvedJavaType type = StampTool.typeOrNull(load.object());
+            if (type != null && !type.isArray()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
+        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
+        assert !hsMethod.getDeclaringClass().isInterface();
+        assert hsMethod.isInVirtualMethodTable();
+
+        int vtableEntryOffset = hsMethod.vtableEntryOffset();
+        assert vtableEntryOffset > 0;
+        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
+        // entry as HotSpot does not guarantee that this is a final value.
+        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind), BarrierType.NONE, false));
+        return metaspaceMethod;
+    }
+
+    private ValueNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object, GuardingNode guard) {
+        HotSpotVMConfig config = runtime.getConfig();
+        LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph);
+        assert !object.isConstant() || object.asConstant().isNull();
+
+        Stamp hubStamp;
+        if (config.useCompressedClassPointers) {
+            hubStamp = StampFactory.forInteger(32);
+        } else {
+            hubStamp = StampFactory.forKind(wordKind);
+        }
+
+        FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(object, location, null, hubStamp, guard, BarrierType.NONE, false));
+        if (config.useCompressedClassPointers) {
+            return CompressionNode.uncompress(memoryRead, config.getKlassEncoding());
+        } else {
+            return memoryRead;
+        }
+    }
+
+    private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) {
+        HotSpotVMConfig config = runtime.getConfig();
+        LocationNode location = ConstantLocationNode.create(HUB_LOCATION, wordKind, config.hubOffset, graph);
+        assert !object.isConstant() || object.asConstant().isNull();
+
+        ValueNode writeValue = value;
+        if (config.useCompressedClassPointers) {
+            writeValue = CompressionNode.compress(value, config.getKlassEncoding());
+        }
+
+        return graph.add(new WriteNode(object, writeValue, location, BarrierType.NONE, false));
+    }
+
+    private static BarrierType getFieldLoadBarrierType(HotSpotResolvedJavaField loadField) {
+        BarrierType barrierType = BarrierType.NONE;
+        if (config().useG1GC && loadField.getKind() == Kind.Object && loadField.getDeclaringClass().mirror() == java.lang.ref.Reference.class && loadField.getName().equals("referent")) {
+            barrierType = BarrierType.PRECISE;
+        }
+        return barrierType;
+    }
+
+    private static BarrierType getFieldStoreBarrierType(StoreFieldNode storeField) {
+        if (storeField.field().getKind() == Kind.Object) {
+            return BarrierType.IMPRECISE;
+        }
+        return BarrierType.NONE;
+    }
+
+    private static BarrierType getArrayStoreBarrierType(StoreIndexedNode store) {
+        if (store.elementKind() == Kind.Object) {
+            return BarrierType.PRECISE;
+        }
+        return BarrierType.NONE;
+    }
+
+    private static BarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) {
+        if (store.value().getKind() == Kind.Object) {
+            ResolvedJavaType type = StampTool.typeOrNull(store.object());
+            if (type != null && !type.isArray()) {
+                return BarrierType.IMPRECISE;
+            } else {
+                return BarrierType.PRECISE;
+            }
+        }
+        return BarrierType.NONE;
+    }
+
+    private static BarrierType getCompareAndSwapBarrierType(CompareAndSwapNode cas) {
+        if (cas.expected().getKind() == Kind.Object) {
+            ResolvedJavaType type = StampTool.typeOrNull(cas.object());
+            if (type != null && !type.isArray()) {
+                return BarrierType.IMPRECISE;
+            } else {
+                return BarrierType.PRECISE;
+            }
+        }
+        return BarrierType.NONE;
+    }
+
+    private static BarrierType getAtomicReadAndWriteBarrierType(AtomicReadAndWriteNode n) {
+        if (n.newValue().getKind() == Kind.Object) {
+            ResolvedJavaType type = StampTool.typeOrNull(n.object());
+            if (type != null && !type.isArray()) {
+                return BarrierType.IMPRECISE;
+            } else {
+                return BarrierType.PRECISE;
+            }
+        }
+        return BarrierType.NONE;
+    }
+
+    protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field, boolean initialization) {
+        LocationIdentity loc = initialization ? INIT_LOCATION : field;
+        return ConstantLocationNode.create(loc, field.getKind(), field.offset(), graph);
+    }
+
+    public int getScalingFactor(Kind kind) {
+        if (useCompressedOops() && kind == Kind.Object) {
+            return this.runtime.getTarget().getSizeInBytes(Kind.Int);
+        } else {
+            return this.runtime.getTarget().getSizeInBytes(kind);
+        }
+    }
+
+    @Override
+    public IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) {
+        LocationIdentity loc = initialization ? INIT_LOCATION : NamedLocationIdentity.getArrayLocation(elementKind);
+        int scale = getScalingFactor(elementKind);
+        return IndexedLocationNode.create(loc, elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
+    }
+
+    @Override
+    public ValueNode reconstructArrayIndex(LocationNode location) {
+        Kind elementKind = location.getValueKind();
+        assert location.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind));
+
+        long base;
+        ValueNode index;
+        int scale = getScalingFactor(elementKind);
+
+        if (location instanceof ConstantLocationNode) {
+            base = ((ConstantLocationNode) location).getDisplacement();
+            index = null;
+        } else if (location instanceof IndexedLocationNode) {
+            IndexedLocationNode indexedLocation = (IndexedLocationNode) location;
+            assert indexedLocation.getIndexScaling() == scale;
+            base = indexedLocation.getDisplacement();
+            index = indexedLocation.getIndex();
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        base -= getArrayBaseOffset(elementKind);
+        assert base >= 0 && base % scale == 0;
+
+        base /= scale;
+        assert NumUtil.isInt(base);
+
+        StructuredGraph graph = location.graph();
+        if (index == null) {
+            return ConstantNode.forInt((int) base, graph);
+        } else {
+            if (base == 0) {
+                return index;
+            } else {
+                return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index);
+            }
+        }
+    }
+
+    private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
+        StructuredGraph g = n.graph();
+        ValueNode array = n.array();
+        ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection());
+        if (arrayLength == null) {
+            Stamp stamp = StampFactory.positiveInt();
+            ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false));
+            g.addBeforeFixed(n, readArrayLength);
+            readArrayLength.setGuard(createNullCheck(array, readArrayLength, tool));
+            arrayLength = readArrayLength;
+        }
+
+        if (arrayLength.isConstant() && n.index().isConstant()) {
+            int l = arrayLength.asConstant().asInt();
+            int i = n.index().asConstant().asInt();
+            if (i >= 0 && i < l) {
+                // unneeded range check
+                return null;
+            }
+        }
+
+        return tool.createGuard(n, g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
+    }
+
+    private static GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
+        if (StampTool.isObjectNonNull(object)) {
+            return null;
+        }
+        return tool.createGuard(before, before.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -286,4 +286,8 @@
     public String disassemble(ResolvedJavaMethod method) {
         return new BytecodeDisassembler().disassemble(method);
     }
+
+    public SpeculationLog createSpeculationLog() {
+        return new HotSpotSpeculationLog();
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.lang.invoke.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 
 import java.lang.reflect.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -44,7 +44,7 @@
 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*;
-import static com.oracle.graal.hotspot.meta.HotSpotLoweringProvider.RuntimeCalls.*;
+import static com.oracle.graal.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.*;
 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
 import static com.oracle.graal.replacements.Log.*;
 import static com.oracle.graal.replacements.MathSubstitutionsX86.*;
@@ -119,7 +119,14 @@
         registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
         registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
         registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+
+        /*
+         * We cannot use LEAF_SP here because on some architectures we have to align the stack
+         * manually before calling into the VM. See {@link
+         * AMD64HotSpotEnterUnpackFramesStackFrameOp#emitCode}.
+         */
         registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+
         registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
 
         link(new NewInstanceStub(providers, target, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import sun.misc.*;
 
 import com.oracle.graal.api.code.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,991 +22,25 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-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.compiler.common.GraalOptions.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
-import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.debug.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.nodes.type.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
-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.virtual.*;
-import com.oracle.graal.replacements.*;
 
 /**
  * HotSpot implementation of {@link LoweringProvider}.
  */
-public class HotSpotLoweringProvider implements LoweringProvider {
-
-    protected final HotSpotGraalRuntime runtime;
-    protected final MetaAccessProvider metaAccess;
-    protected final ForeignCallsProvider foreignCalls;
-    protected final HotSpotRegistersProvider registers;
-
-    protected CheckCastDynamicSnippets.Templates checkcastDynamicSnippets;
-    protected InstanceOfSnippets.Templates instanceofSnippets;
-    protected NewObjectSnippets.Templates newObjectSnippets;
-    protected MonitorSnippets.Templates monitorSnippets;
-    protected WriteBarrierSnippets.Templates writeBarrierSnippets;
-    protected BoxingSnippets.Templates boxingSnippets;
-    protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
-    protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
-
-    public HotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
-        this.runtime = runtime;
-        this.metaAccess = metaAccess;
-        this.foreignCalls = foreignCalls;
-        this.registers = registers;
-    }
-
-    public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
-        TargetDescription target = providers.getCodeCache().getTarget();
-        checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target);
-        instanceofSnippets = new InstanceOfSnippets.Templates(providers, target);
-        newObjectSnippets = new NewObjectSnippets.Templates(providers, target);
-        monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking);
-        writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
-        boxingSnippets = new BoxingSnippets.Templates(providers, providers.getSnippetReflection(), target);
-        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
-        unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
-        providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
-    }
-
-    @Override
-    public void lower(Node n, LoweringTool tool) {
-        StructuredGraph graph = (StructuredGraph) n.graph();
-
-        if (n instanceof ArrayLengthNode) {
-            lowerArrayLengthNode((ArrayLengthNode) n, tool);
-        } else if (n instanceof Invoke) {
-            lowerInvoke((Invoke) n, tool, graph);
-        } else if (n instanceof LoadFieldNode) {
-            lowerLoadFieldNode((LoadFieldNode) n, tool);
-        } else if (n instanceof StoreFieldNode) {
-            lowerStoreFieldNode((StoreFieldNode) n, tool);
-        } else if (n instanceof CompareAndSwapNode) {
-            lowerCompareAndSwapNode((CompareAndSwapNode) n);
-        } else if (n instanceof AtomicReadAndWriteNode) {
-            lowerAtomicReadAndWriteNode((AtomicReadAndWriteNode) n);
-        } else if (n instanceof LoadIndexedNode) {
-            lowerLoadIndexedNode((LoadIndexedNode) n, tool);
-        } else if (n instanceof StoreIndexedNode) {
-            lowerStoreIndexedNode((StoreIndexedNode) n, tool);
-        } else if (n instanceof UnsafeLoadNode) {
-            lowerUnsafeLoadNode((UnsafeLoadNode) n, tool);
-        } else if (n instanceof UnsafeStoreNode) {
-            lowerUnsafeStoreNode((UnsafeStoreNode) n);
-        } else if (n instanceof JavaReadNode) {
-            lowerJavaReadNode((JavaReadNode) n);
-        } else if (n instanceof JavaWriteNode) {
-            lowerJavaWriteNode((JavaWriteNode) n);
-        } else if (n instanceof LoadHubNode) {
-            lowerLoadHubNode((LoadHubNode) n);
-        } else if (n instanceof LoadMethodNode) {
-            lowerLoadMethodNode((LoadMethodNode) n);
-        } else if (n instanceof StoreHubNode) {
-            lowerStoreHubNode((StoreHubNode) n, graph);
-        } else if (n instanceof CommitAllocationNode) {
-            lowerCommitAllocationNode((CommitAllocationNode) n, tool);
-        } else if (n instanceof OSRStartNode) {
-            lowerOSRStartNode((OSRStartNode) n);
-        } else if (n instanceof DynamicCounterNode) {
-            lowerDynamicCounterNode((DynamicCounterNode) n);
-        } else if (n instanceof BytecodeExceptionNode) {
-            lowerBytecodeExceptionNode((BytecodeExceptionNode) n);
-        } else if (n instanceof CheckCastDynamicNode) {
-            checkcastDynamicSnippets.lower((CheckCastDynamicNode) n, tool);
-        } else if (n instanceof InstanceOfNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                instanceofSnippets.lower((InstanceOfNode) n, tool);
-            }
-        } else if (n instanceof InstanceOfDynamicNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
-            }
-        } else if (n instanceof NewInstanceNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewInstanceNode) n, registers, tool);
-            }
-        } else if (n instanceof DynamicNewInstanceNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((DynamicNewInstanceNode) n, registers, tool);
-            }
-        } else if (n instanceof NewArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewArrayNode) n, registers, tool);
-            }
-        } else if (n instanceof DynamicNewArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((DynamicNewArrayNode) n, registers, tool);
-            }
-        } else if (n instanceof MonitorEnterNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                monitorSnippets.lower((MonitorEnterNode) n, registers, tool);
-            }
-        } else if (n instanceof MonitorExitNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                monitorSnippets.lower((MonitorExitNode) n, tool);
-            }
-        } else if (n instanceof G1PreWriteBarrier) {
-            writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
-        } else if (n instanceof G1PostWriteBarrier) {
-            writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool);
-        } else if (n instanceof G1ReferentFieldReadBarrier) {
-            writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool);
-        } else if (n instanceof SerialWriteBarrier) {
-            writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
-        } else if (n instanceof SerialArrayRangeWriteBarrier) {
-            writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
-        } else if (n instanceof G1ArrayRangePreWriteBarrier) {
-            writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool);
-        } else if (n instanceof G1ArrayRangePostWriteBarrier) {
-            writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool);
-        } else if (n instanceof NewMultiArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewMultiArrayNode) n, tool);
-            }
-        } else if (n instanceof LoadExceptionObjectNode) {
-            exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool);
-        } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
-            // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
-            // zero and the MIN_VALUE / -1 cases.
-        } else if (n instanceof BoxNode) {
-            boxingSnippets.lower((BoxNode) n, tool);
-        } else if (n instanceof UnboxNode) {
-            boxingSnippets.lower((UnboxNode) n, tool);
-        } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode) {
-            /* No lowering, we generate LIR directly for these nodes. */
-        } else {
-            throw GraalInternalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
-        }
-    }
-
-    private void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) {
-        StructuredGraph graph = arrayLengthNode.graph();
-        ValueNode array = arrayLengthNode.array();
-        ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, graph),
-                        StampFactory.positiveInt(), BarrierType.NONE, false));
-        arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool));
-        graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
-    }
-
-    private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) {
-        if (invoke.callTarget() instanceof MethodCallTargetNode) {
-            MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-            NodeInputList<ValueNode> parameters = callTarget.arguments();
-            ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
-            GuardingNode receiverNullCheck = null;
-            if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !StampTool.isObjectNonNull(receiver)) {
-                receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
-                invoke.setGuard(receiverNullCheck);
-            }
-            JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
-
-            LoweredCallTargetNode loweredCallTarget = null;
-            if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
-
-                HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
-                if (!hsMethod.getDeclaringClass().isInterface()) {
-                    if (hsMethod.isInVirtualMethodTable()) {
-                        int vtableEntryOffset = hsMethod.vtableEntryOffset();
-                        assert vtableEntryOffset > 0;
-                        Kind wordKind = runtime.getTarget().wordKind;
-                        ValueNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
-
-                        ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
-                        // We use LocationNode.ANY_LOCATION for the reads that access the
-                        // compiled code entry as HotSpot does not guarantee they are final
-                        // values.
-                        ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph),
-                                        StampFactory.forKind(wordKind), BarrierType.NONE, false));
-
-                        loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
-                                        CallingConvention.Type.JavaCall));
-
-                        graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
-                        graph.addAfterFixed(metaspaceMethod, compiledEntry);
-                    }
-                }
-            }
-
-            if (loweredCallTarget == null) {
-                loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
-                                callTarget.invokeKind()));
-            }
-            callTarget.replaceAndDelete(loweredCallTarget);
-        }
-    }
-
-    private Stamp loadStamp(Stamp stamp, Kind kind) {
-        return loadStamp(stamp, kind, true);
-    }
-
-    private Stamp loadStamp(Stamp stamp, Kind kind, boolean compressible) {
-        switch (kind) {
-            case Boolean:
-            case Byte:
-                return StampTool.narrowingConversion(stamp, 8);
-
-            case Char:
-            case Short:
-                return StampTool.narrowingConversion(stamp, 16);
-
-            case Object:
-                if (compressible && runtime.getConfig().useCompressedOops) {
-                    return new NarrowOopStamp((ObjectStamp) stamp, runtime.getConfig().getOopEncoding());
-                }
-        }
-        return stamp;
-    }
-
-    private ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value) {
-        return implicitLoadConvert(graph, kind, value, true);
-    }
-
-    private ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
-        switch (kind) {
-            case Byte:
-            case Short:
-                return graph.unique(new SignExtendNode(value, 32));
+public interface HotSpotLoweringProvider extends LoweringProvider {
 
-            case Boolean:
-            case Char:
-                return graph.unique(new ZeroExtendNode(value, 32));
-
-            case Object:
-                if (compressible && runtime.getConfig().useCompressedOops) {
-                    return CompressionNode.uncompress(value, runtime.getConfig().getOopEncoding());
-                }
-        }
-        return value;
-    }
-
-    private void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
-        StructuredGraph graph = loadField.graph();
-        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
-        ValueNode object = loadField.isStatic() ? ConstantNode.forConstant(HotSpotObjectConstant.forObject(field.getDeclaringClass().mirror()), metaAccess, graph) : loadField.object();
-        assert loadField.getKind() != Kind.Illegal;
-        BarrierType barrierType = getFieldLoadBarrierType(field);
-
-        Stamp loadStamp = loadStamp(loadField.stamp(), field.getKind());
-        ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadStamp, barrierType, false));
-        ValueNode readValue = implicitLoadConvert(graph, field.getKind(), memoryRead);
-
-        loadField.replaceAtUsages(readValue);
-        graph.replaceFixed(loadField, memoryRead);
-
-        memoryRead.setGuard(createNullCheck(object, memoryRead, tool));
-
-        if (loadField.isVolatile()) {
-            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
-            graph.addBeforeFixed(memoryRead, preMembar);
-            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
-            graph.addAfterFixed(memoryRead, postMembar);
-        }
-    }
-
-    private ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value) {
-        return implicitStoreConvert(graph, kind, value, true);
-    }
-
-    private ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
-        switch (kind) {
-            case Boolean:
-            case Byte:
-                return graph.unique(new NarrowNode(value, 8));
-            case Char:
-            case Short:
-                return graph.unique(new NarrowNode(value, 16));
-            case Object:
-                if (compressible && runtime.getConfig().useCompressedOops) {
-                    return CompressionNode.compress(value, runtime.getConfig().getOopEncoding());
-                }
-        }
-        return value;
-    }
-
-    private void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
-        StructuredGraph graph = storeField.graph();
-        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
-        ValueNode object = storeField.isStatic() ? ConstantNode.forConstant(HotSpotObjectConstant.forObject(field.getDeclaringClass().mirror()), metaAccess, graph) : storeField.object();
-        BarrierType barrierType = getFieldStoreBarrierType(storeField);
-
-        ValueNode value = implicitStoreConvert(graph, storeField.field().getKind(), storeField.value());
-        WriteNode memoryWrite = graph.add(new WriteNode(object, value, createFieldLocation(graph, field, false), barrierType, false));
-        memoryWrite.setStateAfter(storeField.stateAfter());
-        graph.replaceFixedWithFixed(storeField, memoryWrite);
-        memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool));
-        FixedWithNextNode last = memoryWrite;
-        FixedWithNextNode first = memoryWrite;
-
-        if (storeField.isVolatile()) {
-            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
-            graph.addBeforeFixed(first, preMembar);
-            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
-            graph.addAfterFixed(last, postMembar);
-        }
-    }
-
-    private void lowerCompareAndSwapNode(CompareAndSwapNode cas) {
-        StructuredGraph graph = cas.graph();
-        Kind valueKind = cas.getValueKind();
-        LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), valueKind, cas.displacement(), cas.offset(), graph, 1);
-
-        ValueNode expectedValue = implicitStoreConvert(graph, valueKind, cas.expected(), true);
-        ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue(), true);
-
-        LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, expectedValue, newValue, getCompareAndSwapBarrierType(cas), false));
-        atomicNode.setStateAfter(cas.stateAfter());
-        graph.replaceFixedWithFixed(cas, atomicNode);
-    }
-
-    private void lowerAtomicReadAndWriteNode(AtomicReadAndWriteNode n) {
-        StructuredGraph graph = n.graph();
-        Kind valueKind = n.getValueKind();
-        LocationNode location = IndexedLocationNode.create(n.getLocationIdentity(), valueKind, 0, n.offset(), graph, 1);
-
-        ValueNode newValue = implicitStoreConvert(graph, valueKind, n.newValue());
-
-        LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(n.object(), location, newValue, getAtomicReadAndWriteBarrierType(n), false));
-        memoryRead.setStateAfter(n.stateAfter());
-
-        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead);
-
-        n.replaceAtUsages(readValue);
-        graph.replaceFixedWithFixed(n, memoryRead);
-    }
-
-    private void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) {
-        StructuredGraph graph = loadIndexed.graph();
-        Kind elementKind = loadIndexed.elementKind();
-        LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
-
-        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
-        ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadStamp, BarrierType.NONE, false));
-        ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
-
-        memoryRead.setGuard(createBoundsCheck(loadIndexed, tool));
+    void initialize(HotSpotProviders providers, HotSpotVMConfig config);
 
-        loadIndexed.replaceAtUsages(readValue);
-        graph.replaceFixed(loadIndexed, memoryRead);
-    }
-
-    private void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
-        StructuredGraph graph = storeIndexed.graph();
-        GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
-        Kind elementKind = storeIndexed.elementKind();
-        LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false);
-
-        ValueNode value = storeIndexed.value();
-        ValueNode array = storeIndexed.array();
-
-        CheckCastNode checkcastNode = null;
-        CheckCastDynamicNode checkcastDynamicNode = null;
-        if (elementKind == Kind.Object && !StampTool.isObjectAlwaysNull(value)) {
-            // Store check!
-            ResolvedJavaType arrayType = StampTool.typeOrNull(array);
-            if (arrayType != null && StampTool.isExactType(array)) {
-                ResolvedJavaType elementType = arrayType.getComponentType();
-                if (!MetaUtil.isJavaLangObject(elementType)) {
-                    checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true));
-                    graph.addBeforeFixed(storeIndexed, checkcastNode);
-                    value = checkcastNode;
-                }
-            } else {
-                Kind wordKind = runtime.getTarget().wordKind;
-                ValueNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck);
-                LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, runtime.getConfig().arrayClassElementOffset, graph);
-                /*
-                 * Anchor the read of the element klass to the cfg, because it is only valid when
-                 * arrayClass is an object class, which might not be the case in other parts of the
-                 * compiled method.
-                 */
-                FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed)));
-                checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
-                graph.addBeforeFixed(storeIndexed, checkcastDynamicNode);
-                value = checkcastDynamicNode;
-            }
-        }
-        BarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
-        WriteNode memoryWrite = graph.add(new WriteNode(array, implicitStoreConvert(graph, elementKind, value), arrayLocation, barrierType, false));
-        memoryWrite.setGuard(boundsCheck);
-        memoryWrite.setStateAfter(storeIndexed.stateAfter());
-        graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
-
-        // Lower the associated checkcast node.
-        if (checkcastNode != null) {
-            checkcastNode.lower(tool);
-        } else if (checkcastDynamicNode != null) {
-            checkcastDynamicSnippets.lower(checkcastDynamicNode, tool);
-        }
-    }
-
-    private ReadNode createUnsafeRead(StructuredGraph graph, UnsafeLoadNode load, GuardingNode guard) {
-        boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
-        Kind readKind = load.accessKind();
-        LocationNode location = createLocation(load);
-        Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible);
-        ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, loadStamp, guard, BarrierType.NONE, false));
-        ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, compressible);
-        load.replaceAtUsages(readValue);
-        return memoryRead;
-    }
-
-    private void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) {
-        StructuredGraph graph = load.graph();
-        if (load.getGuardingCondition() != null) {
-            ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition()));
-            ReadNode memoryRead = createUnsafeRead(graph, load, valueAnchorNode);
-            graph.replaceFixedWithFixed(load, valueAnchorNode);
-            graph.addAfterFixed(valueAnchorNode, memoryRead);
-        } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
-            assert load.getKind() != Kind.Illegal;
-            if (addReadBarrier(load)) {
-                unsafeLoadSnippets.lower(load, tool);
-            } else {
-                ReadNode memoryRead = createUnsafeRead(graph, load, null);
-                // An unsafe read must not float outside its block otherwise
-                // it may float above an explicit null check on its object.
-                memoryRead.setGuard(BeginNode.prevBegin(load));
-                graph.replaceFixedWithFixed(load, memoryRead);
-            }
-        }
-    }
-
-    private void lowerUnsafeStoreNode(UnsafeStoreNode store) {
-        StructuredGraph graph = store.graph();
-        LocationNode location = createLocation(store);
-        ValueNode object = store.object();
-        BarrierType barrierType = getUnsafeStoreBarrierType(store);
-        boolean compressible = store.value().getKind() == Kind.Object;
-        Kind valueKind = store.accessKind();
-        ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible);
-        WriteNode write = graph.add(new WriteNode(object, value, location, barrierType, false));
-        write.setStateAfter(store.stateAfter());
-        graph.replaceFixedWithFixed(store, write);
-    }
-
-    private void lowerJavaReadNode(JavaReadNode read) {
-        StructuredGraph graph = read.graph();
-
-        Kind valueKind = read.location().getValueKind();
-        Stamp loadStamp = loadStamp(read.stamp(), valueKind, read.isCompressible());
-        ReadNode memoryRead = graph.add(new ReadNode(read.object(), read.location(), loadStamp, read.getBarrierType(), false));
-        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead, read.isCompressible());
-
-        memoryRead.setGuard(read.getGuard());
-
-        read.replaceAtUsages(readValue);
-        graph.replaceFixed(read, memoryRead);
-    }
-
-    private void lowerJavaWriteNode(JavaWriteNode write) {
-        StructuredGraph graph = write.graph();
-
-        Kind valueKind = write.location().getValueKind();
-        ValueNode value = implicitStoreConvert(graph, valueKind, write.value(), write.isCompressible());
+    int getScalingFactor(Kind kind);
 
-        WriteNode memoryWrite = graph.add(new WriteNode(write.object(), value, write.location(), write.getBarrierType(), false, write.isInitialization()));
-        memoryWrite.setStateAfter(write.stateAfter());
-        graph.replaceFixedWithFixed(write, memoryWrite);
-
-        memoryWrite.setGuard(write.getGuard());
-    }
-
-    private void lowerLoadHubNode(LoadHubNode loadHub) {
-        StructuredGraph graph = loadHub.graph();
-        if (graph.getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) {
-            Kind wordKind = runtime.getTarget().wordKind;
-            assert loadHub.getKind() == wordKind;
-            ValueNode object = loadHub.object();
-            GuardingNode guard = loadHub.getGuard();
-            ValueNode hub = createReadHub(graph, wordKind, object, guard);
-            graph.replaceFloating(loadHub, hub);
-        }
-    }
-
-    private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
-        StructuredGraph graph = loadMethodNode.graph();
-        ResolvedJavaMethod method = loadMethodNode.getMethod();
-        ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method);
-        graph.replaceFixed(loadMethodNode, metaspaceMethod);
-    }
-
-    private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) {
-        WriteNode hub = createWriteHub(graph, runtime.getTarget().wordKind, storeHub.getObject(), storeHub.getValue());
-        graph.replaceFixed(storeHub, hub);
-    }
-
-    private void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
-        StructuredGraph graph = commit.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-            ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
-            BitSet omittedValues = new BitSet();
-            int valuePos = 0;
-            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
-                int entryCount = virtual.entryCount();
-                FixedWithNextNode newObject;
-                if (virtual instanceof VirtualInstanceNode) {
-                    newObject = graph.add(new NewInstanceNode(virtual.type(), true));
-                } else {
-                    newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true));
-                }
-                graph.addBeforeFixed(commit, newObject);
-                allocations[objIndex] = newObject;
-                for (int i = 0; i < entryCount; i++) {
-                    ValueNode value = commit.getValues().get(valuePos);
-                    if (value instanceof VirtualObjectNode) {
-                        value = allocations[commit.getVirtualObjects().indexOf(value)];
-                    }
-                    if (value == null) {
-                        omittedValues.set(valuePos);
-                    } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
-                        // Constant.illegal is always the defaultForKind, so it is skipped
-                        Kind valueKind = value.getKind();
-                        Kind entryKind = virtual.entryKind(i);
-
-                        // Truffle requires some leniency in terms of what can be put where:
-                        Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind;
-                        assert valueKind.getStackKind() == entryKind.getStackKind() ||
-                                        (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode));
-                        ConstantLocationNode location;
-                        BarrierType barrierType;
-                        if (virtual instanceof VirtualInstanceNode) {
-                            ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
-                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, ((HotSpotResolvedJavaField) field).offset(), graph);
-                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
-                        } else {
-                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(entryKind) + i * getScalingFactor(entryKind), graph);
-                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE;
-                        }
-                        WriteNode write = new WriteNode(newObject, implicitStoreConvert(graph, entryKind, value), location, barrierType, false);
-                        graph.addAfterFixed(newObject, graph.add(write));
-                    }
-                    valuePos++;
-
-                }
-            }
-            valuePos = 0;
-
-            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
-                int entryCount = virtual.entryCount();
-                ValueNode newObject = allocations[objIndex];
-                for (int i = 0; i < entryCount; i++) {
-                    if (omittedValues.get(valuePos)) {
-                        ValueNode value = commit.getValues().get(valuePos);
-                        assert value instanceof VirtualObjectNode;
-                        ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
-                        if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
-                            assert virtual.entryKind(i) == Kind.Object && allocValue.getKind() == Kind.Object;
-                            WriteNode write;
-                            if (virtual instanceof VirtualInstanceNode) {
-                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
-                                write = new WriteNode(newObject, implicitStoreConvert(graph, Kind.Object, allocValue), createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i),
-                                                true), BarrierType.IMPRECISE, false);
-                            } else {
-                                write = new WriteNode(newObject, implicitStoreConvert(graph, Kind.Object, allocValue), createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph),
-                                                true), BarrierType.PRECISE, false);
-                            }
-                            graph.addBeforeFixed(commit, graph.add(write));
-                        }
-                    }
-                    valuePos++;
-                }
-            }
-
-            finishAllocatedObjects(tool, commit, allocations);
-            graph.removeFixed(commit);
-        }
-    }
-
-    private void lowerOSRStartNode(OSRStartNode osrStart) {
-        StructuredGraph graph = osrStart.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-            StartNode newStart = graph.add(new StartNode());
-            ParameterNode buffer = graph.unique(new ParameterNode(0, StampFactory.forKind(runtime.getTarget().wordKind)));
-            ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
-            migrationEnd.setStateAfter(osrStart.stateAfter());
-
-            newStart.setNext(migrationEnd);
-            FixedNode next = osrStart.next();
-            osrStart.setNext(null);
-            migrationEnd.setNext(next);
-            graph.setStart(newStart);
-
-            // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
-            int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
-            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
-                int size = HIRFrameStateBuilder.stackSlots(osrLocal.getKind());
-                int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
-                IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.getKind(), offset, ConstantNode.forLong(0, graph), graph, 1);
-                ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false));
-                osrLocal.replaceAndDelete(load);
-                graph.addBeforeFixed(migrationEnd, load);
-            }
-            osrStart.replaceAtUsages(newStart);
-            osrStart.safeDelete();
-        }
-    }
-
-    private void lowerDynamicCounterNode(DynamicCounterNode n) {
-        StructuredGraph graph = n.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-            BenchmarkCounters.lower(n, registers, runtime.getConfig(), runtime.getTarget().wordKind);
-        }
-    }
-
-    static final class Exceptions {
-        protected static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException;
-        protected static final NullPointerException cachedNullPointerException;
-
-        static {
-            cachedArrayIndexOutOfBoundsException = new ArrayIndexOutOfBoundsException();
-            cachedArrayIndexOutOfBoundsException.setStackTrace(new StackTraceElement[0]);
-            cachedNullPointerException = new NullPointerException();
-            cachedNullPointerException.setStackTrace(new StackTraceElement[0]);
-        }
-    }
-
-    public static final class RuntimeCalls {
-        public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", NullPointerException.class);
-        public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class);
-    }
-
-    private void lowerBytecodeExceptionNode(BytecodeExceptionNode node) {
-        StructuredGraph graph = node.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
-            if (OmitHotExceptionStacktrace.getValue()) {
-                Throwable exception;
-                if (node.getExceptionClass() == NullPointerException.class) {
-                    exception = Exceptions.cachedNullPointerException;
-                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
-                    exception = Exceptions.cachedArrayIndexOutOfBoundsException;
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-                FloatingNode exceptionNode = ConstantNode.forConstant(HotSpotObjectConstant.forObject(exception), metaAccess, graph);
-                graph.replaceFixedWithFloating(node, exceptionNode);
-
-            } else {
-                ForeignCallDescriptor descriptor;
-                if (node.getExceptionClass() == NullPointerException.class) {
-                    descriptor = RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION;
-                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
-                    descriptor = RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION;
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-
-                ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, descriptor, node.stamp(), node.getArguments()));
-                graph.replaceFixedWithFixed(node, foreignCallNode);
-            }
-        }
-    }
-
-    protected static void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
-        StructuredGraph graph = commit.graph();
-        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-            FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
-            allocations[objIndex] = anchor;
-            graph.addBeforeFixed(commit, anchor);
-        }
-        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-            for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
-                MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
-                graph.addBeforeFixed(commit, enter);
-                enter.lower(tool);
-            }
-        }
-        for (Node usage : commit.usages().snapshot()) {
-            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
-            int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
-            graph.replaceFloating(addObject, allocations[index]);
-        }
-    }
-
-    private static LocationNode createLocation(UnsafeAccessNode access) {
-        return createLocation(access.offset(), access.getLocationIdentity(), access.accessKind());
-    }
-
-    private static LocationNode createLocation(ValueNode offsetNode, LocationIdentity locationIdentity, Kind accessKind) {
-        ValueNode offset = offsetNode;
-        if (offset.isConstant()) {
-            long offsetValue = offset.asConstant().asLong();
-            return ConstantLocationNode.create(locationIdentity, accessKind, offsetValue, offset.graph());
-        }
+    IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization);
 
-        long displacement = 0;
-        int indexScaling = 1;
-        boolean signExtend = false;
-        if (offset instanceof SignExtendNode) {
-            SignExtendNode extend = (SignExtendNode) offset;
-            if (extend.getResultBits() == 64) {
-                signExtend = true;
-                offset = extend.getInput();
-            }
-        }
-        if (offset instanceof IntegerAddNode) {
-            IntegerAddNode integerAddNode = (IntegerAddNode) offset;
-            if (integerAddNode.y() instanceof ConstantNode) {
-                displacement = integerAddNode.y().asConstant().asLong();
-                offset = integerAddNode.x();
-            }
-        }
-
-        if (offset instanceof LeftShiftNode) {
-            LeftShiftNode leftShiftNode = (LeftShiftNode) offset;
-            if (leftShiftNode.y() instanceof ConstantNode) {
-                long shift = leftShiftNode.y().asConstant().asLong();
-                if (shift >= 1 && shift <= 3) {
-                    if (shift == 1) {
-                        indexScaling = 2;
-                    } else if (shift == 2) {
-                        indexScaling = 4;
-                    } else {
-                        indexScaling = 8;
-                    }
-                    offset = leftShiftNode.x();
-                }
-            }
-        }
-        if (signExtend) {
-            // If we were using sign extended values before restore the sign extension.
-            offset = offset.graph().addOrUnique(new SignExtendNode(offset, 64));
-        }
-        return IndexedLocationNode.create(locationIdentity, accessKind, displacement, offset, offset.graph(), indexScaling);
-    }
-
-    private static boolean addReadBarrier(UnsafeLoadNode load) {
-        if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getKind() == Kind.Object && load.accessKind() == Kind.Object &&
-                        !StampTool.isObjectAlwaysNull(load.object())) {
-            ResolvedJavaType type = StampTool.typeOrNull(load.object());
-            if (type != null && !type.isArray()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
-        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
-        assert !hsMethod.getDeclaringClass().isInterface();
-        assert hsMethod.isInVirtualMethodTable();
-
-        int vtableEntryOffset = hsMethod.vtableEntryOffset();
-        assert vtableEntryOffset > 0;
-        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
-        // entry as HotSpot does not guarantee that this is a final value.
-        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind), BarrierType.NONE, false));
-        return metaspaceMethod;
-    }
-
-    private ValueNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object, GuardingNode guard) {
-        HotSpotVMConfig config = runtime.getConfig();
-        LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph);
-        assert !object.isConstant() || object.asConstant().isNull();
-
-        Stamp hubStamp;
-        if (config.useCompressedClassPointers) {
-            hubStamp = StampFactory.forInteger(32);
-        } else {
-            hubStamp = StampFactory.forKind(wordKind);
-        }
-
-        FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(object, location, null, hubStamp, guard, BarrierType.NONE, false));
-        if (config.useCompressedClassPointers) {
-            return CompressionNode.uncompress(memoryRead, config.getKlassEncoding());
-        } else {
-            return memoryRead;
-        }
-    }
-
-    private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) {
-        HotSpotVMConfig config = runtime.getConfig();
-        LocationNode location = ConstantLocationNode.create(HUB_LOCATION, wordKind, config.hubOffset, graph);
-        assert !object.isConstant() || object.asConstant().isNull();
-
-        ValueNode writeValue = value;
-        if (config.useCompressedClassPointers) {
-            writeValue = CompressionNode.compress(value, config.getKlassEncoding());
-        }
-
-        return graph.add(new WriteNode(object, writeValue, location, BarrierType.NONE, false));
-    }
-
-    private static BarrierType getFieldLoadBarrierType(HotSpotResolvedJavaField loadField) {
-        BarrierType barrierType = BarrierType.NONE;
-        if (config().useG1GC && loadField.getKind() == Kind.Object && loadField.getDeclaringClass().mirror() == java.lang.ref.Reference.class && loadField.getName().equals("referent")) {
-            barrierType = BarrierType.PRECISE;
-        }
-        return barrierType;
-    }
-
-    private static BarrierType getFieldStoreBarrierType(StoreFieldNode storeField) {
-        if (storeField.field().getKind() == Kind.Object) {
-            return BarrierType.IMPRECISE;
-        }
-        return BarrierType.NONE;
-    }
-
-    private static BarrierType getArrayStoreBarrierType(StoreIndexedNode store) {
-        if (store.elementKind() == Kind.Object) {
-            return BarrierType.PRECISE;
-        }
-        return BarrierType.NONE;
-    }
+    ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value);
 
-    private static BarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) {
-        if (store.value().getKind() == Kind.Object) {
-            ResolvedJavaType type = StampTool.typeOrNull(store.object());
-            if (type != null && !type.isArray()) {
-                return BarrierType.IMPRECISE;
-            } else {
-                return BarrierType.PRECISE;
-            }
-        }
-        return BarrierType.NONE;
-    }
-
-    private static BarrierType getCompareAndSwapBarrierType(CompareAndSwapNode cas) {
-        if (cas.expected().getKind() == Kind.Object) {
-            ResolvedJavaType type = StampTool.typeOrNull(cas.object());
-            if (type != null && !type.isArray()) {
-                return BarrierType.IMPRECISE;
-            } else {
-                return BarrierType.PRECISE;
-            }
-        }
-        return BarrierType.NONE;
-    }
-
-    private static BarrierType getAtomicReadAndWriteBarrierType(AtomicReadAndWriteNode n) {
-        if (n.newValue().getKind() == Kind.Object) {
-            ResolvedJavaType type = StampTool.typeOrNull(n.object());
-            if (type != null && !type.isArray()) {
-                return BarrierType.IMPRECISE;
-            } else {
-                return BarrierType.PRECISE;
-            }
-        }
-        return BarrierType.NONE;
-    }
-
-    protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field, boolean initialization) {
-        LocationIdentity loc = initialization ? INIT_LOCATION : field;
-        return ConstantLocationNode.create(loc, field.getKind(), field.offset(), graph);
-    }
-
-    public int getScalingFactor(Kind kind) {
-        if (useCompressedOops() && kind == Kind.Object) {
-            return this.runtime.getTarget().getSizeInBytes(Kind.Int);
-        } else {
-            return this.runtime.getTarget().getSizeInBytes(kind);
-        }
-    }
-
-    protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) {
-        LocationIdentity loc = initialization ? INIT_LOCATION : NamedLocationIdentity.getArrayLocation(elementKind);
-        int scale = getScalingFactor(elementKind);
-        return IndexedLocationNode.create(loc, elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
-    }
-
-    @Override
-    public ValueNode reconstructArrayIndex(LocationNode location) {
-        Kind elementKind = location.getValueKind();
-        assert location.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind));
-
-        long base;
-        ValueNode index;
-        int scale = getScalingFactor(elementKind);
-
-        if (location instanceof ConstantLocationNode) {
-            base = ((ConstantLocationNode) location).getDisplacement();
-            index = null;
-        } else if (location instanceof IndexedLocationNode) {
-            IndexedLocationNode indexedLocation = (IndexedLocationNode) location;
-            assert indexedLocation.getIndexScaling() == scale;
-            base = indexedLocation.getDisplacement();
-            index = indexedLocation.getIndex();
-        } else {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
-        base -= getArrayBaseOffset(elementKind);
-        assert base >= 0 && base % scale == 0;
-
-        base /= scale;
-        assert NumUtil.isInt(base);
-
-        StructuredGraph graph = location.graph();
-        if (index == null) {
-            return ConstantNode.forInt((int) base, graph);
-        } else {
-            if (base == 0) {
-                return index;
-            } else {
-                return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index);
-            }
-        }
-    }
-
-    private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
-        StructuredGraph g = n.graph();
-        ValueNode array = n.array();
-        ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection());
-        if (arrayLength == null) {
-            Stamp stamp = StampFactory.positiveInt();
-            ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false));
-            g.addBeforeFixed(n, readArrayLength);
-            readArrayLength.setGuard(createNullCheck(array, readArrayLength, tool));
-            arrayLength = readArrayLength;
-        }
-
-        if (arrayLength.isConstant() && n.index().isConstant()) {
-            int l = arrayLength.asConstant().asInt();
-            int i = n.index().asConstant().asInt();
-            if (i >= 0 && i < l) {
-                // unneeded range check
-                return null;
-            }
-        }
-
-        return tool.createGuard(n, g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
-    }
-
-    private static GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
-        if (StampTool.isObjectNonNull(object)) {
-            return null;
-        }
-        return tool.createGuard(before, before.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
-    }
-
+    ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.lang.reflect.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static java.lang.String.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,6 @@
 
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 
@@ -84,10 +82,10 @@
     }
 
     protected boolean checkThreeObjectArgs() {
-        assert method.getSignature().getParameterCount(!Modifier.isStatic(method.getModifiers())) == 3;
+        assert method.getSignature().getParameterCount(!method.isStatic()) == 3;
         assert method.getSignature().getParameterKind(0) == Kind.Object;
         assert method.getSignature().getParameterKind(1) == Kind.Object;
-        assert !Modifier.isStatic(method.getModifiers()) || method.getSignature().getParameterKind(2) == Kind.Object;
+        assert !method.isStatic() || method.getSignature().getParameterKind(2) == Kind.Object;
         return true;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,7 +26,6 @@
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.meta.HotSpotResolvedObjectType.*;
-import static java.lang.reflect.Modifier.*;
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
@@ -200,8 +199,8 @@
         assert !ImmutableCode.getValue() || isCalledForSnippets() : receiver;
 
         if (receiver == null) {
-            assert isStatic(modifiers);
-            if (Modifier.isFinal(getModifiers())) {
+            assert isStatic();
+            if (isFinal()) {
                 if (holder.isInitialized() && !holder.getName().equals(SystemClassName) && isEmbeddable()) {
                     return readValue(receiver);
                 }
@@ -211,14 +210,14 @@
              * for non-static final fields, we must assume that they are only initialized if they
              * have a non-default value.
              */
-            assert !isStatic(modifiers);
+            assert !isStatic();
             Object object = HotSpotObjectConstant.asObject(receiver);
 
             // Canonicalization may attempt to process an unsafe read before
             // processing a guard (e.g. a null check or a type check) for this read
             // so we need to check the object being read
             if (object != null && isInObject(object)) {
-                if (Modifier.isFinal(getModifiers())) {
+                if (isFinal()) {
                     Constant value = readValue(receiver);
                     if (assumeNonStaticFinalFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) {
                         return value;
@@ -248,7 +247,7 @@
      *         {@code object}'s class
      */
     public boolean isInObject(Object object) {
-        if (isStatic(modifiers)) {
+        if (isStatic()) {
             return false;
         }
         return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectType.fromClass(object.getClass()));
@@ -257,13 +256,13 @@
     @Override
     public Constant readValue(Constant receiver) {
         if (receiver == null) {
-            assert isStatic(modifiers);
+            assert isStatic();
             if (holder.isInitialized()) {
                 return runtime().getHostProviders().getConstantReflection().readUnsafeConstant(getKind(), HotSpotObjectConstant.forObject(holder.mirror()), offset);
             }
             return null;
         } else {
-            assert !isStatic(modifiers);
+            assert !isStatic();
             assert receiver.isNonNull() && isInObject(HotSpotObjectConstant.asObject(receiver));
             return runtime().getHostProviders().getConstantReflection().readUnsafeConstant(getKind(), receiver, offset);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.lang.annotation.*;
@@ -186,8 +186,7 @@
 
     @Override
     public boolean canBeStaticallyBound() {
-        int modifiers = getModifiers();
-        return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(holder.getModifiers())) && !Modifier.isAbstract(modifiers);
+        return (isFinal() || isPrivate() || isStatic() || holder.isFinal()) && !isAbstract();
     }
 
     @Override
@@ -314,18 +313,17 @@
 
     @Override
     public boolean isClassInitializer() {
-        return "<clinit>".equals(name) && Modifier.isStatic(getModifiers());
+        return "<clinit>".equals(name) && isStatic();
     }
 
     @Override
     public boolean isConstructor() {
-        return "<init>".equals(name) && !Modifier.isStatic(getModifiers());
+        return "<init>".equals(name) && !isStatic();
     }
 
     @Override
     public int getMaxLocals() {
-        int modifiers = getModifiers();
-        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+        if (isAbstract() || isNative()) {
             return 0;
         }
         HotSpotVMConfig config = runtime().getConfig();
@@ -334,8 +332,7 @@
 
     @Override
     public int getMaxStackSize() {
-        int modifiers = getModifiers();
-        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+        if (isAbstract() || isNative()) {
             return 0;
         }
         HotSpotVMConfig config = runtime().getConfig();
@@ -487,10 +484,6 @@
         return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface();
     }
 
-    public boolean isSynchronized() {
-        return Modifier.isSynchronized(getModifiers());
-    }
-
     @Override
     public Type[] getGenericParameterTypes() {
         if (isConstructor()) {
@@ -620,7 +613,7 @@
      * @return virtual table index
      */
     private int getVtableIndex() {
-        assert !Modifier.isInterface(holder.getModifiers());
+        assert !holder.isInterface();
         HotSpotVMConfig config = runtime().getConfig();
         int result = unsafe.getInt(metaspaceMethod + config.methodVtableIndexOffset);
         assert result >= config.nonvirtualVtableIndex : "must be linked";
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,10 +23,8 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.lang.annotation.*;
 import java.lang.reflect.*;
 import java.net.*;
@@ -141,7 +139,7 @@
     public ResolvedJavaType findUniqueConcreteSubtype() {
         HotSpotVMConfig config = runtime().getConfig();
         if (isArray()) {
-            return isFinal(getElementalType(this).getModifiers()) ? this : null;
+            return getElementalType(this).isFinal() ? this : null;
         } else if (isInterface()) {
             final long implementorMetaspaceKlass = runtime().getCompilerToVM().getKlassImplementor(metaspaceKlass());
 
@@ -157,20 +155,20 @@
              * than one implementors (see: InstanceKlass::add_implementor). The isInterface check
              * takes care of this fact since this class is an interface.
              */
-            if (isAbstract(type.getModifiers()) || type.isInterface() || !type.isLeafClass()) {
+            if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) {
                 return null;
             }
             return type;
         } else {
             HotSpotResolvedObjectType type = this;
-            while (isAbstract(type.getModifiers())) {
+            while (type.isAbstract()) {
                 long subklass = type.getSubklass();
                 if (subklass == 0 || unsafeReadWord(subklass + config.nextSiblingOffset) != 0) {
                     return null;
                 }
                 type = (HotSpotResolvedObjectType) fromMetaspaceKlass(subklass);
             }
-            if (isAbstract(type.getModifiers()) || type.isInterface() || !type.isLeafClass()) {
+            if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) {
                 return null;
             }
             return type;
@@ -255,7 +253,7 @@
         if (isArray()) {
             return getComponentType().asExactType() != null ? this : null;
         }
-        return isFinal(getModifiers()) ? this : null;
+        return isFinal() ? this : null;
     }
 
     @Override
@@ -358,7 +356,7 @@
     @Override
     public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method) {
         assert method instanceof HotSpotMethod;
-        if (!isAbstract(method.getModifiers()) && method.getDeclaringClass().equals(this)) {
+        if (!method.isAbstract() && method.getDeclaringClass().equals(this)) {
             return method;
         }
 
@@ -367,7 +365,7 @@
             return null;
         }
         HotSpotResolvedJavaMethod resolvedMethod = HotSpotResolvedJavaMethod.fromMetaspace(resolvedMetaspaceMethod);
-        if (isAbstract(resolvedMethod.getModifiers())) {
+        if (resolvedMethod.isAbstract()) {
             return null;
         }
         return resolvedMethod;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.nfi;
 
 import static com.oracle.graal.api.code.CodeUtil.*;
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.nfi.NativeCallStubGraphBuilder.*;
 
 import com.oracle.graal.api.code.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,8 +27,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -37,7 +35,7 @@
  * Reserves a block of memory in the stack frame of a method. The block is reserved in the frame for
  * the entire execution of the associated method.
  */
-public final class AllocaNode extends FixedWithNextNode implements LIRGenResLowerable {
+public final class AllocaNode extends FixedWithNextNode implements LIRLowerable {
 
     /**
      * The number of slots in block.
@@ -58,8 +56,8 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
-        StackSlot array = res.getFrameMap().allocateStackSlots(slots, objects, null);
+    public void generate(NodeLIRBuilderTool gen) {
+        StackSlot array = gen.getLIRGeneratorTool().getResult().getFrameMap().allocateStackSlots(slots, objects, null);
         Value result = gen.getLIRGeneratorTool().emitAddress(array);
         gen.setResult(this, result);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,12 +24,11 @@
 
 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.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -39,7 +38,7 @@
  * check on the object.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRGenLowerable, MonitorEnter, MemoryCheckpoint.Single {
+public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorEnter, MemoryCheckpoint.Single {
 
     private int lockDepth;
 
@@ -59,7 +58,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         assert lockDepth != -1;
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
         StackSlot slot = hsGen.getLockSlot(lockDepth);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,8 +23,6 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -32,7 +30,7 @@
 /**
  * Converts a compile-time constant Java string into a C string installed with the generated code.
  */
-public final class CStringNode extends FloatingNode implements LIRGenLowerable {
+public final class CStringNode extends FloatingNode implements LIRLowerable {
 
     private final String string;
 
@@ -41,7 +39,7 @@
         this.string = string;
     }
 
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         gen.setResult(this, emitCString(gen, string));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -93,6 +93,10 @@
         throw GraalInternalError.shouldNotReachHere();
     }
 
+    public ValueNode getInput() {
+        return input;
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (input instanceof CompressionNode) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -28,7 +28,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -28,8 +28,7 @@
 
 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.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -38,7 +37,7 @@
  * Intrinsic for allocating an on-stack array of integers to hold the dimensions of a multianewarray
  * instruction.
  */
-public final class DimensionsNode extends FixedWithNextNode implements LIRGenResLowerable {
+public final class DimensionsNode extends FixedWithNextNode implements LIRLowerable {
 
     private final int rank;
 
@@ -48,12 +47,13 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRGeneratorTool lirGen = gen.getLIRGeneratorTool();
         int size = rank * 4;
-        int wordSize = gen.getLIRGeneratorTool().target().wordSize;
+        int wordSize = lirGen.target().wordSize;
         int slots = roundUp(size, wordSize) / wordSize;
-        StackSlot array = res.getFrameMap().allocateStackSlots(slots, new BitSet(0), null);
-        Value result = gen.getLIRGeneratorTool().emitAddress(array);
+        StackSlot array = lirGen.getResult().getFrameMap().allocateStackSlots(slots, new BitSet(0), null);
+        Value result = lirGen.emitAddress(array);
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,13 +23,12 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -39,7 +38,7 @@
  * expected value or the compared against value instead of a boolean.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRGenLowerable, MemoryCheckpoint.Single {
+public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
@@ -79,7 +78,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         ((HotSpotNodeLIRBuilder) gen).visitDirectCompareAndSwap(this);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.compiler.match.*;
+import com.oracle.graal.nodes.*;
+
+@MatchableNode(shortName = "Compression", value = CompressionNode.class, inputs = 1, adapter = HotSpotMatchableNodes.CompressionNodeAdapter.class)
+public class HotSpotMatchableNodes {
+    public static class CompressionNodeAdapter extends MatchNodeAdapter {
+        @Override
+        protected ValueNode getFirstInput(ValueNode node) {
+            return ((CompressionNode) node).getInput();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LoadExceptionObjectNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
+
+    public LoadExceptionObjectNode(Stamp stamp) {
+        super(stamp);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,6 @@
 
 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.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -35,16 +33,16 @@
 /**
  * Node that is used to maintain a stack based counter of how many locks are currently held.
  */
-public final class MonitorCounterNode extends FloatingNode implements LIRGenResLowerable {
+public final class MonitorCounterNode extends FloatingNode implements LIRLowerable {
 
     private MonitorCounterNode() {
         super(null);
     }
 
     @Override
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+    public void generate(NodeLIRBuilderTool gen) {
         assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance";
-        StackSlot counter = res.getFrameMap().allocateStackSlots(1, new BitSet(0), null);
+        StackSlot counter = gen.getLIRGeneratorTool().getResult().getFrameMap().allocateStackSlots(1, new BitSet(0), null);
         Value result = gen.getLIRGeneratorTool().emitAddress(counter);
         gen.setResult(this, result);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Tue Apr 29 12:43:27 2014 -0700
@@ -25,18 +25,17 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
  * A call to the {@link NewArrayStub}.
  */
-public class NewArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
+public class NewArrayStubCall extends DeoptimizingStubCall implements LIRLowerable {
 
     private static final Stamp defaultStamp = StampFactory.objectNonNull();
 
@@ -61,9 +60,9 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_ARRAY);
-        Variable result = gen.getLIRGenerator().emitForeignCall(linkage, this, gen.operand(hub), gen.operand(length));
+        Variable result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(hub), gen.operand(length));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Tue Apr 29 12:43:27 2014 -0700
@@ -59,7 +59,7 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_INSTANCE);
-        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, this, gen.operand(hub));
+        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(hub));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,13 +24,12 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
-public class PrefetchAllocateNode extends FixedWithNextNode implements LIRGenLowerable {
+public class PrefetchAllocateNode extends FixedWithNextNode implements LIRLowerable {
 
     @Input private ValueNode distance;
     @Input private ValueNode address;
@@ -42,7 +41,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         ((HotSpotNodeLIRBuilder) gen).emitPrefetchAllocate(address, distance);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,17 +24,15 @@
 
 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.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -42,7 +40,7 @@
  * Performs a tail call to the specified target compiled method, with the parameter taken from the
  * supplied FrameState.
  */
-public class TailcallNode extends FixedWithNextNode implements LIRGenResLowerable {
+public class TailcallNode extends FixedWithNextNode implements LIRLowerable {
 
     @Input(InputType.State) private FrameState frameState;
     @Input private ValueNode target;
@@ -59,20 +57,21 @@
         this.frameState = frameState;
     }
 
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+    public void generate(NodeLIRBuilderTool gen) {
         HotSpotVMConfig config = runtime().getConfig();
+        LIRGeneratorTool lirGen = gen.getLIRGeneratorTool();
         ResolvedJavaMethod method = frameState.method();
-        boolean isStatic = Modifier.isStatic(method.getModifiers());
+        boolean isStatic = method.isStatic();
 
         JavaType[] signature = MetaUtil.signatureToTypes(method.getSignature(), isStatic ? null : method.getDeclaringClass());
-        CallingConvention cc = res.getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, gen.getLIRGeneratorTool().target(), false);
+        CallingConvention cc = lirGen.getResult().getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, lirGen.target(), false);
         List<ValueNode> parameters = new ArrayList<>();
         for (int i = 0, slot = 0; i < cc.getArgumentCount(); i++, slot += HIRFrameStateBuilder.stackSlots(frameState.localAt(slot).getKind())) {
             parameters.add(frameState.localAt(slot));
         }
         Value[] args = gen.visitInvokeArguments(cc, parameters);
-        Value address = gen.getLIRGeneratorTool().emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
-        Value entry = gen.getLIRGeneratorTool().emitLoad(Kind.Long, address, null);
+        Value address = lirGen.emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
+        Value entry = lirGen.emitLoad(Kind.Long, address, null);
         HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen;
         hsgen.emitTailcall(args, entry);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowOopStamp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowOopStamp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -76,7 +76,7 @@
     }
 
     @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
         return NarrowOop;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Tue Apr 29 12:43:27 2014 -0700
@@ -28,7 +28,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -173,7 +172,7 @@
         // to a direct call we must cast the receiver and arguments to its
         // actual types.
         HotSpotSignature signature = targetMethod.getSignature();
-        final boolean isStatic = Modifier.isStatic(targetMethod.getModifiers());
+        final boolean isStatic = targetMethod.isStatic();
         final int receiverSkip = isStatic ? 0 : 1;
 
         // Cast receiver to its type.
@@ -240,7 +239,7 @@
      * @return invoke node for the member name target
      */
     private InvokeNode createTargetInvokeNode(ResolvedJavaMethod targetMethod) {
-        InvokeKind invokeKind = Modifier.isStatic(targetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special;
+        InvokeKind invokeKind = targetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
         JavaType returnType = targetMethod.getSignature().getReturnType(null);
 
         // MethodHandleLinkTo* nodes have a trailing MemberName argument which
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java	Tue Apr 29 12:43:27 2014 -0700
@@ -34,7 +34,7 @@
 public class CallSiteSubstitutions implements ReplacementsProvider {
 
     @Override
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         replacements.registerSubstitutions(ConstantCallSiteSubstitutions.class);
         replacements.registerSubstitutions(MutableCallSiteSubstitutions.class);
         replacements.registerSubstitutions(VolatileCallSiteSubstitutions.class);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Tue Apr 29 12:43:27 2014 -0700
@@ -28,7 +28,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.nodes.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
@@ -32,7 +33,7 @@
 public class HotSpotSubstitutions implements ReplacementsProvider {
 
     @Override
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         replacements.registerSubstitutions(ObjectSubstitutions.class);
         replacements.registerSubstitutions(SystemSubstitutions.class);
         replacements.registerSubstitutions(ThreadSubstitutions.class);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Tue Apr 29 12:43:27 2014 -0700
@@ -30,9 +30,9 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
@@ -44,6 +44,12 @@
 
 /**
  * Snippet for loading the exception object at the start of an exception dispatcher.
+ * <p>
+ * The frame state upon entry to an exception handler is such that it is a
+ * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly the
+ * exception object (per the JVM spec) to rethrow. This means that the code generated for this node
+ * must not cause a deoptimization as the runtime/interpreter would not have a valid location to
+ * find the exception object to be rethrown.
  */
 public class LoadExceptionObjectSnippets implements Snippets {
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Tue Apr 29 12:43:27 2014 -0700
@@ -126,8 +126,8 @@
         // Pop all the frames we must move/replace.
         //
         // Frame picture (youngest to oldest)
-        // 1: self-frame (no frame link)
-        // 2: deoptimizing frame (no frame link)
+        // 1: self-frame
+        // 2: deoptimizing frame
         // 3: caller of deoptimizing frame (could be compiled/interpreted).
 
         // Pop self-frame.
@@ -136,7 +136,7 @@
         // Load the initial info we should save (e.g. frame pointer).
         final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset());
 
-        // Pop deoptimized frame
+        // Pop deoptimized frame.
         final int sizeOfDeoptimizedFrame = unrollBlock.readInt(deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset());
         LeaveDeoptimizedStackFrameNode.leaveDeoptimizedStackFrame(sizeOfDeoptimizedFrame, initialInfo);
 
@@ -144,13 +144,15 @@
          * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
          * total size of the interpreter frames plus shadow page size. Bang one page at a time
          * because large sizes can bang beyond yellow and red zones.
+         *
+         * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository.
          */
         final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset());
         final int bangPages = NumUtil.roundUp(totalFrameSizes, pageSize()) / pageSize() + stackShadowPages();
         Word stackPointer = readRegister(stackPointerRegister);
 
         for (int i = 1; i < bangPages; i++) {
-            stackPointer.writeInt(-(i * pageSize()), i);
+            stackPointer.writeInt((-i * pageSize()) + stackBias(), 0);
         }
 
         // Load number of interpreter frames.
@@ -221,6 +223,19 @@
         return config().useStackBanging ? config().stackShadowPages : 0;
     }
 
+    /**
+     * Returns the stack bias for the host architecture.
+     *
+     * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository.
+     *
+     * @return stack bias
+     */
+    @Deprecated
+    @Fold
+    private static int stackBias() {
+        return config().stackBias;
+    }
+
     @Fold
     private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
         return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
@@ -61,15 +60,9 @@
     protected Arguments makeArguments(SnippetInfo stub) {
         HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) providers.getMetaAccess().lookupJavaType(int[].class);
 
-        // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we
-        // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since
-        // the int[] class will never be unloaded.
-        Constant intArrayHub = intArrayType.klass();
-        intArrayHub = Constant.forIntegerKind(runtime().getTarget().wordKind, intArrayHub.asLong());
-
         Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS, LoweringTool.StandardLoweringStage.HIGH_TIER);
         args.add("hub", null);
-        args.addConst("intArrayHub", intArrayHub);
+        args.addConst("intArrayHub", intArrayType.klass());
         args.addConst("threadRegister", providers.getRegisters().getThreadRegister());
         return args;
     }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Tue Apr 29 12:43:27 2014 -0700
@@ -25,8 +25,6 @@
 
 import static com.oracle.graal.api.code.TypeCheckHints.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -39,7 +37,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 
@@ -327,7 +324,7 @@
     private void genArithmeticOp(Kind result, int opcode) {
         T y = frameState.pop(result);
         T x = frameState.pop(result);
-        boolean isStrictFP = isStrict(method.getModifiers());
+        boolean isStrictFP = method.isStrict();
         T v;
         switch (opcode) {
             case IADD:
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -69,6 +69,12 @@
     public abstract boolean isCompatibleWith(S other);
 
     public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
+        /*
+         * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
+         * remove it for normal compilations, but not for OSR compilations - otherwise dead object
+         * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
+         * Kind.Illegal, because the conflicting branch might not have been parsed.
+         */
         if (liveness == null) {
             return;
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,6 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -46,7 +44,6 @@
 import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
@@ -723,7 +720,7 @@
                      * https://wikis.oracle.com/display/HotSpotInternals/Method+handles
                      * +and+invokedynamic
                      */
-                    boolean hasReceiver = !isStatic(((ResolvedJavaMethod) target).getModifiers());
+                    boolean hasReceiver = !((ResolvedJavaMethod) target).isStatic();
                     Constant appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL);
                     if (appendix != null) {
                         frameState.apush(ConstantNode.forConstant(appendix, metaAccess, currentGraph));
@@ -1089,7 +1086,7 @@
             }
 
             private ValueNode synchronizedObject(HIRFrameStateBuilder state, ResolvedJavaMethod target) {
-                if (isStatic(target.getModifiers())) {
+                if (target.isStatic()) {
                     return appendConstant(target.getDeclaringClass().getEncoding(Representation.JavaClass));
                 } else {
                     return state.loadLocal(0);
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,8 +23,6 @@
 package com.oracle.graal.java;
 
 import static com.oracle.graal.graph.iterators.NodePredicates.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -55,7 +53,7 @@
 
         int javaIndex = 0;
         int index = 0;
-        if (!isStatic(method.getModifiers())) {
+        if (!method.isStatic()) {
             // add the receiver
             ParameterNode receiver = graph.unique(new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass())));
             storeLocal(javaIndex, receiver);
@@ -328,6 +326,7 @@
         } finally {
             lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1);
             monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1);
+            assert lockedObjects.length == monitorIds.length;
         }
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/VerifyOptionsPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/VerifyOptionsPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,6 @@
 package com.oracle.graal.java;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -115,9 +113,9 @@
             if (node instanceof StoreFieldNode) {
                 ResolvedJavaField field = ((StoreFieldNode) node).field();
                 verify(field.getDeclaringClass().equals(declaringClass), node, "store to field " + format("%H.%n", field));
-                verify(isStatic(field.getModifiers()), node, "store to field " + format("%H.%n", field));
+                verify(field.isStatic(), node, "store to field " + format("%H.%n", field));
                 if (optionValueType.isAssignableFrom((ResolvedJavaType) field.getType())) {
-                    verify(isFinal(field.getModifiers()), node, "option field " + format("%H.%n", field) + " not final");
+                    verify(field.isFinal(), node, "option field " + format("%H.%n", field) + " not final");
                 } else {
                     verify((field.isSynthetic()), node, "store to non-synthetic field " + format("%H.%n", field));
                 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NPE_07.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NPE_07.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,8 +23,9 @@
 
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -61,12 +62,12 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -49,17 +50,17 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -56,17 +57,17 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_InNested.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_InNested.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_InNested extends JTTTest {
 
@@ -48,12 +49,12 @@
         return i;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_Synchronized01 extends JTTTest {
 
@@ -38,12 +39,12 @@
         throw new Exception();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_Synchronized02 extends JTTTest {
 
@@ -36,12 +37,12 @@
         throw new Exception();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_Synchronized03 extends JTTTest {
 
@@ -41,12 +42,12 @@
         throw new Exception();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_allocate01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_allocate01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -37,27 +38,27 @@
         return sum;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 80);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,8 +23,9 @@
 // Checkstyle: stop
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -55,12 +56,12 @@
         return (int) (b + c + s + i + l + f + d);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 40);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1000);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_invoke01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_invoke01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -104,12 +105,12 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 40);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 80);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_life.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_life.java	Tue Apr 29 12:43:27 2014 -0700
@@ -25,8 +25,9 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -106,7 +107,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_nest02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_nest02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,8 +23,9 @@
 // Checkstyle: stop
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -48,7 +49,7 @@
         return sum;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 15);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6196102.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6196102.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.hotspot;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /**
  * @bug 6196102
@@ -46,7 +47,7 @@
         return "ok";
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6850611.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6850611.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.hotspot;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 //@formatter:off
 
@@ -50,7 +51,7 @@
         return 95;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/EnumMap02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/EnumMap02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -45,17 +46,17 @@
         C
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 import java.io.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -58,7 +59,7 @@
         out.println(test(10000));
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 10000);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,10 +24,11 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import sun.misc.*;
 
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -55,7 +56,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/ClassLoader_loadClass01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/ClassLoader_loadClass01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 import java.net.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -43,22 +44,22 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_Literal01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_Literal01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_Literal01 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_asSubclass01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_asSubclass01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_asSubclass01 extends JTTTest {
 
@@ -53,27 +54,27 @@
         return i;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_cast01 extends JTTTest {
 
@@ -57,27 +58,27 @@
         return i;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_forName01 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_forName02 extends JTTTest {
 
@@ -51,27 +52,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 import java.net.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -56,32 +57,32 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName04.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName04.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -48,32 +49,32 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName05.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName05.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 import java.net.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -41,17 +42,17 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -81,27 +82,27 @@
 
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Object_getClass01 extends JTTTest {
 
@@ -49,27 +50,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_toString01 extends JTTTest {
 
@@ -47,17 +48,17 @@
         return string;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -33,17 +34,17 @@
         return ("id" + i).intern() == ("id" + i).intern();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -33,17 +34,17 @@
         return ("id" + i).intern().equals("id" + i);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.loop;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class LoopParseLong extends JTTTest {
 
@@ -98,7 +99,7 @@
         return negative ? result : -result;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("testShortened", "7", 10);
         runTest("testShortened", "-100", 10);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopSwitch01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopSwitch01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.loop;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -58,7 +59,7 @@
         return "" + ('a' + count);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigObjectParams02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigObjectParams02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -33,7 +34,7 @@
         return p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/Matrix01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/Matrix01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -155,32 +156,32 @@
         ((Matrix[]) array)[val % array.length] = new Matrix(number);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ReferenceMap01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ReferenceMap01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -57,7 +58,7 @@
         return Integer.valueOf(foo(new String[]{"asdf"}));
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -58,7 +59,7 @@
         Object c = b;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -117,22 +118,22 @@
         return c2 ? 1 : 0;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 10);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 20);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 40);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_FlowSensitive05.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_FlowSensitive05.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 import java.io.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -44,7 +45,7 @@
         return (String) arg;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", (Object) null);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.optimize;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  * Tests value numbering of instanceof operations.
@@ -76,17 +77,17 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -37,22 +38,22 @@
         return Class_getField01.class.getField(input).getName();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "field");
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", "field2");
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", "field3");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -42,27 +43,27 @@
         public String field4;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "field");
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", "field2");
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", "field3");
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", "field4");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -39,17 +40,17 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "main");
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", "xx");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -52,37 +53,37 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_newInstance03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_newInstance03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Class_newInstance03 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -59,47 +60,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -61,47 +62,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -87,47 +88,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -61,47 +62,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_getType01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_getType01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -59,47 +60,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -67,47 +68,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -69,47 +70,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -69,47 +70,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -56,27 +57,27 @@
         return arg.length;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -44,12 +45,12 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test1");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "test2");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -48,12 +49,12 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test1");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "test2");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getParameterTypes01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getParameterTypes01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -51,22 +52,22 @@
     public void method3(int arg1, Object arg2) {
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getReturnType01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getReturnType01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -51,22 +52,22 @@
     public void method3() {
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Monitor_contended01 extends JTTTest implements Runnable {
 
@@ -71,7 +72,7 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_notowner01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_notowner01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Monitor_notowner01 extends JTTTest {
 
@@ -62,7 +63,7 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait01 extends JTTTest implements Runnable {
 
@@ -57,22 +58,22 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run3() throws Throwable {
         runTest("test", 15);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait02 extends JTTTest implements Runnable {
 
@@ -57,17 +58,17 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait03 extends JTTTest implements Runnable {
 
@@ -63,17 +64,17 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait04 extends JTTTest implements Runnable {
 
@@ -67,32 +68,32 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/ThreadLocal03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/ThreadLocal03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -59,22 +60,22 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_getState02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_getState02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Thread_getState02 extends JTTTest {
 
@@ -33,7 +34,7 @@
         return new Thread().getState() == Thread.State.NEW;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,9 @@
 
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 //Test all, mainly monitors
 public class Thread_isInterrupted02 extends JTTTest {
@@ -85,12 +86,12 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0, 0);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1, 500);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -68,7 +69,7 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -66,7 +67,7 @@
 
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted05.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted05.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -66,7 +67,7 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_join01 extends JTTTest implements Runnable {
 
@@ -43,7 +44,7 @@
         cont = false;
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,8 +27,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_join02 extends JTTTest implements Runnable {
 
@@ -50,7 +51,7 @@
         cont = false;
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,8 +27,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_join03 extends JTTTest implements Runnable {
 
@@ -47,7 +48,7 @@
         cont = false;
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Thread_new01 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_new02 extends JTTTest implements Runnable {
 
@@ -51,27 +52,27 @@
         // do nothing.
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_sleep01.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_sleep01.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Thread_sleep01 extends JTTTest {
 
@@ -35,17 +36,17 @@
         return System.currentTimeMillis() - before >= i;
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 10);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 20);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 100);
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Tue Apr 29 12:43:27 2014 -0700
@@ -39,8 +39,8 @@
 
     // @formatter:off
 
-    IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR,
-    LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR,
+    IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, IROL, IROR,
+    LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, LROL, LROR,
     FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR,
     DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR,
     INEG, LNEG, INOT, LNOT,
@@ -491,6 +491,14 @@
                     assert asIntReg(src).equals(AMD64.rcx);
                     masm.shrl(asIntReg(dst));
                     break;
+                case IROL:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.roll(asIntReg(dst));
+                    break;
+                case IROR:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.roll(asIntReg(dst));
+                    break;
 
                 case LADD:
                     masm.addq(asLongReg(dst), asLongReg(src));
@@ -522,6 +530,14 @@
                     assert asIntReg(src).equals(AMD64.rcx);
                     masm.shrq(asLongReg(dst));
                     break;
+                case LROL:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.rolq(asLongReg(dst));
+                    break;
+                case LROR:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.rorq(asLongReg(dst));
+                    break;
 
                 case FADD:
                     masm.addss(asFloatReg(dst), asFloatReg(src));
@@ -695,6 +711,12 @@
                 case IUSHR:
                     masm.shrl(asIntReg(dst), crb.asIntConst(src) & 31);
                     break;
+                case IROL:
+                    masm.roll(asIntReg(dst), crb.asIntConst(src) & 31);
+                    break;
+                case IROR:
+                    masm.rorl(asIntReg(dst), crb.asIntConst(src) & 31);
+                    break;
 
                 case LADD:
                     masm.addq(asLongReg(dst), crb.asIntConst(src));
@@ -723,6 +745,12 @@
                 case LUSHR:
                     masm.shrq(asLongReg(dst), crb.asIntConst(src) & 63);
                     break;
+                case LROL:
+                    masm.rolq(asLongReg(dst), crb.asIntConst(src) & 31);
+                    break;
+                case LROR:
+                    masm.rorq(asLongReg(dst), crb.asIntConst(src) & 31);
+                    break;
 
                 case FADD:
                     masm.addss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src));
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,7 +23,7 @@
 package com.oracle.graal.lir.amd64;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import java.lang.reflect.*;
@@ -38,7 +38,7 @@
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.lir.gen.*;
 
 /**
  * Emits code which compares two arrays of the same length. If the CPU supports any vector
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Tue Apr 29 12:43:27 2014 -0700
@@ -132,6 +132,9 @@
                     default:
                         throw GraalInternalError.shouldNotReachHere();
                 }
+
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
             }
         }
 
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Tue Apr 29 12:43:27 2014 -0700
@@ -402,7 +402,8 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
-            throw new InternalError("NYI");
+            HSAILAddress addr = address.toAddress();
+            masm.emitLea(result, addr);
         }
     }
 
@@ -479,6 +480,32 @@
         }
     }
 
+    @Opcode("ATOMIC_READ_AND_WRITE")
+    public static class AtomicReadAndWriteOp extends HSAILLIRInstruction {
+
+        private final Kind accessKind;
+
+        @Def protected AllocatableValue result;
+        @Use({COMPOSITE}) protected HSAILAddressValue address;
+        @Use({REG, CONST}) protected Value newValue;
+
+        public AtomicReadAndWriteOp(Kind accessKind, AllocatableValue result, HSAILAddressValue address, Value newValue) {
+            this.accessKind = accessKind;
+            this.result = result;
+            this.address = address;
+            this.newValue = newValue;
+        }
+
+        public HSAILAddressValue getAddress() {
+            return address;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
+            masm.emitAtomicExch(accessKind, result, address.toAddress(), newValue);
+        }
+    }
+
     public static class NullCheckOp extends HSAILLIRInstruction {
 
         @Use protected Value input;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Tue Apr 29 12:43:27 2014 -0700
@@ -59,7 +59,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.lir.gen.*;
 
 public enum SPARCArithmetic {
     // @formatter:off
@@ -68,7 +68,7 @@
     FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR,
     DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR,
     INEG, LNEG, FNEG, DNEG, INOT, LNOT,
-    I2L, L2I, I2B, I2C, I2S,
+    L2I, B2I, S2I, B2L, S2L, I2L,
     F2D, D2F,
     I2F, I2D, F2I, D2I,
     L2F, L2D, F2L, D2L,
@@ -572,11 +572,11 @@
                 case L2I:
                     new Signx(asLongReg(src), asIntReg(dst)).emit(masm);
                     break;
-                case I2B:
+                case B2I:
                     new Sll(asIntReg(src), 24, asIntReg(dst)).emit(masm);
                     new Srl(asIntReg(dst), 24, asIntReg(dst)).emit(masm);
                     break;
-                case I2C:
+                case S2I:
                     new Sll(asIntReg(src), 16, asIntReg(dst)).emit(masm);
                     new Srl(asIntReg(dst), 16, asIntReg(dst)).emit(masm);
                     break;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -40,7 +40,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.lir.gen.*;
 
 public class SPARCBitManipulationOp extends SPARCLIRInstruction {
 
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Tue Apr 29 12:43:27 2014 -0700
@@ -270,13 +270,16 @@
     @Opcode("CMOVE")
     public static class CondMoveOp extends SPARCLIRInstruction {
 
+        private final Kind kind;
+
         @Def({REG, HINT}) protected Value result;
         @Alive({REG}) protected Value trueValue;
         @Use({REG, STACK, CONST}) protected Value falseValue;
 
         private final ConditionFlag condition;
 
-        public CondMoveOp(Variable result, Condition condition, Variable trueValue, Value falseValue) {
+        public CondMoveOp(Kind kind, Variable result, Condition condition, Variable trueValue, Value falseValue) {
+            this.kind = kind;
             this.result = result;
             this.condition = intCond(condition);
             this.trueValue = trueValue;
@@ -285,20 +288,28 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            cmove(crb, masm, result, false, condition, false, trueValue, falseValue);
+            // check that we don't overwrite an input operand before it is used.
+            assert !result.equals(trueValue);
+
+            SPARCMove.move(crb, masm, result, falseValue);
+            cmove(crb, masm, kind, result, condition, trueValue);
         }
     }
 
     @Opcode("CMOVE")
     public static class FloatCondMoveOp extends SPARCLIRInstruction {
 
+        private final Kind kind;
+
         @Def({REG}) protected Value result;
         @Alive({REG}) protected Value trueValue;
         @Alive({REG}) protected Value falseValue;
+
         private final ConditionFlag condition;
         private final boolean unorderedIsTrue;
 
-        public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) {
+        public FloatCondMoveOp(Kind kind, Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) {
+            this.kind = kind;
             this.result = result;
             this.condition = floatCond(condition);
             this.unorderedIsTrue = unorderedIsTrue;
@@ -308,18 +319,12 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            cmove(crb, masm, result, true, condition, unorderedIsTrue, trueValue, falseValue);
-        }
-    }
+            // check that we don't overwrite an input operand before it is used.
+            assert !result.equals(trueValue);
 
-    private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, boolean isFloat, ConditionFlag condition, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
-        // check that we don't overwrite an input operand before it is used.
-        assert !result.equals(trueValue);
+            SPARCMove.move(crb, masm, result, falseValue);
+            cmove(crb, masm, kind, result, condition, trueValue);
 
-        SPARCMove.move(crb, masm, result, falseValue);
-        cmove(crb, masm, result, condition, trueValue);
-
-        if (isFloat) {
             if (unorderedIsTrue && !trueOnUnordered(condition)) {
                 // cmove(crb, masm, result, ConditionFlag.Parity, trueValue);
                 throw GraalInternalError.unimplemented();
@@ -330,18 +335,20 @@
         }
     }
 
-    private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, ConditionFlag cond, Value other) {
+    private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Kind kind, Value result, ConditionFlag cond, Value other) {
         if (!isRegister(other)) {
             SPARCMove.move(crb, masm, result, other);
-            throw new InternalError("result should be scratch");
+            throw GraalInternalError.shouldNotReachHere("result should be scratch");
         }
         assert !asRegister(other).equals(asRegister(result)) : "other already overwritten by previous move";
-        switch (other.getKind()) {
+        switch (kind) {
             case Int:
-                // XXX CC depends on compare
                 new Movcc(cond, CC.Icc, asRegister(other), asRegister(result)).emit(masm);
                 break;
             case Long:
+            case Object:
+                new Movcc(cond, CC.Xcc, asRegister(other), asRegister(result)).emit(masm);
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
 import com.oracle.graal.lir.*;
 
 /**
@@ -33,7 +34,7 @@
  *
  * <pre>
  *   Base       Contents
- *
+ * 
  *            :                                :  -----
  *   caller   | incoming overflow argument n   |    ^
  *   frame    :     ...                        :    | positive
@@ -88,8 +89,7 @@
 
     @Override
     protected int alignFrameSize(int size) {
-        int x = size + (target.stackAlignment - 1);
-        return (x / target.stackAlignment) * target.stackAlignment;
+        return NumUtil.roundUp(size, target.stackAlignment);
     }
 
     @Override
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Tue Apr 29 12:43:27 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,32 +23,14 @@
 package com.oracle.graal.lir.sparc;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CompilationResult.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Add;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Lddf;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldf;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsb;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsh;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsw;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Lduh;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldx;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Membar;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Rdpc;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stb;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Sth;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stw;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stx;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cas;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Casx;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Clr;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Mov;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setuw;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
@@ -154,32 +136,33 @@
 
         @Override
         public void emitMemAccess(SPARCMacroAssembler masm) {
-            SPARCAddress addr = address.toAddress();
+            final SPARCAddress addr = address.toAddress();
+            final Register dst = asRegister(result);
             switch (kind) {
                 case Boolean:
                 case Byte:
-                    new Ldsb(addr, asRegister(result)).emit(masm);
+                    new Ldsb(addr, dst).emit(masm);
                     break;
                 case Short:
-                    new Ldsh(addr, asRegister(result)).emit(masm);
+                    new Ldsh(addr, dst).emit(masm);
                     break;
                 case Char:
-                    new Lduh(addr, asRegister(result)).emit(masm);
+                    new Lduh(addr, dst).emit(masm);
                     break;
                 case Int:
-                    new Ldsw(addr, asRegister(result)).emit(masm);
+                    new Ldsw(addr, dst).emit(masm);
                     break;
                 case Long:
-                    new Ldx(addr, asRegister(result)).emit(masm);
+                    new Ldx(addr, dst).emit(masm);
                     break;
                 case Float:
-                    new Ldf(addr, asRegister(result)).emit(masm);
+                    new Ldf(addr, dst).emit(masm);
                     break;
                 case Double:
-                    new Lddf(addr, asRegister(result)).emit(masm);
+                    new Lddf(addr, dst).emit(masm);
                     break;
                 case Object:
-                    new Ldx(addr, asRegister(result)).emit(masm);
+                    new Ldx(addr, dst).emit(masm);
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -208,6 +191,26 @@
         }
     }
 
+    public static class LoadDataAddressOp extends SPARCLIRInstruction {
+
+        @Def({REG}) protected AllocatableValue result;
+        private final byte[] data;
+
+        public LoadDataAddressOp(AllocatableValue result, byte[] data) {
+            this.result = result;
+            this.data = data;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            RawData rawData = new RawData(data, 16);
+            SPARCAddress addr = (SPARCAddress) crb.recordDataReferenceInCode(rawData);
+            assert addr == masm.getPlaceholder();
+            final boolean forceRelocatable = true;
+            new Setx(0, asRegister(result), forceRelocatable).emit(masm);
+        }
+    }
+
     public static class MembarOp extends SPARCLIRInstruction {
 
         private final int barriers;
@@ -395,19 +398,25 @@
     }
 
     private static void reg2reg(SPARCAssembler masm, Value result, Value input) {
-        if (asRegister(input).equals(asRegister(result))) {
+        final Register src = asRegister(input);
+        final Register dst = asRegister(result);
+        if (src.equals(dst)) {
             return;
         }
         switch (input.getKind()) {
             case Int:
             case Long:
             case Object:
-                new Mov(asRegister(input), asRegister(result)).emit(masm);
+                new Mov(src, dst).emit(masm);
                 break;
             case Float:
+                new Fmovs(src, dst).emit(masm);
+                break;
             case Double:
+                new Fmovd(src, dst).emit(masm);
+                break;
             default:
-                throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind());
+                throw GraalInternalError.shouldNotReachHere();
         }
     }
 
@@ -423,7 +432,11 @@
                 new Stx(src, dst).emit(masm);
                 break;
             case Float:
+                new Stf(src, dst).emit(masm);
+                break;
             case Double:
+                new Stdf(src, dst).emit(masm);
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -461,7 +474,7 @@
                     }
                 }
                 break;
-            case Long: {
+            case Long:
                 if (crb.codeCache.needsDataPatch(input)) {
                     crb.recordInlineDataInCode(input);
                     new Setx(input.asLong(), asRegister(result), true).emit(masm);
@@ -473,8 +486,10 @@
                     }
                 }
                 break;
-            }
-            case Object: {
+            case Float:
+                new Ldf((SPARCAddress) crb.asFloatConstRef(input), asFloatReg(result)).emit(masm);
+                break;
+            case Object:
                 if (input.isNull()) {
                     new Clr(asRegister(result)).emit(masm);
                 } else if (crb.target.inlineObjects) {
@@ -488,7 +503,6 @@
                     throw GraalInternalError.shouldNotReachHere("the patched offset might be too big for the load");
                 }
                 break;
-            }
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind());
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.sparc;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Saves registers to stack slots.
+ */
+@Opcode("SAVE_REGISTER")
+public class SPARCSaveRegistersOp extends SPARCLIRInstruction implements SaveRegistersOp {
+
+    /**
+     * The registers (potentially) saved by this operation.
+     */
+    protected final Register[] savedRegisters;
+
+    /**
+     * The slots to which the registers are saved.
+     */
+    @Def(STACK) protected final StackSlot[] slots;
+
+    /**
+     * Specifies if {@link #remove(Set)} should have an effect.
+     */
+    protected final boolean supportsRemove;
+
+    /**
+     *
+     * @param savedRegisters the registers saved by this operation which may be subject to
+     *            {@linkplain #remove(Set) pruning}
+     * @param slots the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned}
+     */
+    public SPARCSaveRegistersOp(Register[] savedRegisters, StackSlot[] slots, boolean supportsRemove) {
+        this.savedRegisters = savedRegisters;
+        this.slots = slots;
+        this.supportsRemove = supportsRemove;
+    }
+
+    private static void saveRegister(CompilationResultBuilder crb, SPARCMacroAssembler masm, StackSlot result, Register register) {
+        RegisterValue input = register.asValue(result.getKind());
+        SPARCMove.move(crb, masm, result, input);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                saveRegister(crb, masm, slots[i], savedRegisters[i]);
+            }
+        }
+    }
+
+    public StackSlot[] getSlots() {
+        return slots;
+    }
+
+    public boolean supportsRemove() {
+        return supportsRemove;
+    }
+
+    public int remove(Set<Register> doNotSave) {
+        if (!supportsRemove) {
+            throw new UnsupportedOperationException();
+        }
+        return prune(doNotSave, savedRegisters);
+    }
+
+    static int prune(Set<Register> toRemove, Register[] registers) {
+        int pruned = 0;
+        for (int i = 0; i < registers.length; i++) {
+            if (registers[i] != null) {
+                if (toRemove.contains(registers[i])) {
+                    registers[i] = null;
+                    pruned++;
+                }
+            }
+        }
+        return pruned;
+    }
+
+    public RegisterSaveLayout getMap(FrameMap frameMap) {
+        int total = 0;
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                total++;
+            }
+        }
+        Register[] keys = new Register[total];
+        int[] values = new int[total];
+        if (total != 0) {
+            int mapIndex = 0;
+            for (int i = 0; i < savedRegisters.length; i++) {
+                if (savedRegisters[i] != null) {
+                    keys[mapIndex] = savedRegisters[i];
+                    values[mapIndex] = frameMap.indexForStackSlot(slots[i]);
+                    mapIndex++;
+                }
+            }
+            assert mapIndex == total;
+        }
+        return new RegisterSaveLayout(keys, values);
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Tue Apr 29 12:43:27 2014 -0700
@@ -86,7 +86,7 @@
     @Override
     protected void rescanFieldOffsets(CalcOffset calc) {
         ValueFieldScanner scanner = new ValueFieldScanner(calc);
-        scanner.scan(clazz);
+        scanner.scan(getClazz());
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class);
         copyInto(componentOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
@@ -108,7 +108,7 @@
         }
 
         @Override
-        protected void scan(Class<?> clazz) {
+        public void scan(Class<?> clazz) {
             super.scan(clazz);
         }
 
@@ -127,7 +127,7 @@
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
-        str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" component[");
+        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" component[");
         for (int i = 0; i < componentOffsets.length; i++) {
             str.append(i == 0 ? "" : ", ").append(componentOffsets[i]);
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Tue Apr 29 12:43:27 2014 -0700
@@ -118,7 +118,7 @@
     @Override
     protected void rescanFieldOffsets(CalcOffset calc) {
         InstructionFieldScanner scanner = new InstructionFieldScanner(calc);
-        scanner.scan(clazz);
+        scanner.scan(getClazz());
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
         copyInto(useOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
@@ -177,7 +177,7 @@
         }
 
         @Override
-        protected void scan(Class<?> clazz) {
+        public void scan(Class<?> clazz) {
             if (clazz.getAnnotation(Opcode.class) != null) {
                 opcodeConstant = clazz.getAnnotation(Opcode.class).value();
             }
@@ -213,7 +213,7 @@
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
-        str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" use[");
+        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use[");
         for (int i = 0; i < useOffsets.length; i++) {
             str.append(i == 0 ? "" : ", ").append(useOffsets[i]);
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Tue Apr 29 12:43:27 2014 -0700
@@ -31,7 +31,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,12 +26,11 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.lir.StandardOp.BranchOp;
 import com.oracle.graal.lir.StandardOp.JumpOp;
-import com.oracle.graal.nodes.cfg.*;
 
 /**
  * LIR instructions such as {@link JumpOp} and {@link BranchOp} need to reference their target
- * {@link Block}. However, direct references are not possible since the control flow graph (and
- * therefore successors lists) can be changed by optimizations - and fixing the instructions is
+ * {@link AbstractBlock}. However, direct references are not possible since the control flow graph
+ * (and therefore successors lists) can be changed by optimizations - and fixing the instructions is
  * error prone. Therefore, we represent an edge to block B from block A via the tuple {@code (A,
  * successor-index-of-B)}. That is, indirectly by storing the index into the successor list of A.
  * Note therefore that the successor list cannot be re-ordered.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -92,14 +92,8 @@
         compilationResult.setTotalFrameSize(frameSize);
     }
 
-    private static final CompilationResult.Mark[] NO_REFS = {};
-
     public CompilationResult.Mark recordMark(Object id) {
-        return compilationResult.recordMark(asm.position(), id, NO_REFS);
-    }
-
-    public CompilationResult.Mark recordMark(Object id, CompilationResult.Mark... references) {
-        return compilationResult.recordMark(asm.position(), id, references);
+        return compilationResult.recordMark(asm.position(), id);
     }
 
     public void blockComment(String s) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/ArithmeticLIRGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,88 @@
+/*
+ * 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.gen;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.lir.*;
+
+/**
+ * This interface can be used to generate LIR for arithmetic operations.
+ */
+public interface ArithmeticLIRGenerator {
+
+    PlatformKind getPlatformKind(Stamp stamp);
+
+    Value emitNegate(Value input);
+
+    Value emitAdd(Value a, Value b);
+
+    Value emitSub(Value a, Value b);
+
+    Value emitMul(Value a, Value b);
+
+    Value emitDiv(Value a, Value b, LIRFrameState state);
+
+    Value emitRem(Value a, Value b, LIRFrameState state);
+
+    Value emitUDiv(Value a, Value b, LIRFrameState state);
+
+    Value emitURem(Value a, Value b, LIRFrameState state);
+
+    Value emitNot(Value input);
+
+    Value emitAnd(Value a, Value b);
+
+    Value emitOr(Value a, Value b);
+
+    Value emitXor(Value a, Value b);
+
+    Value emitShl(Value a, Value b);
+
+    Value emitShr(Value a, Value b);
+
+    Value emitUShr(Value a, Value b);
+
+    Value emitFloatConvert(FloatConvert op, Value inputVal);
+
+    Value emitReinterpret(PlatformKind to, Value inputVal);
+
+    Value emitNarrow(Value inputVal, int bits);
+
+    Value emitSignExtend(Value inputVal, int fromBits, int toBits);
+
+    Value emitZeroExtend(Value inputVal, int fromBits, int toBits);
+
+    Value emitMathAbs(Value input);
+
+    Value emitMathSqrt(Value input);
+
+    Value emitMathLog(Value input, boolean base10);
+
+    Value emitMathCos(Value input);
+
+    Value emitMathSin(Value input);
+
+    Value emitMathTan(Value input);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.gen;
+
+import com.oracle.graal.lir.*;
+
+public interface LIRGenerationResult {
+    FrameMap getFrameMap();
+
+    LIR getLIR();
+
+    boolean hasForeignCall();
+
+    void setForeignCall(boolean b);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.gen;
+
+import com.oracle.graal.lir.*;
+
+public class LIRGenerationResultBase implements LIRGenerationResult {
+    private final LIR lir;
+    private final FrameMap frameMap;
+    /**
+     * Records whether the code being generated makes at least one foreign call.
+     */
+    private boolean hasForeignCall;
+
+    public LIRGenerationResultBase(LIR lir, FrameMap frameMap) {
+        this.lir = lir;
+        this.frameMap = frameMap;
+    }
+
+    public LIR getLIR() {
+        return lir;
+    }
+
+    /**
+     * Determines whether the code being generated makes at least one foreign call.
+     */
+    public boolean hasForeignCall() {
+        return hasForeignCall;
+    }
+
+    public final void setForeignCall(boolean hasForeignCall) {
+        this.hasForeignCall = hasForeignCall;
+    }
+
+    public final FrameMap getFrameMap() {
+        return frameMap;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,594 @@
+/*
+ * 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.lir.gen;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.api.meta.Value.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.lir.LIR.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.compiler.common.spi.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.StandardOp.NoOp;
+import com.oracle.graal.options.*;
+
+/**
+ * This class traverses the HIR instructions and generates LIR instructions from them.
+ */
+public abstract class LIRGenerator implements LIRGeneratorTool, PlatformKindTool {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Print HIR along side LIR as the latter is generated")
+        public static final OptionValue<Boolean> PrintIRWithLIR = new OptionValue<>(false);
+        @Option(help = "The trace level for the LIR generator")
+        public static final OptionValue<Integer> TraceLIRGeneratorLevel = new OptionValue<>(0);
+        // @formatter:on
+    }
+
+    private final CodeGenProviders providers;
+    private final CallingConvention cc;
+
+    private AbstractBlock<?> currentBlock;
+
+    /**
+     * Handle for an operation that loads a constant into a variable. The operation starts in the
+     * first block where the constant is used but will eventually be
+     * {@linkplain LIRGenerator#insertConstantLoads() moved} to a block dominating all usages of the
+     * constant.
+     */
+    public static class LoadConstant implements Comparable<LoadConstant> {
+        /**
+         * The index of {@link #op} within {@link #block}'s instruction list or -1 if {@code op} is
+         * to be moved to a dominator block.
+         */
+        int index;
+
+        /**
+         * The operation that loads the constant.
+         */
+        private final LIRInstruction op;
+
+        /**
+         * The block that does or will contain {@link #op}. This is initially the block where the
+         * first usage of the constant is seen during LIR generation.
+         */
+        AbstractBlock<?> block;
+
+        /**
+         * The variable into which the constant is loaded.
+         */
+        final Variable variable;
+
+        public LoadConstant(Variable variable, AbstractBlock<?> block, int index, LIRInstruction op) {
+            this.variable = variable;
+            this.block = block;
+            this.index = index;
+            this.op = op;
+        }
+
+        /**
+         * Sorts {@link LoadConstant} objects according to their enclosing blocks. This is used to
+         * group loads per block in {@link LIRGenerator#insertConstantLoads()}.
+         */
+        public int compareTo(LoadConstant o) {
+            if (block.getId() < o.block.getId()) {
+                return -1;
+            }
+            if (block.getId() > o.block.getId()) {
+                return 1;
+            }
+            return 0;
+        }
+
+        @Override
+        public String toString() {
+            return block + "#" + op;
+        }
+
+        /**
+         * Removes the {@link #op} from its original location if it is still at that location.
+         */
+        public void unpin(LIR lir) {
+            if (index >= 0) {
+                // Replace the move with a filler op so that the operation
+                // list does not need to be adjusted.
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                instructions.set(index, new NoOp(null, -1));
+                index = -1;
+            }
+        }
+
+        public AbstractBlock<?> getBlock() {
+            return block;
+        }
+
+        public void setBlock(AbstractBlock<?> block) {
+            this.block = block;
+        }
+
+        public Variable getVariable() {
+            return variable;
+        }
+
+        public int getIndex() {
+            return index;
+        }
+
+        public void setIndex(int index) {
+            this.index = index;
+        }
+    }
+
+    private Map<Constant, LoadConstant> constantLoads;
+
+    private LIRGenerationResult res;
+
+    /**
+     * Checks whether the supplied constant can be used without loading it into a register for store
+     * operations, i.e., on the right hand side of a memory access.
+     *
+     * @param c The constant to check.
+     * @return True if the constant can be used directly, false if the constant needs to be in a
+     *         register.
+     */
+    public abstract boolean canStoreConstant(Constant c, boolean isCompressed);
+
+    public LIRGenerator(CodeGenProviders providers, CallingConvention cc, LIRGenerationResult res) {
+        this.res = res;
+        this.providers = providers;
+        this.cc = cc;
+    }
+
+    /**
+     * Returns true if the redundant move elimination optimization should be done after register
+     * allocation.
+     */
+    public boolean canEliminateRedundantMoves() {
+        return true;
+    }
+
+    @Override
+    public TargetDescription target() {
+        return getCodeCache().getTarget();
+    }
+
+    public CodeGenProviders getProviders() {
+        return providers;
+    }
+
+    @Override
+    public MetaAccessProvider getMetaAccess() {
+        return providers.getMetaAccess();
+    }
+
+    @Override
+    public CodeCacheProvider getCodeCache() {
+        return providers.getCodeCache();
+    }
+
+    @Override
+    public ForeignCallsProvider getForeignCalls() {
+        return providers.getForeignCalls();
+    }
+
+    /**
+     * Creates a new {@linkplain Variable variable}.
+     *
+     * @param platformKind The kind of the new variable.
+     * @return a new variable
+     */
+    @Override
+    public Variable newVariable(PlatformKind platformKind) {
+        return new Variable(platformKind, res.getLIR().nextVariable());
+    }
+
+    @Override
+    public RegisterAttributes attributes(Register register) {
+        return res.getFrameMap().registerConfig.getAttributesMap()[register.number];
+    }
+
+    @Override
+    public abstract Variable emitMove(Value input);
+
+    public AllocatableValue asAllocatable(Value value) {
+        if (isAllocatableValue(value)) {
+            return asAllocatableValue(value);
+        } else {
+            return emitMove(value);
+        }
+    }
+
+    public Variable load(Value value) {
+        if (!isVariable(value)) {
+            return emitMove(value);
+        }
+        return (Variable) value;
+    }
+
+    public Value loadNonConst(Value value) {
+        if (isConstant(value) && !canInlineConstant((Constant) value)) {
+            return emitMove(value);
+        }
+        return value;
+    }
+
+    /**
+     * Determines if only oop maps are required for the code generated from the LIR.
+     */
+    public boolean needOnlyOopMaps() {
+        return false;
+    }
+
+    /**
+     * Gets the ABI specific operand used to return a value of a given kind from a method.
+     *
+     * @param kind the kind of value being returned
+     * @return the operand representing the ABI defined location used return a value of kind
+     *         {@code kind}
+     */
+    public AllocatableValue resultOperandFor(Kind kind) {
+        if (kind == Kind.Void) {
+            return ILLEGAL;
+        }
+        return res.getFrameMap().registerConfig.getReturnRegister(kind).asValue(kind);
+    }
+
+    public void append(LIRInstruction op) {
+        if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) {
+            TTY.println(op.toStringWithIdPrefix());
+            TTY.println();
+        }
+        assert LIRVerifier.verify(op);
+        res.getLIR().getLIRforBlock(currentBlock).add(op);
+    }
+
+    public boolean hasBlockEnd(AbstractBlock<?> block) {
+        List<LIRInstruction> ops = getResult().getLIR().getLIRforBlock(block);
+        if (ops.size() == 0) {
+            return false;
+        }
+        return ops.get(ops.size() - 1) instanceof BlockEndOp;
+    }
+
+    public final void doBlockStart(AbstractBlock<?> block) {
+        if (Options.PrintIRWithLIR.getValue()) {
+            TTY.print(block.toString());
+        }
+
+        currentBlock = block;
+
+        // set up the list of LIR instructions
+        assert res.getLIR().getLIRforBlock(block) == null : "LIR list already computed for this block";
+        res.getLIR().setLIRforBlock(block, new ArrayList<LIRInstruction>());
+
+        append(new LabelOp(new Label(block.getId()), block.isAligned()));
+
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
+            TTY.println("BEGIN Generating LIR for block B" + block.getId());
+        }
+    }
+
+    public final void doBlockEnd(AbstractBlock<?> block) {
+
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
+            TTY.println("END Generating LIR for block B" + block.getId());
+        }
+
+        currentBlock = null;
+
+        if (Options.PrintIRWithLIR.getValue()) {
+            TTY.println();
+        }
+    }
+
+    public void emitIncomingValues(Value[] params) {
+        ((LabelOp) res.getLIR().getLIRforBlock(currentBlock).get(0)).setIncomingValues(params);
+    }
+
+    public abstract void emitJump(LabelRef label);
+
+    public abstract void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability);
+
+    public abstract void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability);
+
+    public abstract void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
+
+    public abstract Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
+
+    public abstract Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
+
+    protected abstract void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info);
+
+    public static AllocatableValue toStackKind(AllocatableValue value) {
+        if (value.getKind().getStackKind() != value.getKind()) {
+            // We only have stack-kinds in the LIR, so convert the operand kind for values from the
+            // calling convention.
+            if (isRegister(value)) {
+                return asRegister(value).asValue(value.getKind().getStackKind());
+            } else if (isStackSlot(value)) {
+                return StackSlot.get(value.getKind().getStackKind(), asStackSlot(value).getRawOffset(), asStackSlot(value).getRawAddFrameSize());
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+        return value;
+    }
+
+    @Override
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState frameState, Value... args) {
+        LIRFrameState state = null;
+        if (linkage.canDeoptimize()) {
+            if (frameState != null) {
+                state = frameState;
+            } else {
+                assert needOnlyOopMaps();
+                state = new LIRFrameState(null, null, null);
+            }
+        }
+
+        // move the arguments into the correct location
+        CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
+        res.getFrameMap().callsMethod(linkageCc);
+        assert linkageCc.getArgumentCount() == args.length : "argument count mismatch";
+        Value[] argLocations = new Value[args.length];
+        for (int i = 0; i < args.length; i++) {
+            Value arg = args[i];
+            AllocatableValue loc = linkageCc.getArgument(i);
+            emitMove(loc, arg);
+            argLocations[i] = loc;
+        }
+        res.setForeignCall(true);
+        emitForeignCall(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state);
+
+        if (isLegal(linkageCc.getReturn())) {
+            return emitMove(linkageCc.getReturn());
+        } else {
+            return null;
+        }
+    }
+
+    public void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
+        int keyCount = keyConstants.length;
+        SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets);
+        long valueRange = keyConstants[keyCount - 1].asLong() - keyConstants[0].asLong() + 1;
+        double tableSwitchDensity = keyCount / (double) valueRange;
+        /*
+         * This heuristic tries to find a compromise between the effort for the best switch strategy
+         * and the density of a tableswitch. If the effort for the strategy is at least 4, then a
+         * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers
+         * gradually with additional effort.
+         */
+        if (strategy.getAverageEffort() < 4 || tableSwitchDensity < (1 / Math.sqrt(strategy.getAverageEffort()))) {
+            emitStrategySwitch(strategy, value, keyTargets, defaultTarget);
+        } else {
+            int minValue = keyConstants[0].asInt();
+            assert valueRange < Integer.MAX_VALUE;
+            LabelRef[] targets = new LabelRef[(int) valueRange];
+            for (int i = 0; i < valueRange; i++) {
+                targets[i] = defaultTarget;
+            }
+            for (int i = 0; i < keyCount; i++) {
+                targets[keyConstants[i].asInt() - minValue] = keyTargets[i];
+            }
+            emitTableSwitch(minValue, defaultTarget, targets, value);
+        }
+    }
+
+    public abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
+
+    protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key);
+
+    public CallingConvention getCallingConvention() {
+        return cc;
+    }
+
+    @Override
+    public void beforeRegisterAllocation() {
+        insertConstantLoads();
+    }
+
+    /**
+     * Moves deferred {@linkplain LoadConstant loads} of constants into blocks dominating all usages
+     * of the constant. Any operations inserted into a block are guaranteed to be immediately prior
+     * to the first control flow instruction near the end of the block.
+     */
+    private void insertConstantLoads() {
+        if (constantLoads != null) {
+            // Remove loads where all usages are in the same block.
+            for (Iterator<Map.Entry<Constant, LoadConstant>> iter = constantLoads.entrySet().iterator(); iter.hasNext();) {
+                LoadConstant lc = iter.next().getValue();
+
+                // Move loads of constant outside of loops
+                if (OptScheduleOutOfLoops.getValue()) {
+                    AbstractBlock<?> outOfLoopDominator = lc.block;
+                    while (outOfLoopDominator.getLoop() != null) {
+                        outOfLoopDominator = outOfLoopDominator.getDominator();
+                    }
+                    if (outOfLoopDominator != lc.block) {
+                        lc.unpin(res.getLIR());
+                        lc.block = outOfLoopDominator;
+                    }
+                }
+
+                if (lc.index != -1) {
+                    assert res.getLIR().getLIRforBlock(lc.block).get(lc.index) == lc.op;
+                    iter.remove();
+                }
+            }
+            if (constantLoads.isEmpty()) {
+                return;
+            }
+
+            // Sorting groups the loads per block.
+            LoadConstant[] groupedByBlock = constantLoads.values().toArray(new LoadConstant[constantLoads.size()]);
+            Arrays.sort(groupedByBlock);
+
+            int groupBegin = 0;
+            while (true) {
+                int groupEnd = groupBegin + 1;
+                AbstractBlock<?> block = groupedByBlock[groupBegin].block;
+                while (groupEnd < groupedByBlock.length && groupedByBlock[groupEnd].block == block) {
+                    groupEnd++;
+                }
+                int groupSize = groupEnd - groupBegin;
+
+                List<LIRInstruction> ops = res.getLIR().getLIRforBlock(block);
+                int lastIndex = ops.size() - 1;
+                assert ops.get(lastIndex) instanceof BlockEndOp;
+                int insertionIndex = lastIndex;
+                for (int i = Math.max(0, lastIndex - MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END); i < lastIndex; i++) {
+                    if (getExceptionEdge(ops.get(i)) != null) {
+                        insertionIndex = i;
+                        break;
+                    }
+                }
+
+                if (groupSize == 1) {
+                    ops.add(insertionIndex, groupedByBlock[groupBegin].op);
+                } else {
+                    assert groupSize > 1;
+                    List<LIRInstruction> moves = new ArrayList<>(groupSize);
+                    for (int i = groupBegin; i < groupEnd; i++) {
+                        moves.add(groupedByBlock[i].op);
+                    }
+                    ops.addAll(insertionIndex, moves);
+                }
+
+                if (groupEnd == groupedByBlock.length) {
+                    break;
+                }
+                groupBegin = groupEnd;
+            }
+            constantLoads = null;
+        }
+    }
+
+    /**
+     * Gets a garbage value for a given kind.
+     */
+    protected Constant zapValueForKind(PlatformKind kind) {
+        long dead = 0xDEADDEADDEADDEADL;
+        switch ((Kind) kind) {
+            case Boolean:
+                return Constant.FALSE;
+            case Byte:
+                return Constant.forByte((byte) dead);
+            case Char:
+                return Constant.forChar((char) dead);
+            case Short:
+                return Constant.forShort((short) dead);
+            case Int:
+                return Constant.forInt((int) dead);
+            case Double:
+                return Constant.forDouble(Double.longBitsToDouble(dead));
+            case Float:
+                return Constant.forFloat(Float.intBitsToFloat((int) dead));
+            case Long:
+                return Constant.forLong(dead);
+            case Object:
+                return Constant.NULL_OBJECT;
+            default:
+                throw new IllegalArgumentException(kind.toString());
+        }
+    }
+
+    /**
+     * Default implementation: Return the Java stack kind for each stamp.
+     */
+    public PlatformKind getPlatformKind(Stamp stamp) {
+        return stamp.getPlatformKind(this);
+    }
+
+    public PlatformKind getIntegerKind(int bits) {
+        if (bits <= 8) {
+            return Kind.Byte;
+        } else if (bits <= 16) {
+            return Kind.Short;
+        } else if (bits <= 32) {
+            return Kind.Int;
+        } else {
+            assert bits <= 64;
+            return Kind.Long;
+        }
+    }
+
+    public PlatformKind getFloatingKind(int bits) {
+        switch (bits) {
+            case 32:
+                return Kind.Float;
+            case 64:
+                return Kind.Double;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    public PlatformKind getObjectKind() {
+        return Kind.Object;
+    }
+
+    public abstract void emitBitCount(Variable result, Value operand);
+
+    public abstract void emitBitScanForward(Variable result, Value operand);
+
+    public abstract void emitBitScanReverse(Variable result, Value operand);
+
+    public abstract void emitByteSwap(Variable result, Value operand);
+
+    public abstract void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+
+    public AbstractBlock<?> getCurrentBlock() {
+        return currentBlock;
+    }
+
+    void setCurrentBlock(AbstractBlock<?> block) {
+        currentBlock = block;
+    }
+
+    public LIRGenerationResult getResult() {
+        return res;
+    }
+
+    public Map<Constant, LoadConstant> getConstantLoads() {
+        return constantLoads;
+    }
+
+    public void setConstantLoads(Map<Constant, LoadConstant> constantLoads) {
+        this.constantLoads = constantLoads;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,199 @@
+/*
+ * 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.lir.gen;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.compiler.common.spi.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.LIRGenerator.*;
+
+public interface LIRGeneratorTool extends ArithmeticLIRGenerator {
+
+    CodeGenProviders getProviders();
+
+    TargetDescription target();
+
+    MetaAccessProvider getMetaAccess();
+
+    CodeCacheProvider getCodeCache();
+
+    ForeignCallsProvider getForeignCalls();
+
+    AbstractBlock<?> getCurrentBlock();
+
+    LIRGenerationResult getResult();
+
+    boolean hasBlockEnd(AbstractBlock<?> block);
+
+    void doBlockStart(AbstractBlock<?> block);
+
+    void doBlockEnd(AbstractBlock<?> block);
+
+    Map<Constant, LoadConstant> getConstantLoads();
+
+    void setConstantLoads(Map<Constant, LoadConstant> constantLoads);
+
+    Value emitLoad(PlatformKind kind, Value address, LIRFrameState state);
+
+    void emitStore(PlatformKind kind, Value address, Value input, LIRFrameState state);
+
+    Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue);
+
+    /**
+     * Emit an atomic read-and-add instruction.
+     *
+     * @param address address of the value to be read and written
+     * @param delta the value to be added
+     */
+    default Value emitAtomicReadAndAdd(Value address, Value delta) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emit an atomic read-and-write instruction.
+     *
+     * @param address address of the value to be read and written
+     * @param newValue the new value to be written
+     */
+    default Value emitAtomicReadAndWrite(Value address, Value newValue) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state);
+
+    Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args);
+
+    /**
+     * Checks whether the supplied constant can be used without loading it into a register for most
+     * operations, i.e., for commonly used arithmetic, logical, and comparison operations.
+     *
+     * @param c The constant to check.
+     * @return True if the constant can be used directly, false if the constant needs to be in a
+     *         register.
+     */
+    boolean canInlineConstant(Constant c);
+
+    boolean canStoreConstant(Constant c, boolean isCompressed);
+
+    RegisterAttributes attributes(Register register);
+
+    Variable newVariable(PlatformKind kind);
+
+    Variable emitMove(Value input);
+
+    void emitMove(AllocatableValue dst, Value src);
+
+    /**
+     * Emits an op that loads the address of some raw data.
+     *
+     * @param dst the variable into which the address is loaded
+     * @param data the data to be installed with the generated code
+     */
+    void emitData(AllocatableValue dst, byte[] data);
+
+    Value emitAddress(Value base, long displacement, Value index, int scale);
+
+    Value emitAddress(StackSlot slot);
+
+    void emitMembar(int barriers);
+
+    void emitUnwind(Value operand);
+
+    /**
+     * Called just before register allocation is performed on the LIR owned by this generator.
+     * Overriding implementations of this method must call the overridden method.
+     */
+    void beforeRegisterAllocation();
+
+    void emitIncomingValues(Value[] params);
+
+    /**
+     * Emits a return instruction. Implementations need to insert a move if the input is not in the
+     * correct location.
+     */
+    void emitReturn(Value input);
+
+    AllocatableValue asAllocatable(Value value);
+
+    Variable load(Value value);
+
+    Value loadNonConst(Value value);
+
+    /**
+     * Returns true if the redundant move elimination optimization should be done after register
+     * allocation.
+     */
+    boolean canEliminateRedundantMoves();
+
+    /**
+     * Determines if only oop maps are required for the code generated from the LIR.
+     */
+    boolean needOnlyOopMaps();
+
+    /**
+     * Gets the ABI specific operand used to return a value of a given kind from a method.
+     *
+     * @param kind the kind of value being returned
+     * @return the operand representing the ABI defined location used return a value of kind
+     *         {@code kind}
+     */
+    AllocatableValue resultOperandFor(Kind kind);
+
+    void append(LIRInstruction op);
+
+    void emitJump(LabelRef label);
+
+    void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability);
+
+    void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability);
+
+    void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
+
+    Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
+
+    Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
+
+    void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value);
+
+    void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
+
+    CallingConvention getCallingConvention();
+
+    void emitBitCount(Variable result, Value operand);
+
+    void emitBitScanForward(Variable result, Value operand);
+
+    void emitBitScanReverse(Variable result, Value operand);
+
+    void emitByteSwap(Variable result, Value operand);
+
+    void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+
+}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Tue Apr 29 12:43:27 2014 -0700
@@ -114,7 +114,7 @@
                 FrameState exitState = exit.stateAfter();
                 if (exitState != null) {
                     exitState.applyToVirtual(v -> {
-                        if (v.usages().filter(n -> nodes.isMarked(n) && !(n instanceof VirtualState && exitState.isPartOfThisState((VirtualState) n))).isEmpty()) {
+                        if (v.usages().filter(n -> nodes.isMarked(n) && n != exit).isEmpty()) {
                             nodes.clear(v);
                         }
                     });
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryLogicNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes;
-
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public abstract class BinaryLogicNode extends LogicNode implements LIRLowerable, MemoryArithmeticLIRLowerable {
-
-    @Input private ValueNode x;
-    @Input private ValueNode y;
-
-    public ValueNode x() {
-        return x;
-    }
-
-    public ValueNode y() {
-        return y;
-    }
-
-    protected void setX(ValueNode x) {
-        updateUsages(this.x, x);
-        this.x = x;
-    }
-
-    protected void setY(ValueNode y) {
-        updateUsages(this.y, y);
-        this.y = y;
-    }
-
-    public BinaryLogicNode(ValueNode x, ValueNode y) {
-        assert x != null && y != null && x.getKind() == y.getKind();
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public boolean verify() {
-        assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp());
-        return super.verify();
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-    }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        return false;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class BinaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable {
+
+    @Input private ValueNode x;
+    @Input private ValueNode y;
+
+    public ValueNode x() {
+        return x;
+    }
+
+    public ValueNode y() {
+        return y;
+    }
+
+    protected void setX(ValueNode x) {
+        updateUsages(this.x, x);
+        this.x = x;
+    }
+
+    protected void setY(ValueNode y) {
+        updateUsages(this.y, y);
+        this.y = y;
+    }
+
+    public BinaryOpLogicNode(ValueNode x, ValueNode y) {
+        assert x != null && y != null && x.getKind() == y.getKind();
+        this.x = x;
+        this.y = y;
+    }
+
+    public abstract TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY);
+
+    @Override
+    public boolean verify() {
+        assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp());
+        return super.verify();
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        switch (evaluate(tool.getConstantReflection(), x(), y())) {
+            case FALSE:
+                return LogicConstantNode.contradiction(graph());
+            case TRUE:
+                return LogicConstantNode.tautology(graph());
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -63,7 +63,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.getLIRGeneratorTool().emitDeoptimize(gen.getLIRGeneratorTool().getMetaAccess().encodeDeoptActionAndReason(action, reason, debugId), speculation, this);
+        gen.getLIRGeneratorTool().emitDeoptimize(gen.getLIRGeneratorTool().getMetaAccess().encodeDeoptActionAndReason(action, reason, debugId), speculation, gen.state(this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -55,7 +55,7 @@
     }
 
     public void generate(NodeLIRBuilderTool generator) {
-        generator.getLIRGeneratorTool().emitDeoptimize(generator.operand(actionAndReason), generator.operand(speculation), this);
+        generator.getLIRGeneratorTool().emitDeoptimize(generator.operand(actionAndReason), generator.operand(speculation), generator.state(this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -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/FrameState.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Tue Apr 29 12:43:27 2014 -0700
@@ -95,8 +95,8 @@
         this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings);
         this.rethrowException = rethrowException;
         this.duringCall = duringCall;
-        assert !rethrowException || stackSize == 1 : "must have exception on top of the stack";
-        assert values.size() - localsSize - stackSize == monitorIds.size();
+        assert !this.rethrowException || this.stackSize == 1 : "must have exception on top of the stack";
+        assert this.locksSize() == this.monitorIds.size();
     }
 
     /**
@@ -220,6 +220,19 @@
      * correctly in slot encoding: a long or double will be followed by a null slot.
      */
     public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) {
+        return duplicateModified(newBci, method, newRethrowException, popKind, pushedValues);
+    }
+
+    /**
+     * Creates a copy of this frame state with one stack element of type popKind popped from the
+     * stack and the values in pushedValues pushed on the stack. The pushedValues will be formatted
+     * correctly in slot encoding: a long or double will be followed by a null slot.
+     */
+    public FrameState duplicateModified(Kind popKind, ValueNode... pushedValues) {
+        return duplicateModified(bci, method, rethrowException, popKind, pushedValues);
+    }
+
+    private FrameState duplicateModified(int newBci, ResolvedJavaMethod newMethod, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) {
         ArrayList<ValueNode> copy = new ArrayList<>(values.subList(0, localsSize + stackSize));
         if (popKind != Kind.Void) {
             if (stackAt(stackSize() - 1) == null) {
@@ -238,7 +251,7 @@
         int newStackSize = copy.size() - localsSize;
         copy.addAll(values.subList(localsSize + stackSize, values.size()));
 
-        FrameState other = graph().add(new FrameState(method, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
+        FrameState other = graph().add(new FrameState(newMethod, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
         other.setOuterFrameState(outerFrameState());
         return other;
     }
@@ -386,7 +399,7 @@
 
     @Override
     public boolean verify() {
-        assertTrue(values.size() - localsSize - stackSize == monitorIds.size(), "mismatch in number of locks");
+        assertTrue(locksSize() == monitorIds.size(), "mismatch in number of locks");
         for (ValueNode value : values) {
             assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes");
             assertTrue(value == null || value instanceof VirtualObjectNode || (value.getKind() != Kind.Void), "unexpected value: %s", value);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -107,7 +107,8 @@
         } else if (condition() instanceof LogicConstantNode) {
             LogicConstantNode c = (LogicConstantNode) condition();
             if (c.getValue() != negated) {
-                return graph().start();
+                this.replaceAtUsages(null);
+                return null;
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -28,7 +28,7 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Guard})
-public class GuardProxyNode extends ProxyNode implements GuardingNode, Proxy {
+public class GuardProxyNode extends ProxyNode implements GuardingNode, Proxy, LIRLowerable {
 
     @Input(InputType.Guard) private GuardingNode value;
 
@@ -38,6 +38,10 @@
     }
 
     @Override
+    public void generate(NodeLIRBuilderTool generator) {
+    }
+
+    @Override
     public ValueNode value() {
         return value.asNode();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -77,7 +77,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (getGuard() == graph().start() || getGuard() == null) {
+        if (getGuard() == null) {
             if (stamp().equals(object().stamp())) {
                 return object();
             } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -51,6 +51,18 @@
         return condition;
     }
 
+    public boolean isNegated() {
+        return negated;
+    }
+
+    public DeoptimizationReason getReason() {
+        return reason;
+    }
+
+    public DeoptimizationAction getAction() {
+        return action;
+    }
+
     /**
      * Constructor for {@link #guardingNonNull(Object)} node intrinsic.
      */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -34,7 +34,6 @@
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
@@ -43,7 +42,7 @@
  * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome
  * of a comparison.
  */
-public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, MemoryArithmeticLIRLowerable {
+public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
 
     @Successor private BeginNode trueSuccessor;
     @Successor private BeginNode falseSuccessor;
@@ -132,11 +131,6 @@
     }
 
     @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        return gen.emitIfMemory(this, access);
-    }
-
-    @Override
     public boolean verify() {
         assertTrue(condition() != null, "missing condition");
         assertTrue(trueSuccessor() != null, "missing trueSuccessor");
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -43,6 +43,6 @@
 
     @Override
     public String targetName() {
-        return "Indirect#" + ((JavaMethod) target()).getName();
+        return MetaUtil.format("Indirect#%h.%n", target());
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -37,7 +37,7 @@
     private static final double EXCEPTION_PROBA = 1e-5;
 
     @Successor private BeginNode next;
-    @Successor private DispatchBeginNode exceptionEdge;
+    @Successor private BeginNode exceptionEdge;
     @Input(InputType.Extension) private CallTargetNode callTarget;
     @Input(InputType.State) private FrameState stateDuring;
     @Input(InputType.State) private FrameState stateAfter;
@@ -47,7 +47,7 @@
     private boolean useForInlining;
     private double exceptionProbability;
 
-    public InvokeWithExceptionNode(CallTargetNode callTarget, DispatchBeginNode exceptionEdge, int bci) {
+    public InvokeWithExceptionNode(CallTargetNode callTarget, BeginNode exceptionEdge, int bci) {
         super(callTarget.returnStamp());
         this.exceptionEdge = exceptionEdge;
         this.bci = bci;
@@ -57,11 +57,11 @@
         this.exceptionProbability = EXCEPTION_PROBA;
     }
 
-    public DispatchBeginNode exceptionEdge() {
+    public BeginNode exceptionEdge() {
         return exceptionEdge;
     }
 
-    public void setExceptionEdge(DispatchBeginNode x) {
+    public void setExceptionEdge(BeginNode x) {
         updatePredecessor(exceptionEdge, x);
         exceptionEdge = x;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -155,7 +155,7 @@
                 return;
             }
             for (PhiNode phi : phis()) {
-                if (phi.usages().filter(isNotA(FrameState.class)).and(node -> !merge.isPhiAtMerge(node)).isNotEmpty()) {
+                if (phi.usages().filter(isNotA(VirtualState.class)).and(node -> !merge.isPhiAtMerge(node)).isNotEmpty()) {
                     return;
                 }
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class UnaryOpLogicNode extends LogicNode implements LIRLowerable {
+
+    @Input private ValueNode object;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    protected void setX(ValueNode object) {
+        updateUsages(this.object, object);
+        this.object = object;
+    }
+
+    public UnaryOpLogicNode(ValueNode object) {
+        assert object != null;
+        this.object = object;
+    }
+
+    public abstract TriState evaluate(ValueNode forObject);
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java	Tue Apr 29 12:43:27 2014 -0700
@@ -45,6 +45,10 @@
 
     public abstract void applyToNonVirtual(NodeClosure<? super ValueNode> closure);
 
+    /**
+     * Performs a <b>pre-order</b> iteration over all elements reachable from this state that are a
+     * subclass of {@link VirtualState}.
+     */
     public abstract void applyToVirtual(VirtualClosure closure);
 
     public abstract boolean isPartOfThisState(VirtualState state);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -92,13 +92,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitAnd(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitAndMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -30,7 +30,7 @@
 /**
  * The {@code LogicNode} class definition.
  */
-public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable, NarrowableArithmeticNode {
+public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     /**
      * Constructs a new logic operation node.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.graph.*;
@@ -35,7 +36,7 @@
  * Compare should probably be made a value (so that it can be canonicalized for example) and in later stages some Compare usage should be transformed
  * into variants that do not materialize the value (CompareIf, CompareGuard...)
  */
-public abstract class CompareNode extends BinaryLogicNode implements Canonicalizable {
+public abstract class CompareNode extends BinaryOpLogicNode {
 
     /**
      * Constructs a new Compare instruction.
@@ -90,9 +91,18 @@
     }
 
     @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (x().isConstant() && y().isConstant()) {
+            return TriState.get(condition().foldCondition(x().asConstant(), y().asConstant(), constantReflection, unorderedIsTrue()));
+        }
+        return TriState.UNKNOWN;
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant() && tool.getMetaAccess() != null) {
-            return LogicConstantNode.forBoolean(condition().foldCondition(x().asConstant(), y().asConstant(), tool.getConstantReflection(), unorderedIsTrue()), graph());
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
         }
         if (x().isConstant()) {
             if (y() instanceof ConditionalNode) {
@@ -110,7 +120,7 @@
         if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
             ConvertNode convertX = (ConvertNode) x();
             ConvertNode convertY = (ConvertNode) y();
-            if (convertX.isLossless() && convertY.isLossless() && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) {
+            if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) {
                 setX(convertX.getInput());
                 setY(convertY.getInput());
             }
@@ -132,8 +142,8 @@
         return this;
     }
 
-    private static ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) {
-        if (convert.isLossless()) {
+    private ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) {
+        if (convert.preservesOrder(condition())) {
             Constant reverseConverted = convert.reverse(constant);
             if (convert.convert(reverseConverted).equals(constant)) {
                 return ConstantNode.forPrimitive(convert.getInput().stamp(), reverseConverted, convert.graph());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 
@@ -47,8 +48,23 @@
 
     public abstract Constant reverse(Constant c);
 
+    /**
+     * Check whether a conversion is lossless.
+     *
+     * @return true iff reverse(convert(c)) == c for all c
+     */
     public abstract boolean isLossless();
 
+    /**
+     * Check whether a conversion preserves comparison order.
+     *
+     * @param op a comparison operator
+     * @return true iff (c1 op c2) == (convert(c1) op convert(c2)) for all c1, c2
+     */
+    public boolean preservesOrder(Condition op) {
+        return isLossless();
+    }
+
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 1;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "+")
@@ -84,13 +84,4 @@
         }
         return false;
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitAddMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
-public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
 
     private final boolean isStrictFP;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,58 +24,19 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
  * A {@code FloatConvert} converts between integers and floating point numbers according to Java
  * semantics.
  */
-public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
-
-    public enum FloatConvert {
-        F2I,
-        D2I,
-        F2L,
-        D2L,
-        I2F,
-        L2F,
-        D2F,
-        I2D,
-        L2D,
-        F2D;
-
-        public FloatConvert reverse() {
-            switch (this) {
-                case D2F:
-                    return F2D;
-                case D2I:
-                    return I2D;
-                case D2L:
-                    return L2D;
-                case F2D:
-                    return D2F;
-                case F2I:
-                    return I2F;
-                case F2L:
-                    return L2F;
-                case I2D:
-                    return D2I;
-                case I2F:
-                    return F2I;
-                case L2D:
-                    return D2L;
-                case L2F:
-                    return F2L;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
+public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable {
 
     private final FloatConvert op;
 
@@ -205,12 +166,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getInput())));
     }
-
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitFloatConvertMemory(getOp(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "/")
@@ -60,13 +60,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitDiv(builder.operand(x()), builder.operand(y()), null));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitDivMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,17 +22,20 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "==")
 public final class FloatEqualsNode extends CompareNode {
 
     /**
      * Constructs a new floating point equality comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -51,4 +54,18 @@
     public boolean unorderedIsTrue() {
         return false;
     }
+
+    @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (forX.stamp() instanceof FloatStamp && forY.stamp() instanceof FloatStamp) {
+            FloatStamp xStamp = (FloatStamp) forX.stamp();
+            FloatStamp yStamp = (FloatStamp) forY.stamp();
+            if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && xStamp.isNonNaN() && yStamp.isNonNaN()) {
+                return TriState.TRUE;
+            } else if (xStamp.alwaysDistinct(yStamp)) {
+                return TriState.FALSE;
+            }
+        }
+        return super.evaluate(constantReflection, forX, forY);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,11 +22,13 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "<")
 public final class FloatLessThanNode extends CompareNode {
@@ -35,7 +37,7 @@
 
     /**
      * Constructs a new floating point comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      * @param unorderedIsTrue whether a comparison that is undecided (involving NaNs, etc.) leads to
@@ -59,10 +61,10 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y() && !unorderedIsTrue()) {
-            return LogicConstantNode.contradiction(graph());
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && !unorderedIsTrue()) {
+            return TriState.FALSE;
         }
-        return super.canonical(tool);
+        return super.evaluate(constantReflection, forX, forY);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "*")
@@ -70,13 +70,4 @@
         }
         builder.setResult(this, gen.emitMul(op1, op2));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitMulMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "%")
@@ -60,13 +60,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitRem(builder.operand(x()), builder.operand(y()), null));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitRemMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "-")
@@ -79,13 +79,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitSubMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,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	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -101,13 +101,4 @@
         }
         builder.setResult(this, gen.emitAdd(op1, op2));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitAddMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
 
     public IntegerArithmeticNode(Stamp stamp, ValueNode x, ValueNode y) {
         super(stamp, x, y);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,18 +23,20 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "|<|")
 public final class IntegerBelowThanNode extends CompareNode {
 
     /**
      * Constructs a new unsigned integer comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -55,28 +57,33 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return LogicConstantNode.contradiction(graph());
-        } else {
-            if (x().isConstant() && x().asConstant().asLong() == 0) {
-                // 0 |<| y is the same as 0 != y
-                return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y())));
-            }
-
-            if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
-                IntegerStamp xStamp = (IntegerStamp) x().stamp();
-                IntegerStamp yStamp = (IntegerStamp) y().stamp();
-                if (yStamp.isPositive()) {
-                    if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
-                        return LogicConstantNode.tautology(graph());
-                    } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
-                        return LogicConstantNode.contradiction(graph());
-                    }
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.FALSE;
+        } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+            if (yStamp.isPositive()) {
+                if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
+                    return TriState.TRUE;
+                } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
+                    return TriState.FALSE;
                 }
             }
         }
+        return super.evaluate(constantReflection, forX, forY);
+    }
 
-        return super.canonical(tool);
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
+        }
+        if (x().isConstant() && x().asConstant().asLong() == 0) {
+            // 0 |<| y is the same as 0 != y
+            return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y())));
+        }
+        return this;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -31,7 +31,7 @@
 /**
  * An {@code IntegerConvert} converts an integer to an integer of different width.
  */
-public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable, MemoryArithmeticLIRLowerable {
+public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable {
 
     private final int resultBits;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -108,7 +108,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitDiv(gen.operand(x()), gen.operand(y()), this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitDiv(gen.operand(x()), gen.operand(y()), gen.state(this)));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -35,7 +36,7 @@
 
     /**
      * Constructs a new integer equality comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -71,24 +72,28 @@
     }
 
     @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.TRUE;
+        } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+            return TriState.FALSE;
+        }
+        return super.evaluate(constantReflection, forX, forY);
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (GraphUtil.unproxify(x()) == GraphUtil.unproxify(y())) {
-            return LogicConstantNode.tautology(graph());
-        } else if (x().stamp().alwaysDistinct(y().stamp())) {
-            return LogicConstantNode.contradiction(graph());
-        }
-
-        ValueNode result = canonicalizeSymmetric(x(), y());
-        if (result != null) {
+        Node result = super.canonical(tool);
+        if (result != this) {
             return result;
         }
 
-        result = canonicalizeSymmetric(y(), x());
-        if (result != null) {
+        result = canonicalizeSymmetric(x(), y());
+        if (result != this) {
             return result;
         }
 
-        return super.canonical(tool);
+        return canonicalizeSymmetric(y(), x());
     }
 
     private ValueNode canonicalizeSymmetric(ValueNode x, ValueNode y) {
@@ -133,6 +138,6 @@
                 }
             }
         }
-        return null;
+        return this;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,18 +23,20 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "<")
 public final class IntegerLessThanNode extends CompareNode {
 
     /**
      * Constructs a new integer comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -71,22 +73,32 @@
     }
 
     @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.FALSE;
+        } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+            if (xStamp.upperBound() < yStamp.lowerBound()) {
+                return TriState.TRUE;
+            } else if (xStamp.lowerBound() >= yStamp.upperBound()) {
+                return TriState.FALSE;
+            }
+        }
+        return super.evaluate(constantReflection, forX, forY);
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return LogicConstantNode.contradiction(graph());
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
         }
         if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
-            IntegerStamp xStamp = (IntegerStamp) x().stamp();
-            IntegerStamp yStamp = (IntegerStamp) y().stamp();
-            if (xStamp.upperBound() < yStamp.lowerBound()) {
-                return LogicConstantNode.tautology(graph());
-            } else if (xStamp.lowerBound() >= yStamp.upperBound()) {
-                return LogicConstantNode.contradiction(graph());
-            }
-            if (IntegerStamp.sameSign(xStamp, yStamp)) {
+            if (IntegerStamp.sameSign((IntegerStamp) x().stamp(), (IntegerStamp) y().stamp())) {
                 return graph().unique(new IntegerBelowThanNode(x(), y()));
             }
         }
-        return super.canonical(tool);
+        return this;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,8 +27,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "*")
@@ -85,13 +85,4 @@
         }
         builder.setResult(this, gen.emitMul(op1, op2));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitMulMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -62,7 +62,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitRem(gen.operand(x()), gen.operand(y()), this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitRem(gen.operand(x()), gen.operand(y()), gen.state(this)));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -121,13 +121,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitSubMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -32,7 +32,7 @@
  * expression "(x &amp; y) == 0", meaning that it will return true if (and only if) no bit is set in
  * both x and y.
  */
-public class IntegerTestNode extends BinaryLogicNode implements Canonicalizable {
+public class IntegerTestNode extends BinaryOpLogicNode {
 
     /**
      * Constructs a new Test instruction.
@@ -45,19 +45,19 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant()) {
-            return LogicConstantNode.forBoolean((x().asConstant().asLong() & y().asConstant().asLong()) == 0, graph());
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            return TriState.get((forX.asConstant().asLong() & forY.asConstant().asLong()) == 0);
         }
         if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
-            IntegerStamp xStamp = (IntegerStamp) x().stamp();
-            IntegerStamp yStamp = (IntegerStamp) y().stamp();
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
             if ((xStamp.upMask() & yStamp.upMask()) == 0) {
-                return LogicConstantNode.tautology(graph());
+                return TriState.TRUE;
             } else if ((xStamp.downMask() & yStamp.downMask()) != 0) {
-                return LogicConstantNode.contradiction(graph());
+                return TriState.FALSE;
             }
         }
-        return this;
+        return TriState.UNKNOWN;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -33,21 +34,15 @@
 /**
  * An IsNullNode will be true if the supplied value is null, and false if it is non-null.
  */
-public final class IsNullNode extends LogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable {
-
-    @Input private ValueNode object;
-
-    public ValueNode object() {
-        return object;
-    }
+public final class IsNullNode extends UnaryOpLogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable {
 
     /**
      * Constructs a new IsNullNode instruction.
-     * 
+     *
      * @param object the instruction producing the object to check against null
      */
     public IsNullNode(ValueNode object) {
-        this.object = object;
+        super(object);
     }
 
     @Override
@@ -64,20 +59,31 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        Constant constant = object().asConstant();
-        if (constant != null) {
-            assert constant.getKind() == Kind.Object;
-            return LogicConstantNode.forBoolean(constant.isNull(), graph());
-        }
-        if (StampTool.isObjectNonNull(object.stamp())) {
-            return LogicConstantNode.contradiction(graph());
+        switch (evaluate(object())) {
+            case FALSE:
+                return LogicConstantNode.contradiction(graph());
+            case TRUE:
+                return LogicConstantNode.tautology(graph());
         }
         return this;
     }
 
     @Override
+    public TriState evaluate(ValueNode forObject) {
+        Constant constant = forObject.asConstant();
+        if (constant != null) {
+            assert constant.getKind() == Kind.Object;
+            return TriState.get(constant.isNull());
+        }
+        if (StampTool.isObjectNonNull(forObject.stamp())) {
+            return TriState.FALSE;
+        }
+        return TriState.UNKNOWN;
+    }
+
+    @Override
     public void virtualize(VirtualizerTool tool) {
-        if (tool.getObjectState(object) != null) {
+        if (tool.getObjectState(object()) != null) {
             tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -108,13 +108,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitNarrow(builder.operand(getInput()), getResultBits()));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitNarrowMemory(getResultBits(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,19 +23,21 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "==")
 public final class ObjectEqualsNode extends CompareNode implements Virtualizable {
 
     /**
      * Constructs a new object equality comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -56,21 +58,28 @@
     }
 
     @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.TRUE;
+        } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+            return TriState.FALSE;
+        } else {
+            return super.evaluate(constantReflection, forX, forY);
+        }
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return LogicConstantNode.tautology(graph());
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
         }
-
         if (StampTool.isObjectAlwaysNull(x())) {
             return graph().unique(new IsNullNode(y()));
         } else if (StampTool.isObjectAlwaysNull(y())) {
             return graph().unique(new IsNullNode(x()));
         }
-        if (x().stamp().alwaysDistinct(y().stamp())) {
-            return LogicConstantNode.contradiction(graph());
-        }
-
-        return super.canonical(tool);
+        return this;
     }
 
     private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -77,13 +77,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitOr(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitOrMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,8 +27,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -36,7 +36,7 @@
  * of a primitive value to some other incompatible stamp. The new stamp must have the same width as
  * the old stamp.
  */
-public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
 
     @Input private ValueNode value;
 
@@ -108,15 +108,6 @@
         builder.setResult(this, gen.emitReinterpret(kind, builder.operand(value())));
     }
 
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitReinterpretMemory(stamp(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
-
     public static ValueNode reinterpret(Kind toKind, ValueNode value) {
         return value.graph().unique(new ReinterpretNode(toKind, value));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -109,13 +109,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitSignExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitSignExtendMemory(access, getInputBits(), getResultBits());
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -72,7 +72,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitUDiv(gen.operand(x()), gen.operand(y()), this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitUDiv(gen.operand(x()), gen.operand(y()), gen.state(this)));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -71,7 +71,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitURem(gen.operand(x()), gen.operand(y()), this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitURem(gen.operand(x()), gen.operand(y()), gen.state(this)));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -76,13 +76,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitXor(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitXorMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,11 +23,12 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -64,6 +65,19 @@
     }
 
     @Override
+    public boolean preservesOrder(Condition op) {
+        switch (op) {
+            case GE:
+            case GT:
+            case LE:
+            case LT:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
         ValueNode ret = canonicalConvert();
         if (ret != null) {
@@ -102,13 +116,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitZeroExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitZeroExtendMemory(getInputBits(), getResultBits(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Tue Apr 29 12:43:27 2014 -0700
@@ -25,8 +25,8 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
 
 public final class Block extends AbstractBlockBase<Block> {
 
@@ -67,7 +67,8 @@
     }
 
     public boolean isExceptionEntry() {
-        return getBeginNode() instanceof ExceptionObjectNode;
+        Node predecessor = getBeginNode().predecessor();
+        return predecessor != null && predecessor instanceof InvokeWithExceptionNode && getBeginNode() == ((InvokeWithExceptionNode) predecessor).exceptionEdge();
     }
 
     public Block getFirstPredecessor() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -30,7 +30,7 @@
  * This node can be used to add a counter to the code that will estimate the dynamic number of calls
  * by adding an increment to the compiled code. This should of course only be used for
  * debugging/testing purposes.
- * 
+ *
  * A unique counter will be created for each unique name passed to the constructor. Depending on the
  * value of withContext, the name of the root method is added to the counter's name.
  */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
@@ -37,8 +38,8 @@
 @NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}")
 public final class AddLocationNode extends LocationNode implements Canonicalizable {
 
-    @Input private ValueNode x;
-    @Input private ValueNode y;
+    @Input(InputType.Association) private ValueNode x;
+    @Input(InputType.Association) private ValueNode y;
 
     protected LocationNode getX() {
         return (LocationNode) x;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -63,7 +63,7 @@
     public void generate(NodeLIRBuilderTool gen) {
         Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
         PlatformKind readKind = gen.getLIRGeneratorTool().getPlatformKind(stamp());
-        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, null));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -94,7 +94,7 @@
     public void generate(NodeLIRBuilderTool gen) {
         ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(descriptor);
         Value[] operands = operands(gen);
-        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, this, operands);
+        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), operands);
         if (result != null) {
             gen.setResult(this, result);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * A node that may be guarded by a {@linkplain GuardingNode guarding node}.
  */
-public interface GuardedNode {
+public interface GuardedNode extends NodeInterface {
 
     GuardingNode getGuard();
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
@@ -45,8 +43,8 @@
         super(kind == Kind.Object ? StampFactory.objectNonNull() : StampFactory.forKind(kind));
         this.hub = hub;
         this.method = method;
-        assert !Modifier.isAbstract(method.getModifiers()) : "Cannot load abstract method from a hub";
-        assert !Modifier.isStatic(method.getModifiers()) : "Cannot load a static method from a hub";
+        assert !method.isAbstract() : "Cannot load abstract method from a hub";
+        assert !method.isStatic() : "Cannot load a static method from a hub";
         assert method.isInVirtualMethodTable();
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.lang.reflect.*;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Tue Apr 29 12:43:27 2014 -0700
@@ -40,7 +40,7 @@
         /**
          * This method is used to determine which memory location is killed by this node. Returning
          * the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory locations.
-         * 
+         *
          * @return the identity of the location killed by this node.
          */
         LocationIdentity getLocationIdentity();
@@ -53,7 +53,7 @@
          * This method is used to determine which set of memory locations is killed by this node.
          * Returning the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory
          * locations.
-         * 
+         *
          * @return the identities of all locations killed by this node.
          */
         LocationIdentity[] getLocationIdentities();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * This interface marks nodes that are part of the memory graph.
  */
-public interface MemoryNode {
+public interface MemoryNode extends NodeInterface {
 
     ValueNode asNode();
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -57,7 +57,7 @@
     public void generate(NodeLIRBuilderTool gen) {
         Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
         PlatformKind readKind = gen.getLIRGeneratorTool().getPlatformKind(stamp());
-        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, gen.state(this)));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,7 @@
  * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Anchor, InputType.Guard})
-public final class ValueAnchorNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Virtualizable, GuardingNode {
+public final class ValueAnchorNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Virtualizable, AnchoringNode, GuardingNode {
 
     @Input(InputType.Guard) private ValueNode anchored;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -54,7 +54,7 @@
             v = gen.operand(value());
         }
         PlatformKind writeKind = gen.getLIRGeneratorTool().getPlatformKind(value().stamp());
-        gen.getLIRGeneratorTool().emitStore(writeKind, address, v, this);
+        gen.getLIRGeneratorTool().emitStore(writeKind, address, v, gen.state(this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
@@ -70,7 +68,7 @@
      * @return {@code true} if this field access is to a static field
      */
     public boolean isStatic() {
-        return Modifier.isStatic(field.getModifiers());
+        return field.isStatic();
     }
 
     /**
@@ -79,7 +77,7 @@
      * @return {@code true} if the field is resolved and declared volatile
      */
     public boolean isVolatile() {
-        return Modifier.isVolatile(field.getModifiers());
+        return field.isVolatile();
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.nodes.java;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
+
 import sun.misc.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,13 +22,14 @@
  */
 package com.oracle.graal.nodes.java;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
+
 import sun.misc.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.nodes.java;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,13 +22,9 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
@@ -37,6 +33,7 @@
  * The entry to an exception handler with the exception coming from a call (as opposed to a local
  * throw instruction or implicit exception).
  */
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
 public class ExceptionObjectNode extends DispatchBeginNode implements Lowerable, MemoryCheckpoint.Single {
 
     public ExceptionObjectNode(MetaAccessProvider metaAccess) {
@@ -49,56 +46,13 @@
     }
 
     @Override
-    public void simplify(SimplifierTool tool) {
-        //
-    }
-
-    private boolean isLowered() {
-        return (stamp() == StampFactory.forVoid());
-    }
-
-    /**
-     * The frame state upon entry to an exception handler is such that it is a
-     * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly
-     * the exception object (per the JVM spec) to rethrow. This means that the code creating this
-     * state (i.e. the {@link LoadExceptionObjectNode}) cannot cause a deoptimization as the
-     * runtime/interpreter would not have a valid location for the exception object to be rethrown.
-     */
-    @Override
     public void lower(LoweringTool tool) {
-        if (isLowered()) {
-            return;
-        }
-        LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(stamp()));
-        loadException.setStateAfter(stateAfter());
-        List<GuardedNode> guardedNodes = new ArrayList<>();
-        for (Node usage : usages().snapshot()) {
-            if (usage instanceof GuardedNode) {
-                // can't replace the guard with LoadExceptionObjectNode as it is not a GuardingNode
-                // so temporarily change it to remove the GuardedNode from usages
-                GuardedNode guardedNode = (GuardedNode) usage;
-                guardedNode.setGuard(graph().add(new BeginNode()));
-                guardedNodes.add(guardedNode);
-            }
-        }
-        replaceAtUsages(loadException);
-        for (GuardedNode guardedNode : guardedNodes) {
-            BeginNode dummyGuard = (BeginNode) guardedNode.getGuard();
-            guardedNode.setGuard(this);
-            graph().removeFixed(dummyGuard);
-        }
-        graph().addAfterFixed(this, loadException);
-        setStateAfter(null);
-        setStamp(StampFactory.forVoid());
-        loadException.lower(tool);
+        tool.getLowerer().lower(this, tool);
     }
 
     @Override
     public boolean verify() {
-        if (isLowered()) {
-            return true;
-        }
-        assertTrue(stateAfter() != null || stamp() == StampFactory.forVoid(), "an exception handler needs a frame state");
+        assertTrue(stateAfter() != null, "an exception handler needs a frame state");
         return super.verify();
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -33,21 +34,20 @@
 /**
  * The {@code InstanceOfNode} represents an instanceof test.
  */
-public final class InstanceOfNode extends LogicNode implements Canonicalizable, Lowerable, Virtualizable {
+public final class InstanceOfNode extends UnaryOpLogicNode implements Canonicalizable, Lowerable, Virtualizable {
 
-    @Input private ValueNode object;
     private final ResolvedJavaType type;
     private JavaTypeProfile profile;
 
     /**
      * Constructs a new InstanceOfNode.
-     * 
+     *
      * @param type the target type of the instanceof check
      * @param object the object being tested by the instanceof
      */
     public InstanceOfNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
+        super(object);
         this.type = type;
-        this.object = object;
         this.profile = profile;
         assert type != null;
     }
@@ -59,13 +59,39 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        Stamp stamp = object().stamp();
+        switch (evaluate(object())) {
+            case FALSE:
+                return LogicConstantNode.contradiction(graph());
+            case TRUE:
+                return LogicConstantNode.tautology(graph());
+            case UNKNOWN:
+                Stamp stamp = object().stamp();
+                if (stamp instanceof ObjectStamp) {
+                    ObjectStamp objectStamp = (ObjectStamp) stamp;
+                    ResolvedJavaType stampType = objectStamp.type();
+                    if (stampType != null && type().isAssignableFrom(stampType)) {
+                        if (!objectStamp.nonNull()) {
+                            // the instanceof matches if the object is non-null, so return true
+                            // depending on the null-ness.
+                            IsNullNode isNull = graph().unique(new IsNullNode(object()));
+                            return graph().unique(new LogicNegationNode(isNull));
+                        }
+                    }
+                }
+                return this;
+        }
+        return this;
+    }
+
+    @Override
+    public TriState evaluate(ValueNode forObject) {
+        Stamp stamp = forObject.stamp();
         if (!(stamp instanceof ObjectStamp)) {
-            return this;
+            return TriState.UNKNOWN;
         }
         ObjectStamp objectStamp = (ObjectStamp) stamp;
         if (objectStamp.alwaysNull()) {
-            return LogicConstantNode.contradiction(graph());
+            return TriState.FALSE;
         }
 
         ResolvedJavaType stampType = objectStamp.type();
@@ -74,34 +100,25 @@
             if (subType) {
                 if (objectStamp.nonNull()) {
                     // the instanceOf matches, so return true
-                    return LogicConstantNode.tautology(graph());
-                } else {
-                    // the instanceof matches if the object is non-null, so return true depending on
-                    // the null-ness.
-                    IsNullNode isNull = graph().unique(new IsNullNode(object()));
-                    return graph().unique(new LogicNegationNode(isNull));
+                    return TriState.TRUE;
                 }
             } else {
                 if (objectStamp.isExactType()) {
                     // since this type check failed for an exact type we know that it can never
                     // succeed at run time. we also don't care about null values, since they will
                     // also make the check fail.
-                    return LogicConstantNode.contradiction(graph());
+                    return TriState.FALSE;
                 } else {
                     boolean superType = stampType.isAssignableFrom(type());
                     if (!superType && !stampType.isInterface() && !type().isInterface()) {
-                        return LogicConstantNode.contradiction(graph());
+                        return TriState.FALSE;
                     }
                     // since the subtype comparison was only performed on a declared type we don't
                     // really know if it might be true at run time...
                 }
             }
         }
-        return this;
-    }
-
-    public ValueNode object() {
-        return object;
+        return TriState.UNKNOWN;
     }
 
     /**
@@ -121,7 +138,7 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
+        State state = tool.getObjectState(object());
         if (state != null) {
             tool.replaceWithValue(LogicConstantNode.forBoolean(type().isAssignableFrom(state.getVirtualObject().type()), graph()));
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.java;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * Loads an exception object passed by the runtime from a callee to an exception handler in a
- * caller. The node is only produced when lowering an {@link ExceptionObjectNode}.
- * <p>
- * The frame state upon entry to an exception handler is such that it is a
- * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly the
- * exception object (per the JVM spec) to rethrow. This means that the code generated for this node
- * must not cause a deoptimization as the runtime/interpreter would not have a valid location to
- * find the exception object to be rethrown.
- */
-public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
-
-    public LoadExceptionObjectNode(Stamp stamp) {
-        super(stamp);
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        tool.getLowerer().lower(this, tool);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,6 @@
 
 import static com.oracle.graal.graph.iterators.NodePredicates.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -99,7 +97,7 @@
     }
 
     private PhiNode asPhi(MetaAccessProvider metaAccess) {
-        if (!isStatic() && Modifier.isFinal(field.getModifiers()) && object() instanceof ValuePhiNode && ((ValuePhiNode) object()).values().filter(isNotA(ConstantNode.class)).isEmpty()) {
+        if (!isStatic() && field.isFinal() && object() instanceof ValuePhiNode && ((ValuePhiNode) object()).values().filter(isNotA(ConstantNode.class)).isEmpty()) {
             PhiNode phi = (PhiNode) object();
             Constant[] constants = new Constant[phi.valueCount()];
             for (int i = 0; i < phi.valueCount(); i++) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -109,12 +107,12 @@
             assertTrue(n instanceof Invoke, "call target can only be used from an invoke (%s)", n);
         }
         if (invokeKind == InvokeKind.Special || invokeKind == InvokeKind.Static) {
-            assertFalse(Modifier.isAbstract(targetMethod.getModifiers()), "special calls or static calls are only allowed for concrete methods (%s)", targetMethod);
+            assertFalse(targetMethod.isAbstract(), "special calls or static calls are only allowed for concrete methods (%s)", targetMethod);
         }
         if (invokeKind == InvokeKind.Static) {
-            assertTrue(Modifier.isStatic(targetMethod.getModifiers()), "static calls are only allowed for static methods (%s)", targetMethod);
+            assertTrue(targetMethod.isStatic(), "static calls are only allowed for static methods (%s)", targetMethod);
         } else {
-            assertFalse(Modifier.isStatic(targetMethod.getModifiers()), "static calls are only allowed for non-static methods (%s)", targetMethod);
+            assertFalse(targetMethod.isStatic(), "static calls are only allowed for non-static methods (%s)", targetMethod);
         }
         return super.verify();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -53,7 +53,7 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(REGISTER_FINALIZER);
-        gen.getLIRGeneratorTool().emitForeignCall(linkage, this, gen.operand(object()));
+        gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(object()));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.*;
@@ -66,7 +64,7 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        InvokeKind invokeKind = Modifier.isStatic(replacementTargetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special;
+        InvokeKind invokeKind = replacementTargetMethod.isStatic() ? 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/spi/ArithmeticLIRGenerator.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +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.spi;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-
-/**
- * This interface can be used to generate LIR for arithmetic operations.
- */
-public interface ArithmeticLIRGenerator {
-    /**
-     * TODO remove reference to {@link Stamp}.
-     */
-    PlatformKind getPlatformKind(Stamp stamp);
-
-    Value emitNegate(Value input);
-
-    Value emitAdd(Value a, Value b);
-
-    Value emitSub(Value a, Value b);
-
-    Value emitMul(Value a, Value b);
-
-    /**
-     * TODO remove {@link DeoptimizeNode}.
-     */
-    Value emitDiv(Value a, Value b, DeoptimizingNode deopting);
-
-    /**
-     * TODO remove {@link DeoptimizeNode}.
-     */
-    Value emitRem(Value a, Value b, DeoptimizingNode deopting);
-
-    /**
-     * TODO remove {@link DeoptimizeNode}.
-     */
-    Value emitUDiv(Value a, Value b, DeoptimizingNode deopting);
-
-    /**
-     * TODO remove {@link DeoptimizeNode}.
-     */
-    Value emitURem(Value a, Value b, DeoptimizingNode deopting);
-
-    Value emitNot(Value input);
-
-    Value emitAnd(Value a, Value b);
-
-    Value emitOr(Value a, Value b);
-
-    Value emitXor(Value a, Value b);
-
-    Value emitShl(Value a, Value b);
-
-    Value emitShr(Value a, Value b);
-
-    Value emitUShr(Value a, Value b);
-
-    Value emitFloatConvert(FloatConvert op, Value inputVal);
-
-    Value emitReinterpret(PlatformKind to, Value inputVal);
-
-    Value emitNarrow(Value inputVal, int bits);
-
-    Value emitSignExtend(Value inputVal, int fromBits, int toBits);
-
-    Value emitZeroExtend(Value inputVal, int fromBits, int toBits);
-
-    Value emitMathAbs(Value input);
-
-    Value emitMathSqrt(Value input);
-
-    Value emitMathLog(Value input, boolean base10);
-
-    Value emitMathCos(Value input);
-
-    Value emitMathSin(Value input);
-
-    Value emitMathTan(Value input);
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRLowerable.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRLowerable.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.spi;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.lir.gen.*;
 
 public interface ArithmeticLIRLowerable extends ArithmeticOperation {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +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.nodes.spi;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-
-public interface LIRGeneratorTool extends ArithmeticLIRGenerator {
-
-    TargetDescription target();
-
-    MetaAccessProvider getMetaAccess();
-
-    CodeCacheProvider getCodeCache();
-
-    ForeignCallsProvider getForeignCalls();
-
-    Value emitLoad(PlatformKind kind, Value address, Access access);
-
-    void emitStore(PlatformKind kind, Value address, Value input, Access access);
-
-    Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue);
-
-    /**
-     * Emit an atomic read-and-add instruction.
-     *
-     * @param address address of the value to be read and written
-     * @param delta the value to be added
-     */
-    default Value emitAtomicReadAndAdd(Value address, Value delta) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    /**
-     * Emit an atomic read-and-write instruction.
-     *
-     * @param address address of the value to be read and written
-     * @param newValue the new value to be written
-     */
-    default Value emitAtomicReadAndWrite(Value address, Value newValue) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    void emitDeoptimize(Value actionAndReason, Value failedSpeculation, DeoptimizingNode deopting);
-
-    Value emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args);
-
-    /**
-     * Checks whether the supplied constant can be used without loading it into a register for most
-     * operations, i.e., for commonly used arithmetic, logical, and comparison operations.
-     *
-     * @param c The constant to check.
-     * @return True if the constant can be used directly, false if the constant needs to be in a
-     *         register.
-     */
-    boolean canInlineConstant(Constant c);
-
-    boolean canStoreConstant(Constant c, boolean isCompressed);
-
-    RegisterAttributes attributes(Register register);
-
-    AllocatableValue newVariable(PlatformKind kind);
-
-    AllocatableValue emitMove(Value input);
-
-    void emitMove(AllocatableValue dst, Value src);
-
-    /**
-     * Emits an op that loads the address of some raw data.
-     *
-     * @param dst the variable into which the address is loaded
-     * @param data the data to be installed with the generated code
-     */
-    void emitData(AllocatableValue dst, byte[] data);
-
-    Value emitAddress(Value base, long displacement, Value index, int scale);
-
-    Value emitAddress(StackSlot slot);
-
-    void emitMembar(int barriers);
-
-    void emitUnwind(Value operand);
-
-    /**
-     * Called just before register allocation is performed on the LIR owned by this generator.
-     * Overriding implementations of this method must call the overridden method.
-     */
-    void beforeRegisterAllocation();
-
-    void emitIncomingValues(Value[] params);
-
-    /**
-     * Emits a return instruction. Implementations need to insert a move if the input is not in the
-     * correct location.
-     */
-    void emitReturn(Value input);
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,13 +22,14 @@
  */
 package com.oracle.graal.nodes.spi;
 
+import com.oracle.graal.graph.*;
 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 interface Lowerable extends NodeInterface {
 
     /**
      * Expand this node into lower level nodes expressing the same semantics. If the introduced
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.spi;
-
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Marks nodes which may be lowered in combination with a memory operation.
- */
-public interface MemoryArithmeticLIRLowerable {
-
-    /**
-     * Attempt to generate a memory form of a node operation. On platforms that support it this will
-     * be called when the merging is safe.
-     * 
-     * @param gen
-     * @param access the memory input which can potentially merge into this operation.
-     * @return null if it's not possible to emit a memory form of this operation. A non-null value
-     *         will be set as the operand of this node.
-     */
-    boolean generate(MemoryArithmeticLIRLowerer gen, Access access);
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.spi;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * This interface can be used to generate LIR for arithmetic operations where one of the operations
- * is load (@see ArithmeticLIRLowerable).
- */
-public interface MemoryArithmeticLIRLowerer {
-
-    Value setResult(ValueNode x, Value operand);
-
-    Value emitAddMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitMulMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitSubMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitDivMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitRemMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitXorMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitOrMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitAndMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitReinterpretMemory(Stamp stamp, Access access);
-
-    Value emitSignExtendMemory(Access access, int fromBits, int toBits);
-
-    Value emitNarrowMemory(int resultBits, Access access);
-
-    Value emitZeroExtendMemory(int inputBits, int resultBits, Access access);
-
-    Value emitFloatConvertMemory(FloatConvert op, Access access);
-
-    boolean memoryPeephole(Access valueNode, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred);
-
-    boolean emitIfMemory(IfNode ifNode, Access access);
-
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,12 +26,19 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 
 public interface NodeLIRBuilderTool extends NodeMappableLIRBuilder {
 
+    // TODO (je) remove and move into the Node
+    LIRFrameState state(DeoptimizingNode deopt);
+
     void emitNullCheck(ValueNode v, DeoptimizingNode deopting);
 
     void emitIf(IfNode i);
@@ -63,5 +70,13 @@
 
     Value[] visitInvokeArguments(CallingConvention cc, Collection<ValueNode> arguments);
 
-    MemoryArithmeticLIRLowerer getMemoryLowerer();
+    Variable newVariable(Kind kind);
+
+    void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+
+    void emitBitCount(Variable result, Value operand);
+
+    void emitBitScanForward(Variable result, Value operand);
+
+    void doBlock(Block block, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Tue Apr 29 12:43:27 2014 -0700
@@ -29,9 +29,7 @@
 /**
  * Interface for nodes which have {@link FrameState} nodes as input.
  */
-public interface NodeWithState {
-
-    Node asNode();
+public interface NodeWithState extends NodeInterface {
 
     default NodeIterable<FrameState> states() {
         return asNode().inputs().filter(FrameState.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,11 +24,12 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 
 /**
  * Interface for service providers that register replacements with the compiler.
  */
 public interface ReplacementsProvider {
 
-    void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target);
+    void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Tue Apr 29 12:43:27 2014 -0700
@@ -506,22 +506,22 @@
     }
 
     /**
-     * Returns the {@linkplain ResolvedJavaType java type} this {@linkplain ValueNode} has if it is
+     * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain ValueNode} has if it is
      * a {@linkplain Stamp#isLegal() legal} Object value.
      *
      * @param node the node to check
-     * @return the javat type this value has if it is a legal Object type, null otherwise
+     * @return the Java type this value has if it is a legal Object type, null otherwise
      */
     public static ResolvedJavaType typeOrNull(ValueNode node) {
         return typeOrNull(node.stamp());
     }
 
     /**
-     * Returns the {@linkplain ResolvedJavaType java type} this {@linkplain Stamp} has if it is a
+     * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain Stamp} has if it is a
      * {@linkplain Stamp#isLegal() legal} Object stamp.
      *
      * @param stamp the stamp to check
-     * @return the java type this stamp has if it is a legal Object stamp, null otherwise
+     * @return the Java type this stamp has if it is a legal Object stamp, null otherwise
      */
     public static ResolvedJavaType typeOrNull(Stamp stamp) {
         if (stamp instanceof ObjectStamp && stamp.isLegal()) {
@@ -532,12 +532,12 @@
 
     /**
      * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#isLegal() legal} Object
-     * value whose java type is known exactly. If this method returns true then the
-     * {@linkplain ResolvedJavaType java type} returned by {@link #typeOrNull(ValueNode)} is the
-     * concrete dynamic/runtime java type of this value.
+     * value whose Java type is known exactly. If this method returns true then the
+     * {@linkplain ResolvedJavaType Java type} returned by {@link #typeOrNull(ValueNode)} is the
+     * concrete dynamic/runtime Java type of this value.
      *
      * @param node the node to check
-     * @return true if this node represents a legal object value whose java type is known exactly
+     * @return true if this node represents a legal object value whose Java type is known exactly
      */
     public static boolean isExactType(ValueNode node) {
         return isExactType(node.stamp());
@@ -545,12 +545,12 @@
 
     /**
      * Checks whether this {@link Stamp} represents a {@linkplain Stamp#isLegal() legal} Object
-     * stamp whose {@linkplain ResolvedJavaType java type} is known exactly. If this method returns
-     * true then the java type returned by {@link #typeOrNull(Stamp)} is the only concrete
-     * dynamic/runtime java type possible for values of this stamp.
+     * stamp whose {@linkplain ResolvedJavaType Java type} is known exactly. If this method returns
+     * true then the Java type returned by {@link #typeOrNull(Stamp)} is the only concrete
+     * dynamic/runtime Java type possible for values of this stamp.
      *
      * @param stamp the stamp to check
-     * @return true if this node represents a legal object stamp whose java type is known exactly
+     * @return true if this node represents a legal object stamp whose Java type is known exactly
      */
     public static boolean isExactType(Stamp stamp) {
         if (stamp instanceof ObjectStamp && stamp.isLegal()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
@@ -42,12 +43,12 @@
         }
     };
 
-    public static void killCFG(Node node) {
+    public static void killCFG(Node node, SimplifierTool tool) {
         assert node.isAlive();
         if (node instanceof AbstractEndNode) {
             // We reached a control flow end.
             AbstractEndNode end = (AbstractEndNode) node;
-            killEnd(end);
+            killEnd(end, tool);
         } else {
             // Normal control flow node.
             /*
@@ -57,13 +58,17 @@
              * while processing one branch.
              */
             for (Node successor : node.successors()) {
-                killCFG(successor);
+                killCFG(successor, tool);
             }
         }
         propagateKill(node);
     }
 
-    private static void killEnd(AbstractEndNode end) {
+    public static void killCFG(Node node) {
+        killCFG(node, null);
+    }
+
+    private static void killEnd(AbstractEndNode end, SimplifierTool tool) {
         MergeNode merge = end.merge();
         if (merge != null) {
             merge.removeEnd(end);
@@ -85,12 +90,17 @@
                     killCFG(loopBody);
                 }
                 begin.safeDelete();
-            } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not
-                                                                                                         // a
-                                                                                                         // loop
-                                                                                                         // anymore
+            } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) {
+                // not a loop anymore
+                if (tool != null) {
+                    merge.phis().forEach(phi -> phi.usages().forEach(usage -> tool.addToWorkList(usage)));
+                }
                 graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
-            } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore
+            } else if (merge.phiPredecessorCount() == 1) {
+                // not a merge anymore
+                if (tool != null) {
+                    merge.phis().forEach(phi -> phi.usages().forEach(usage -> tool.addToWorkList(usage)));
+                }
                 graph.reduceTrivialMerge(merge);
             }
         }
@@ -137,6 +147,13 @@
     }
 
     public static void removeFixedWithUnusedInputs(FixedWithNextNode fixed) {
+        if (fixed instanceof StateSplit) {
+            FrameState stateAfter = ((StateSplit) fixed).stateAfter();
+            ((StateSplit) fixed).setStateAfter(null);
+            if (stateAfter.usages().isEmpty()) {
+                killWithUnusedFloatingInputs(stateAfter);
+            }
+        }
         FixedNode next = fixed.next();
         fixed.setNext(null);
         fixed.replaceAtPredecessor(next);
@@ -326,6 +343,14 @@
         return v;
     }
 
+    public static boolean tryKillUnused(Node node) {
+        if (node.isAlive() && isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) {
+            killWithUnusedFloatingInputs(node);
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Exhaustive search for {@link GraphUtil#originalValue(ValueNode)} when a simple search fails.
      * This can happen in the presence of complicated phi/proxy/phi constructs.
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java	Tue Apr 29 12:43:27 2014 -0700
@@ -40,8 +40,10 @@
  *
  * <pre>
  * ServiceLoader&lt;Options&gt; sl = ServiceLoader.loadInstalled(Options.class);
- * for (OptionDescriptor desc : sl) {
- *     // use desc
+ * for (Options opts : sl) {
+ *     for (OptionDescriptor desc : sl) {
+ *         // use desc
+ *     }
  * }
  * </pre>
  */
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -178,7 +178,7 @@
                 }
                 StructuredGraph graph = (StructuredGraph) node.graph();
                 Mark mark = graph.getMark();
-                if (!tryKillUnused(node)) {
+                if (!GraphUtil.tryKillUnused(node)) {
                     if (!tryCanonicalize(node, nodeClass)) {
                         if (node instanceof ValueNode) {
                             ValueNode valueNode = (ValueNode) node;
@@ -200,14 +200,6 @@
             }
         }
 
-        private static boolean tryKillUnused(Node node) {
-            if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) {
-                GraphUtil.killWithUnusedFloatingInputs(node);
-                return true;
-            }
-            return false;
-        }
-
         public static boolean tryGlobalValueNumbering(Node node, NodeClass nodeClass) {
             if (nodeClass.valueNumberable() && !nodeClass.isLeafNode()) {
                 Node newNode = node.graph().findDuplicate(node);
@@ -354,7 +346,7 @@
             @Override
             public void deleteBranch(Node branch) {
                 branch.predecessor().replaceFirstSuccessor(branch, null);
-                GraphUtil.killCFG(branch);
+                GraphUtil.killCFG(branch, this);
             }
 
             /**
@@ -383,7 +375,7 @@
 
             @Override
             public void removeIfUnused(Node node) {
-                tryKillUnused(node);
+                GraphUtil.tryKillUnused(node);
             }
 
             @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.phases.common;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -815,7 +814,7 @@
                         if (!Objects.equals(type, StampTool.typeOrNull(receiver))) {
                             ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod());
                             if (method != null) {
-                                if (method.canBeStaticallyBound() || Modifier.isFinal(type.getModifiers())) {
+                                if (method.canBeStaticallyBound() || type.isFinal()) {
                                     callTarget.setInvokeKind(InvokeKind.Special);
                                     callTarget.setTargetMethod(method);
                                 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -40,6 +40,11 @@
         this.canonicalizer = canonicalizer;
     }
 
+    public IncrementalCanonicalizerPhase(CanonicalizerPhase canonicalizer, BasePhase<? super C> phase) {
+        this.canonicalizer = canonicalizer;
+        appendPhase(phase);
+    }
+
     @Override
     protected void run(StructuredGraph graph, C context) {
         Mark newNodesMark = graph.getMark();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -174,28 +174,30 @@
         Mark markBeforeInlining = callerGraph.getMark();
         InlineInfo callee = calleeInfo.callee();
         try {
-            List<Node> invokeUsages = callee.invoke().asNode().usages().snapshot();
-            callee.inline(new Providers(context), callerAssumptions);
-            callerAssumptions.record(calleeInfo.assumptions());
-            metricInliningRuns.increment();
-            Debug.dump(callerGraph, "after %s", callee);
+            try (Scope scope = Debug.scope("doInline", callerGraph)) {
+                List<Node> invokeUsages = callee.invoke().asNode().usages().snapshot();
+                callee.inline(new Providers(context), callerAssumptions);
+                callerAssumptions.record(calleeInfo.assumptions());
+                metricInliningRuns.increment();
+                Debug.dump(callerGraph, "after %s", callee);
 
-            if (OptCanonicalizer.getValue()) {
-                Mark markBeforeCanonicalization = callerGraph.getMark();
-                canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining);
+                if (OptCanonicalizer.getValue()) {
+                    Mark markBeforeCanonicalization = callerGraph.getMark();
+                    canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining);
 
-                // process invokes that are possibly created during canonicalization
-                for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
-                    if (newNode instanceof Invoke) {
-                        callerGraphInfo.pushInvoke((Invoke) newNode);
+                    // process invokes that are possibly created during canonicalization
+                    for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
+                        if (newNode instanceof Invoke) {
+                            callerGraphInfo.pushInvoke((Invoke) newNode);
+                        }
                     }
                 }
-            }
+
+                callerGraphInfo.computeProbabilities();
 
-            callerGraphInfo.computeProbabilities();
-
-            inliningCount++;
-            metricInliningPerformed.increment();
+                inliningCount++;
+                metricInliningPerformed.increment();
+            }
         } catch (BailoutException bailout) {
             throw bailout;
         } catch (AssertionError | RuntimeException e) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,9 +26,6 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.compiler.common.type.StampFactory.*;
-import static java.lang.reflect.Modifier.*;
-
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -140,13 +137,12 @@
      */
     private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final int inliningDepth, final boolean success, final String msg, final Object... args) {
         if (HotSpotPrintInlining.getValue()) {
-            final int mod = method.getModifiers();
             // 1234567
             TTY.print("        ");     // print timestamp
             // 1234
             TTY.print("     ");        // print compilation number
             // % s ! b n
-            TTY.print("%c%c%c%c%c ", ' ', Modifier.isSynchronized(mod) ? 's' : ' ', ' ', ' ', Modifier.isNative(mod) ? 'n' : ' ');
+            TTY.print("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' ');
             TTY.print("     ");        // more indent
             TTY.print("    ");         // initial inlining indent
             for (int i = 0; i < inliningDepth; i++) {
@@ -435,7 +431,7 @@
             super(invoke);
             this.concrete = concrete;
             this.type = type;
-            assert type.isArray() || !isAbstract(type.getModifiers()) : type;
+            assert type.isArray() || !type.isAbstract() : type;
         }
 
         @Override
@@ -1114,7 +1110,7 @@
 
     private static InlineInfo getAssumptionInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete,
                     Assumption takenAssumption) {
-        assert !Modifier.isAbstract(concrete.getModifiers());
+        assert !concrete.isAbstract();
         if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
             return null;
         }
@@ -1122,7 +1118,7 @@
     }
 
     private static InlineInfo getExactInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod targetMethod) {
-        assert !Modifier.isAbstract(targetMethod.getModifiers());
+        assert !targetMethod.isAbstract();
         if (!checkTargetConditions(data, replacements, invoke, targetMethod, optimisticOpts)) {
             return null;
         }
@@ -1152,7 +1148,7 @@
             }
 
             ResolvedJavaType type = ptypes[0].getType();
-            assert type.isArray() || !isAbstract(type.getModifiers());
+            assert type.isArray() || !type.isAbstract();
             ResolvedJavaMethod concrete = type.resolveMethod(targetMethod);
             if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
                 return null;
@@ -1224,7 +1220,7 @@
                 if (index == -1) {
                     notRecordedTypeProbability += type.getProbability();
                 } else {
-                    assert type.getType().isArray() || !isAbstract(type.getType().getModifiers()) : type + " " + concrete;
+                    assert type.getType().isArray() || !type.getType().isAbstract() : type + " " + concrete;
                     usedTypes.add(type);
                     typesToConcretes.add(index);
                 }
@@ -1277,9 +1273,9 @@
     private static boolean checkTargetConditions(InliningData data, Replacements replacements, Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) {
         if (method == null) {
             return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method is not resolved");
-        } else if (Modifier.isNative(method.getModifiers()) && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(replacements, method))) {
+        } else if (method.isNative() && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(replacements, method))) {
             return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is a non-intrinsic native method");
-        } else if (Modifier.isAbstract(method.getModifiers())) {
+        } else if (method.isAbstract()) {
             return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is an abstract method");
         } else if (!method.getDeclaringClass().isInitialized()) {
             return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method's class is not initialized");
@@ -1320,8 +1316,6 @@
         assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
         assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase";
 
-        Kind returnKind = invokeNode.getKind();
-
         FrameState stateAfter = invoke.stateAfter();
         assert stateAfter == null || stateAfter.isAlive();
         if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) {
@@ -1405,38 +1399,8 @@
         }
 
         if (stateAfter != null) {
-            FrameState outerFrameState = null;
+            processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge);
             int callerLockDepth = stateAfter.nestedLockDepth();
-            for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
-                FrameState frameState = (FrameState) duplicates.get(original);
-                if (frameState != null && frameState.isAlive()) {
-                    assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
-                    if (frameState.bci == BytecodeFrame.AFTER_BCI) {
-                        frameState.replaceAndDelete(returnKind == Kind.Void ? stateAfter : stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), returnKind,
-                                        frameState.stackAt(0)));
-                    } else if (frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized())) {
-                        if (stateAtExceptionEdge != null) {
-                            frameState.replaceAndDelete(stateAtExceptionEdge);
-                        } else {
-                            handleMissingAfterExceptionFrameState(frameState);
-                        }
-                    } else if (frameState.bci == BytecodeFrame.UNWIND_BCI) {
-                        handleMissingAfterExceptionFrameState(frameState);
-                    } else {
-                        // only handle the outermost frame states
-                        if (frameState.outerFrameState() == null) {
-                            assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
-                            assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI &&
-                                            frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci;
-                            if (outerFrameState == null) {
-                                outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invokeNode.getKind());
-                                outerFrameState.setDuringCall(true);
-                            }
-                            frameState.setOuterFrameState(outerFrameState);
-                        }
-                    }
-                }
-            }
             if (callerLockDepth != 0) {
                 for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) {
                     MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
@@ -1474,10 +1438,61 @@
         return duplicates;
     }
 
-    protected static void handleMissingAfterExceptionFrameState(FrameState nonReplacableFrameState) {
-        Graph graph = nonReplacableFrameState.graph();
+    protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map<Node, Node> duplicates, FrameState stateAtExceptionEdge) {
+        FrameState stateAtReturn = invoke.stateAfter();
+        FrameState outerFrameState = null;
+        Kind invokeReturnKind = invoke.asNode().getKind();
+        for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
+            FrameState frameState = (FrameState) duplicates.get(original);
+            if (frameState != null && frameState.isAlive()) {
+                if (frameState.bci == BytecodeFrame.AFTER_BCI) {
+                    /*
+                     * pop return kind from invoke's stateAfter and replace with this frameState's
+                     * return value (top of stack)
+                     */
+                    FrameState stateAfterReturn = stateAtReturn;
+                    if (invokeReturnKind != Kind.Void && frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)) {
+                        stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0));
+                    }
+                    frameState.replaceAndDelete(stateAfterReturn);
+                } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) {
+                    /*
+                     * pop exception object from invoke's stateAfter and replace with this
+                     * frameState's exception object (top of stack)
+                     */
+                    FrameState stateAfterException = stateAtExceptionEdge;
+                    if (frameState.stackSize() > 0 && stateAtExceptionEdge.stackAt(0) != frameState.stackAt(0)) {
+                        stateAfterException = stateAtExceptionEdge.duplicateModified(Kind.Object, frameState.stackAt(0));
+                    }
+                    frameState.replaceAndDelete(stateAfterException);
+                } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+                    handleMissingAfterExceptionFrameState(frameState);
+                } else {
+                    // only handle the outermost frame states
+                    if (frameState.outerFrameState() == null) {
+                        assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
+                        assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
+                        assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI &&
+                                        frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci;
+                        if (outerFrameState == null) {
+                            outerFrameState = stateAtReturn.duplicateModified(invoke.bci(), stateAtReturn.rethrowException(), invokeReturnKind);
+                            outerFrameState.setDuringCall(true);
+                        }
+                        frameState.setOuterFrameState(outerFrameState);
+                    }
+                }
+            }
+        }
+    }
+
+    private static boolean isStateAfterException(FrameState frameState) {
+        return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized());
+    }
+
+    protected static void handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState) {
+        Graph graph = nonReplaceableFrameState.graph();
         NodeWorkList workList = graph.createNodeWorkList();
-        workList.add(nonReplacableFrameState);
+        workList.add(nonReplaceableFrameState);
         for (Node node : workList) {
             FrameState fs = (FrameState) node;
             for (Node usage : fs.usages().snapshot()) {
@@ -1498,7 +1513,10 @@
                             GraphUtil.killCFG(end);
                         }
                     } else {
-                        DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                        FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                        if (fixedStateSplit instanceof BeginNode) {
+                            deoptimizeNode = BeginNode.begin(deoptimizeNode);
+                        }
                         fixedStateSplit.replaceAtPredecessor(deoptimizeNode);
                         GraphUtil.killCFG(fixedStateSplit);
                     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -62,7 +62,7 @@
             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);
+                throw new BailoutException("Number of iterations in ConditionalEliminationPhase phase exceeds " + MAX_ITERATIONS);
             }
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -240,14 +240,20 @@
 
         private final PhaseContext context;
         private final SchedulePhase schedule;
+        private final int iteration;
 
         private Round(int iteration, PhaseContext context) {
-            super("LoweringIteration" + iteration);
+            this.iteration = iteration;
             this.context = context;
             this.schedule = new SchedulePhase();
         }
 
         @Override
+        protected CharSequence createName() {
+            return "LoweringIteration" + iteration;
+        }
+
+        @Override
         public void run(StructuredGraph graph) {
             schedule.apply(graph, false);
             processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -55,8 +55,11 @@
 
     private static final String GROUP_NAME = "~profiled weight";
     private static final String GROUP_NAME_WITHOUT = "~profiled weight (invoke-free sections)";
+    private static final String GROUP_NAME_INVOKES = "~profiled invokes";
 
     private static final boolean WITH_SECTION_HEADER = false;
+    private static boolean WITH_INVOKE_FREE_SECTIONS = false;
+    private static boolean WITH_INVOKES = true;
 
     @Override
     protected void run(StructuredGraph graph) {
@@ -72,7 +75,22 @@
                 addSectionCounters(loop.header.getBeginNode(), loop.blocks, loop.children, schedule, probabilities);
             }
         }
-        addSectionCounters(graph.start(), Arrays.asList(cfg.getBlocks()), cfg.getLoops(), schedule, probabilities);
+        // don't put the counter increase directly after the start (problems with OSR)
+        FixedWithNextNode current = graph.start();
+        while (current.next() instanceof FixedWithNextNode) {
+            current = (FixedWithNextNode) current.next();
+        }
+        addSectionCounters(current, Arrays.asList(cfg.getBlocks()), cfg.getLoops(), schedule, probabilities);
+
+        if (WITH_INVOKES) {
+            for (Node node : graph.getNodes()) {
+                if (node instanceof Invoke) {
+                    Invoke invoke = (Invoke) node;
+                    DynamicCounterNode.addCounterBefore(GROUP_NAME_INVOKES, invoke.callTarget().targetName(), 1, true, invoke.asNode());
+
+                }
+            }
+        }
     }
 
     private static void addSectionCounters(FixedWithNextNode start, Collection<Block> sectionBlocks, Collection<Loop<Block>> childLoops, SchedulePhase schedule, NodesToDoubles probabilities) {
@@ -82,7 +100,7 @@
         }
         double weight = getSectionWeight(schedule, probabilities, blocks) / probabilities.get(start);
         DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next());
-        if (!hasInvoke(blocks)) {
+        if (WITH_INVOKE_FREE_SECTIONS && !hasInvoke(blocks)) {
             DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), (long) weight, true, start.next());
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,233 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.spi.CanonicalizerTool;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.phases.graph.PostOrderNodeIterator;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import java.util.ArrayList;
+
+/**
+ * <p>
+ * For readability purposes the code realizing control-flow-sensitive reductions is chopped into
+ * several classes in an inheritance hierarchy, this class being their common ancestor. That way,
+ * many dependencies can be ruled out immediately (e.g., private members of a class aren't needed by
+ * other classes). The whole thing is reminiscent of trait-based patterns, minus their
+ * disadvantages.
+ * </p>
+ *
+ *
+ * <p>
+ * This class makes available little more than a few fields and a few utility methods used
+ * throughout the remaining components making up control-flow sensitive reductions.
+ * </p>
+ */
+public abstract class BaseReduction extends PostOrderNodeIterator<State> {
+
+    protected static final DebugMetric metricCheckCastRemoved = Debug.metric("CheckCastRemoved");
+    protected static final DebugMetric metricGuardingPiNodeRemoved = Debug.metric("GuardingPiNodeRemoved");
+    protected static final DebugMetric metricFixedGuardNodeRemoved = Debug.metric("FixedGuardNodeRemoved");
+    protected static final DebugMetric metricMethodResolved = Debug.metric("MethodResolved");
+
+    /**
+     * <p>
+     * Upon visiting a {@link com.oracle.graal.nodes.FixedNode FixedNode} in
+     * {@link #node(com.oracle.graal.nodes.FixedNode)}, an impossible path may be detected. We'd
+     * like to insert an unconditional deoptimizing node as a hint for Dead Code Elimination to kill
+     * that branch. However that can't be made on the go (a
+     * {@link com.oracle.graal.nodes.ControlSinkNode} can't have successors). Thus their insertion
+     * is postponed till the end of a round of
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}.
+     * </p>
+     *
+     * @see State#impossiblePath()
+     * @see com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#finished()
+     */
+    public static class PostponedDeopt {
+
+        private final boolean goesBeforeFixed;
+        private final FixedWithNextNode fixed;
+        private final DeoptimizationReason deoptReason;
+
+        public PostponedDeopt(boolean goesBeforeFixed, FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+            this.goesBeforeFixed = goesBeforeFixed;
+            this.fixed = fixed;
+            this.deoptReason = deoptReason;
+        }
+
+        public void doRewrite(LogicNode falseConstant) {
+            StructuredGraph graph = fixed.graph();
+            // have to insert a FixedNode other than a ControlSinkNode
+            FixedGuardNode buckStopsHere = graph.add(new FixedGuardNode(falseConstant, deoptReason, DeoptimizationAction.None));
+            if (goesBeforeFixed) {
+                fixed.replaceAtPredecessor(buckStopsHere);
+            } else {
+                graph.addAfterFixed(fixed, buckStopsHere);
+            }
+        }
+
+    }
+
+    protected static class PostponedDeopts extends ArrayList<PostponedDeopt> {
+
+        private static final long serialVersionUID = 7188324432387121238L;
+
+        /**
+         * Enqueue adding a {@link com.oracle.graal.nodes.DeoptimizeNode} right before the fixed
+         * argument, will be done once we're done traversing the graph.
+         *
+         * @see #finished()
+         */
+        void addDeoptBefore(FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+            add(new PostponedDeopt(true, fixed, deoptReason));
+        }
+
+        /**
+         * Enqueue adding a {@link com.oracle.graal.nodes.DeoptimizeNode} right after the fixed
+         * argument, will be done once we're done traversing the graph.
+         *
+         * @see #finished()
+         */
+        void addDeoptAfter(FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+            add(new PostponedDeopt(false, fixed, deoptReason));
+        }
+
+    }
+
+    /**
+     * <p>
+     * One of the promises of
+     * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+     * is that a "maximally reduced" node is returned. That is achieved in part by leveraging
+     * {@link com.oracle.graal.graph.Node#canonical(com.oracle.graal.graph.spi.CanonicalizerTool)}.
+     * Doing so, in turn, requires this subclass of
+     * {@link com.oracle.graal.graph.spi.CanonicalizerTool}.
+     * </p>
+     */
+    public final class Tool implements CanonicalizerTool {
+
+        private final PhaseContext context;
+
+        public Tool(PhaseContext context) {
+            this.context = context;
+        }
+
+        @Override
+        public Assumptions assumptions() {
+            return context.getAssumptions();
+        }
+
+        @Override
+        public MetaAccessProvider getMetaAccess() {
+            return context.getMetaAccess();
+        }
+
+        @Override
+        public ConstantReflectionProvider getConstantReflection() {
+            return context.getConstantReflection();
+        }
+
+        /**
+         * Postpone
+         * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)}
+         * until {@link FlowSensitiveReduction#finished()} for the reasons covered there.
+         */
+        @Override
+        public void removeIfUnused(Node node) {
+            // GraphUtil.tryKillUnused(node);
+        }
+
+        @Override
+        public boolean canonicalizeReads() {
+            return false;
+        }
+    } // end of class FlowSensitiveReduction.Tool
+
+    protected final LogicConstantNode trueConstant;
+    protected final LogicConstantNode falseConstant;
+    protected final ConstantNode nullConstant;
+
+    protected final CanonicalizerTool tool;
+    protected final StructuredGraph graph;
+
+    protected EquationalReasoner reasoner;
+
+    protected final PostponedDeopts postponedDeopts = new PostponedDeopts();
+
+    protected BaseReduction(FixedNode start, State initialState, PhaseContext context) {
+        super(start, initialState);
+        graph = start.graph();
+        trueConstant = LogicConstantNode.tautology(graph);
+        falseConstant = LogicConstantNode.contradiction(graph);
+        nullConstant = ConstantNode.defaultForKind(Kind.Object, graph); // ConstantNode.forObject(null,
+                                                                        // metaAccess, graph);
+        tool = new Tool(context);
+        reasoner = new EquationalReasoner(graph, tool, trueConstant, falseConstant, nullConstant);
+    }
+
+    /**
+     * <p>
+     * Test whether the output's stamp is an upcast of that of the input. For example, upon
+     * replacing a CheckCastNode in
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode, com.oracle.graal.nodes.ValueNode)}
+     * we don't want to be left with an upcast, as it loses precision.
+     * </p>
+     *
+     * <p>
+     * As usual with object stamps, they can be compared along different dimensions (alwaysNull,
+     * etc.) It's enough for one such dimension to show precision loss for the end result to be
+     * reported as such.
+     * </p>
+     *
+     */
+    public static boolean precisionLoss(ValueNode input, ValueNode output) {
+        ObjectStamp inputStamp = (ObjectStamp) input.stamp();
+        ObjectStamp outputStamp = (ObjectStamp) output.stamp();
+        if (FlowUtil.isMorePrecise(inputStamp.type(), outputStamp.type())) {
+            return true;
+        }
+        if (lessThan(outputStamp.alwaysNull(), inputStamp.alwaysNull())) {
+            return true;
+        }
+        if (lessThan(outputStamp.nonNull(), inputStamp.nonNull())) {
+            return true;
+        }
+        if (lessThan(outputStamp.isExactType(), inputStamp.isExactType())) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean lessThan(boolean a, boolean b) {
+        return a == false && b == true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CastCheckExtractor.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,87 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.nodes.LogicNode;
+import com.oracle.graal.nodes.ShortCircuitOrNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.java.InstanceOfNode;
+
+/**
+ * @see #extract(com.oracle.graal.nodes.LogicNode)
+ */
+class CastCheckExtractor {
+
+    public final ResolvedJavaType type;
+    public final ValueNode subject;
+
+    CastCheckExtractor(ResolvedJavaType type, ValueNode subject) {
+        this.type = type;
+        this.subject = subject;
+    }
+
+    private static CastCheckExtractor extractCastCheckInfo(LogicNode x, LogicNode y) {
+        if (x instanceof IsNullNode) {
+            IsNullNode isNull = (IsNullNode) x;
+            ValueNode subject = isNull.object();
+            if (isInstanceOfCheckOn(y, subject)) {
+                InstanceOfNode iOf = (InstanceOfNode) y;
+                return new CastCheckExtractor(iOf.type(), subject);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This method detects whether the argument realizes the CheckCast pattern. If so, distills and
+     * returns the essentials of such check, otherwise returns null.
+     */
+    static CastCheckExtractor extract(LogicNode cond) {
+        if (!(cond instanceof ShortCircuitOrNode)) {
+            return null;
+        }
+        ShortCircuitOrNode orNode = (ShortCircuitOrNode) cond;
+        if (orNode.isXNegated() || orNode.isYNegated()) {
+            return null;
+        }
+        CastCheckExtractor result = extractCastCheckInfo(orNode.getX(), orNode.getY());
+        if (result != null) {
+            return result;
+        }
+        result = extractCastCheckInfo(orNode.getY(), orNode.getX());
+        return result;
+    }
+
+    /**
+     * Porcelain method.
+     */
+    static boolean isInstanceOfCheckOn(LogicNode cond, ValueNode subject) {
+        if (!(cond instanceof InstanceOfNode)) {
+            return false;
+        }
+        InstanceOfNode io = (InstanceOfNode) cond;
+        return io.object() == subject;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,334 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import static com.oracle.graal.api.meta.DeoptimizationAction.InvalidateReprofile;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
+
+/**
+ * <p>
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.java.CheckCastNode}.
+ * </p>
+ *
+ * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+ */
+public abstract class CheckCastReduction extends GuardingPiReduction {
+
+    public CheckCastReduction(FixedNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * <p>
+     * This phase is able to refine the types of reference-values at use sites provided a
+     * {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} is available witnessing
+     * that fact.
+     * </p>
+     *
+     * <p>
+     * This method turns non-redundant {@link com.oracle.graal.nodes.java.CheckCastNode}s into
+     * {@link com.oracle.graal.nodes.GuardingPiNode}s. Once such lowering has been performed (during
+     * run N of this phase) follow-up runs attempt to further simplify the resulting node, see
+     * {@link EquationalReasoner#downcastGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode, Witness)}
+     * and {@link #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}
+     * </p>
+     *
+     * <p>
+     * Precondition: the inputs (ie, object) hasn't been deverbosified yet.
+     * </p>
+     */
+    protected final void visitCheckCastNode(CheckCastNode checkCast) {
+
+        /*
+         * checkCast.object() hasn't been deverbosified yet.
+         */
+
+        if (!FlowUtil.hasLegalObjectStamp(checkCast)) {
+            // This situation is exercised by test Class_cast01
+            return;
+        }
+
+        final ValueNode subject = checkCast.object();
+        final ResolvedJavaType toType = checkCast.type();
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        ResolvedJavaType subjectType = subjectStamp.type();
+
+        // --------- checkCast deemed redundant by subject-stamp alone ---------
+        // --------- in particular due to stamp informing always null ----------
+        boolean isRedundantPerStamp = StampTool.isObjectAlwaysNull(subject) || (subjectType != null && toType.isAssignableFrom(subjectType));
+        if (isRedundantPerStamp) {
+            metricCheckCastRemoved.increment();
+            checkCast.replaceAtUsages(subject);
+            graph.removeFixed(checkCast);
+            return;
+        }
+
+        assert !StampTool.isObjectAlwaysNull(subject) : "Null as per stamp subjects should have been handled above";
+
+        // --------- checkCast deemed unsatisfiable by subject-stamp alone ---------
+        if (state.knownNotToConform(subject, toType)) {
+            postponedDeopts.addDeoptBefore(checkCast, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException);
+            state.impossiblePath();
+            // let FixedGuardNode(false).simplify() prune the dead-code control-path
+            return;
+        }
+
+        /*
+         * Remark: subject may be TypeProxyNode, GuardedValueNode, ProxyNode, GuardingPiNode, among
+         * others.
+         */
+
+        PiNode untrivialNull = reasoner.nonTrivialNull(subject);
+        if (untrivialNull != null) {
+            metricCheckCastRemoved.increment();
+            checkCast.replaceAtUsages(untrivialNull);
+            graph.removeFixed(checkCast);
+            return;
+        }
+
+        Witness w = state.typeInfo(subject);
+
+        if (w == null) {
+            /*
+             * If there's no witness, attempting `downcast(subject)` is futile.
+             */
+            visitCheckCastNodeLackingWitness(checkCast);
+            return;
+        }
+
+        visitCheckCastNodeWithWitness(checkCast);
+
+    }
+
+    /**
+     * Given that no witness is available for the {@link com.oracle.graal.nodes.java.CheckCastNode}
+     * 's subject there's no point in downcasting such subject, ie no
+     * {@link com.oracle.graal.nodes.PiNode} can be fabricated for the subject.
+     *
+     * @see #lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode,
+     *      com.oracle.graal.nodes.ValueNode)
+     *
+     */
+    private void visitCheckCastNodeLackingWitness(CheckCastNode checkCast) {
+        final ValueNode subject = checkCast.object();
+        final ResolvedJavaType toType = checkCast.type();
+        if (toType.isInterface()) {
+            return;
+        }
+        assert reasoner.downcast(subject) == subject;
+        lowerCheckCastAnchorFriendlyWay(checkCast, subject);
+    }
+
+    /**
+     * Porcelain method.
+     *
+     * <p>
+     * Rather than tracking the CheckCastNode via {@link com.oracle.graal.phases.common.cfs.State
+     * State} (doing so woud add a special case because a
+     * {@link com.oracle.graal.nodes.java.CheckCastNode} isn't a
+     * {@link com.oracle.graal.nodes.extended.GuardingNode}) this method creates an anchor by
+     * lowering the CheckCastNode into a FixedGuardNode. Not the same way as done by
+     * {@link com.oracle.graal.nodes.java.CheckCastNode#lower(com.oracle.graal.nodes.spi.LoweringTool)}
+     * which lowers into a {@link com.oracle.graal.nodes.GuardingPiNode} (which is not a
+     * {@link com.oracle.graal.nodes.extended.GuardingNode}).
+     * </p>
+     *
+     * <p>
+     * With that, state tracking can proceed as usual.
+     * </p>
+     *
+     * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     *
+     */
+    public void lowerCheckCastAnchorFriendlyWay(CheckCastNode checkCast, ValueNode subject) {
+        ValueNode originalCheckCastObject = checkCast.object();
+
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        final ResolvedJavaType toType = checkCast.type();
+        ObjectStamp resultStamp = (ObjectStamp) StampFactory.declared(toType);
+        JavaTypeProfile profile = checkCast.profile();
+
+        assert FlowUtil.isLegalObjectStamp(subjectStamp);
+        assert subjectStamp.type() == null || !toType.isAssignableFrom(subjectStamp.type()) : "No need to lower in an anchor-friendly way in the first place";
+
+        /*
+         * Depending on what is known about the subject:
+         * 
+         * (a) definitely-non-null
+         * 
+         * (b) null-not-seen-in-profiling
+         * 
+         * (c) runtime-null-check-needed
+         * 
+         * the condition (of the cast-guard to be emitted) and the stamp (of the PiNode to be
+         * emitted) are going to be different. Each of the three branches below deals with one of
+         * the cases above.
+         */
+        LogicNode condition;
+        if (subjectStamp.nonNull()) {
+            /*
+             * (1 of 3) definitely-non-null
+             */
+            // addWithoutUnique for the same reason as in CheckCastNode.lower()
+            condition = graph.addWithoutUnique(new InstanceOfNode(toType, subject, profile));
+            reasoner.added.add(condition);
+            resultStamp = FlowUtil.asNonNullStamp(resultStamp);
+            // TODO fix in CheckCastNode.lower()
+        } else {
+            if (profile != null && profile.getNullSeen() == ProfilingInfo.TriState.FALSE) {
+                /*
+                 * (2 of 3) null-not-seen-in-profiling
+                 */
+                IsNullNode isNN = graph.unique(new IsNullNode(subject));
+                reasoner.added.add(isNN);
+                FixedGuardNode nullCheck = graph.add(new FixedGuardNode(isNN, UnreachedCode, InvalidateReprofile, true));
+                graph.addBeforeFixed(checkCast, nullCheck);
+                // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+                PiNode nonNullGuarded = graph.unique(new PiNode(subject, FlowUtil.asNonNullStamp(subjectStamp), nullCheck));
+                reasoner.added.add(nonNullGuarded);
+                // addWithoutUnique for the same reason as in CheckCastNode.lower()
+                condition = graph.addWithoutUnique(new InstanceOfNode(toType, nonNullGuarded, profile));
+                reasoner.added.add(condition);
+                resultStamp = FlowUtil.asNonNullStamp(resultStamp);
+            } else {
+                /*
+                 * (3 of 3) runtime-null-check-needed
+                 */
+                // addWithoutUnique for the same reason as in CheckCastNode.lower()
+                InstanceOfNode typeTest = graph.addWithoutUnique(new InstanceOfNode(toType, subject, profile));
+                reasoner.added.add(typeTest);
+                LogicNode nullTest = graph.unique(new IsNullNode(subject));
+                reasoner.added.add(nullTest);
+                // TODO (ds) replace with probability of null-seen when available
+                final double shortCircuitProbability = NOT_FREQUENT_PROBABILITY;
+                condition = LogicNode.or(nullTest, typeTest, shortCircuitProbability);
+                reasoner.added.add(condition);
+            }
+        }
+
+        /*
+         * Add a cast-guard (checking only what needs to be checked) and a PiNode (to be used in
+         * place of the CheckCastNode).
+         */
+        FixedGuardNode castGuard = graph.add(new FixedGuardNode(condition, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException, InvalidateReprofile));
+        graph.addBeforeFixed(checkCast, castGuard);
+
+        assert FlowUtil.isLegalObjectStamp(resultStamp);
+        Witness w = state.typeInfo(subject);
+        assert !isTypeOfWitnessBetter(w, resultStamp);
+
+        if (!FlowUtil.lacksUsages(checkCast)) {
+            // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+            PiNode checkedObject = graph.unique(new PiNode(subject, resultStamp, castGuard));
+            reasoner.added.add(checkedObject);
+            assert !precisionLoss(originalCheckCastObject, checkedObject);
+            assert !precisionLoss(subject, checkedObject);
+            checkCast.replaceAtUsages(checkedObject);
+        }
+
+        graph.removeFixed(checkCast);
+
+        if (resultStamp.nonNull()) {
+            state.trackIO(subject, toType, castGuard);
+        } else {
+            state.trackCC(subject, toType, castGuard);
+        }
+    }
+
+    /**
+     * Porcelain method.
+     */
+    public static boolean isTypeOfWitnessBetter(Witness w, ObjectStamp stamp) {
+        if (w == null) {
+            return false;
+        }
+        return FlowUtil.isMorePrecise(w.type(), stamp.type());
+    }
+
+    /**
+     *
+     * Please note in this method "subject" refers to the downcasted input to the checkCast.
+     *
+     * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     */
+    private void visitCheckCastNodeWithWitness(CheckCastNode checkCast) {
+
+        final ResolvedJavaType toType = checkCast.type();
+
+        ValueNode subject;
+        if (checkCast.object() instanceof CheckCastNode) {
+            subject = reasoner.downcast(checkCast);
+            if (subject == checkCast) {
+                subject = reasoner.downcast(checkCast.object());
+            }
+        } else {
+            subject = reasoner.downcast(checkCast.object());
+        }
+
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        ResolvedJavaType subjectType = subjectStamp.type();
+
+        /*
+         * At this point, two sources of (partial) information: the witness and the stamp of
+         * subject. The latter might be more precise than the witness (eg, subject might be
+         * GuardedValueNode)
+         */
+
+        // --------- checkCast made redundant by downcasting its input ---------
+        if (subjectType != null && toType.isAssignableFrom(subjectType)) {
+            checkCast.replaceAtUsages(subject);
+            graph.removeFixed(checkCast);
+            return;
+        }
+
+        /*
+         * At this point, `downcast()` might or might not have delivered a more precise value. If
+         * more precise, it wasn't precise enough to conform to `toType`. Even so, for the
+         * `toType.isInterface()` case (dealt with below) we'll replace the checkCast's input with
+         * that value (its class-stamp being more precise than the original).
+         */
+
+        if (toType.isInterface()) {
+            boolean wasDowncasted = (subject != checkCast.object());
+            if (wasDowncasted) {
+                FlowUtil.replaceInPlace(checkCast, checkCast.object(), subject);
+            }
+            return;
+        }
+
+        lowerCheckCastAnchorFriendlyWay(checkCast, subject);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,948 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeBitMap;
+import com.oracle.graal.graph.spi.CanonicalizerTool;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.calc.ObjectEqualsNode;
+import com.oracle.graal.nodes.extended.GuardedNode;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.java.CheckCastNode;
+import com.oracle.graal.nodes.java.InstanceOfNode;
+import com.oracle.graal.nodes.spi.ValueProxy;
+import com.oracle.graal.compiler.common.type.IllegalStamp;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.nodes.util.GraphUtil;
+
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+/**
+ * <p>
+ * This class implements a simple partial evaluator that recursively reduces a given
+ * {@link com.oracle.graal.nodes.calc.FloatingNode} into a simpler one based on the current state.
+ * Such evaluator comes handy when visiting a {@link com.oracle.graal.nodes.FixedNode} N, just
+ * before updating the state for N. At the pre-state, an {@link EquationalReasoner} can be used to
+ * reduce N's inputs (actually only those inputs of Value and Condition
+ * {@link com.oracle.graal.graph.InputType InputType}). For an explanation of where it's warranted
+ * to replace "old input" with "reduced input", see the inline comments in method
+ * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node n) deverbosify(Node n)}
+ * </p>
+ *
+ * <p>
+ * The name {@link EquationalReasoner EquationalReasoner} was chosen because it conveys what it
+ * does.
+ * </p>
+ */
+public final class EquationalReasoner {
+
+    private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved");
+    private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved");
+    private static final DebugMetric metricObjectEqualsRemoved = Debug.metric("ObjectEqualsRemoved");
+    private static final DebugMetric metricEquationalReasoning = Debug.metric("EquationalReasoning");
+    private static final DebugMetric metricDowncasting = Debug.metric("Downcasting");
+
+    private final StructuredGraph graph;
+    private final CanonicalizerTool tool;
+    private final LogicConstantNode trueConstant;
+    private final LogicConstantNode falseConstant;
+    private final ConstantNode nullConstant;
+
+    private State state;
+    private NodeBitMap visited;
+
+    /**
+     * The reduction of a {@link com.oracle.graal.nodes.calc.FloatingNode} performed by
+     * {@link EquationalReasoner EquationalReasoner} may result in a FloatingNode being added to the
+     * graph. Those nodes aren't tracked in the {@link EquationalReasoner#visited visited}
+     * {@link com.oracle.graal.graph.NodeBitMap NodeBitMap} but in this set instead (those nodes are
+     * added after the {@link com.oracle.graal.graph.NodeBitMap} was obtained).
+     */
+    final Set<ValueNode> added = java.util.Collections.newSetFromMap(new IdentityHashMap<ValueNode, Boolean>());
+
+    /**
+     * The reduction of a FloatingNode performed by {@link EquationalReasoner EquationalReasoner}
+     * may result in a FloatingNode being added to the graph. Those nodes are tracked in this map,
+     * to avoid recomputing them.
+     *
+     * The substitutions tracked in this field become invalid as described in
+     * {@link #updateState(com.oracle.graal.phases.common.cfs.State) updateState(State)}
+     */
+    private final IdentityHashMap<ValueNode, ValueNode> substs = new IdentityHashMap<>();
+
+    public EquationalReasoner(StructuredGraph graph, CanonicalizerTool tool, LogicConstantNode trueConstant, LogicConstantNode falseConstant, ConstantNode nullConstant) {
+        this.graph = graph;
+        this.tool = tool;
+        this.trueConstant = trueConstant;
+        this.falseConstant = falseConstant;
+        this.nullConstant = nullConstant;
+    }
+
+    /**
+     * {@link #added} grows during a run of
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase
+     * FlowSensitiveReductionPhase}, and doesn't survive across runs.
+     */
+    public void forceState(State s) {
+        state = s;
+        substs.clear();
+        added.clear();
+        visited = null;
+        versionNrAsofLastForce = s.versionNr;
+    }
+
+    /**
+     * <p>
+     * Gaining more precise type information about an SSA value doesn't "invalidate" as such any of
+     * the substitutions tracked in {@link EquationalReasoner#substs substs}, at least not in the
+     * sense of making the value tracked by one such entry "wrong". However, clearing the
+     * {@link EquationalReasoner#substs substs} is still justified because next time they are
+     * computed, the newly computed reduction could (in principle) be more effective (due to the
+     * more precise type information).
+     * </p>
+     *
+     * <p>
+     * Between clearings of cached substitutions, it is expected they get applied a number of times
+     * to justify the bookkeeping cost.
+     * </p>
+     *
+     */
+    public void updateState(State s) {
+        assert s != null;
+        if (state == null || state != s || state.versionNr != versionNrAsofLastForce) {
+            forceState(s);
+        }
+    }
+
+    private int versionNrAsofLastForce = 0;
+
+    /**
+     * Reduce the argument based on the state at the program point where the argument is consumed.
+     * For most FixedNodes, that's how their inputs can be reduced. Two exceptions:
+     * <ul>
+     * <li>
+     * the condition of a {@link com.oracle.graal.nodes.GuardingPiNode}, see
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}
+     * </li>
+     * <li>
+     * the condition of a {@link com.oracle.graal.nodes.FixedGuardNode}, see
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)}
+     * </li>
+     *
+     * </ul>
+     *
+     *
+     * <p>
+     * Part of the reduction work is delegated to baseCase-style reducers, whose contract explicitly
+     * requires them not to deverbosify the argument's inputs --- the decision is made based on the
+     * argument only (thus "base case"). Returning the unmodified argument is how a baseCase-style
+     * tells this method to fall to the default case (for a floating node only: walk into the
+     * argument's inputs, canonicalize followed by
+     * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)
+     * rememberSubstitution()} if any input changed).
+     * </p>
+     *
+     * <p>
+     * This method must behave as a function (idempotent query method), ie refrain from mutating the
+     * state other than updating caches:
+     * <ul>
+     * <li>{@link EquationalReasoner#added EquationalReasoner#added},</li>
+     * <li>{@link EquationalReasoner#visited EquationalReasoner#visited} and</li>
+     * <li>the cache updated via
+     * {@link EquationalReasoner#rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)
+     * EquationalReasoner#rememberSubstitution(ValueNode, FloatingNode)}.</li>
+     * </ul>
+     * </p>
+     *
+     * <p>
+     * In turn, baseCase-style reducers are even more constrained: besides behaving as functions,
+     * their contract prevents them from updating any caches (basically because they already grab
+     * the answer from caches, if the answer isn't there they should just return their unmodified
+     * argument).
+     * </p>
+     *
+     * <p>
+     * This method returns:
+     * <ul>
+     * <li>
+     * the original argument, in case no reduction possible.</li>
+     * <li>
+     * a {@link com.oracle.graal.nodes.ValueNode ValueNode} different from the argument, in case the
+     * conditions for a reduction were met. The node being returned might be already in the graph.
+     * In any case it's canonicalized already, the caller need not perform that again.</li>
+     * <li>
+     * the unmodified argument, in case no reduction was made. Otherwise, a maximally reduced
+     * {@link com.oracle.graal.nodes.ValueNode}.</li>
+     * </ul>
+     * </p>
+     *
+     * @see com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#deverbosifyInputsInPlace(com.oracle.graal.nodes.ValueNode)
+     *
+     * @see com.oracle.graal.phases.common.cfs.BaseReduction.Tool
+     *
+     */
+    public Node deverbosify(final Node n) {
+
+        // --------------------------------------------------------------------
+        // cases that don't initiate any call-chain that may enter this method
+        // --------------------------------------------------------------------
+
+        if (n == null) {
+            return null;
+        }
+        assert !(n instanceof GuardNode) : "This phase not yet ready to run during MidTier";
+        if (!(n instanceof ValueNode)) {
+            return n;
+        }
+        ValueNode v = (ValueNode) n;
+        if (v.stamp() instanceof IllegalStamp) {
+            return v;
+        }
+        if (FlowUtil.isLiteralNode(v)) {
+            return v;
+        }
+        ValueNode result = substs.get(v);
+        if (result != null) {
+            // picked cached substitution
+            return result;
+        }
+        if ((visited != null && visited.contains(n)) || added.contains(v)) {
+            return v;
+        }
+
+        // --------------------------------------------------------------------
+        // stack overflow prevention via added, visited
+        // --------------------------------------------------------------------
+
+        if (visited == null) {
+            visited = graph.createNodeBitMap();
+        }
+        visited.mark(n);
+
+        /*
+         * Past this point, if we ever want `n` to be deverbosified, it must be looked-up by one of
+         * the cases above. One sure way to achieve that is with `rememberSubstitution(old, new)`
+         */
+        if (v instanceof ValueProxy) {
+            return downcast(v);
+        }
+
+        if (n instanceof FloatingNode) {
+            /*
+             * `deverbosifyFloatingNode()` will drill down over floating inputs, when that not
+             * possible anymore it resorts to calling `downcast()`. Thus it's ok to take the
+             * `deverbosifyFloatingNode()` route first, as no downcasting opportunity will be
+             * missed.
+             */
+            return deverbosifyFloatingNode((FloatingNode) n);
+        }
+
+        if (FlowUtil.hasLegalObjectStamp(v)) {
+            return downcast(v);
+        }
+
+        return n;
+    }
+
+    /**
+     * This method:
+     *
+     * <ul>
+     * <li>
+     * Recurses only over floating inputs to attempt reductions, leave anything else as is.</li>
+     * <li>
+     * Performs copy-on-write aka lazy-DAG-copying as described in source comments, in-line.</li>
+     * <li>
+     * Usage: must be called only from {@link #deverbosify(com.oracle.graal.graph.Node)
+     * deverbosify(Node)}.</li>
+     * </ul>
+     */
+    public Node deverbosifyFloatingNode(final FloatingNode n) {
+
+        assert n != null : "Should have been caught in deverbosify()";
+        assert !(n instanceof ValueProxy) : "Should have been caught in deverbosify()";
+        assert !FlowUtil.isLiteralNode(n) : "Should have been caught in deverbosify()";
+
+        if (n instanceof PhiNode) {
+            /*
+             * Each input to a PhiNode should be deverbosified with the state applicable to the path
+             * providing such input, as done in visitAbstractEndNode()
+             */
+            return n;
+        }
+
+        final FloatingNode f = baseCaseFloating(n);
+        if (f != n) {
+            return f;
+        }
+
+        FloatingNode changed = null;
+        for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(f)) {
+            /*
+             * Although deverbosify() is invoked below, it's only for floating inputs. That way, the
+             * state can't be used to make invalid conclusions.
+             */
+            Node j = (i instanceof FloatingNode) ? deverbosify(i) : i;
+            if (i != j) {
+                assert j != f;
+                if (changed == null) {
+                    changed = (FloatingNode) f.copyWithInputs();
+                    added.add(changed);
+                    // copyWithInputs() implies graph.unique(changed)
+                    assert changed.isAlive();
+                    assert FlowUtil.lacksUsages(changed);
+                }
+                /*
+                 * Note: we don't trade i for j at each usage of i (doing so would change meaning)
+                 * but only at those usages consumed by `changed`. In turn, `changed` won't replace
+                 * `n` at arbitrary usages, but only where such substitution is valid as per the
+                 * state holding there. In practice, this means the buck stops at the "root"
+                 * FixedNode on whose inputs deverbosify() is invoked for the first time, via
+                 * deverbosifyInputsInPlace().
+                 */
+                FlowUtil.replaceInPlace(changed, i, j);
+            }
+        }
+        if (changed == null) {
+            assert visited.contains(f) || added.contains(f);
+            if (FlowUtil.hasLegalObjectStamp(f)) {
+                /*
+                 * No input has changed doesn't imply there's no witness to refine the
+                 * floating-object value.
+                 */
+                ValueNode d = downcast(f);
+                return d;
+            } else {
+                return f;
+            }
+        }
+        FlowUtil.inferStampAndCheck(changed);
+        added.add(changed);
+        ValueNode canon = (ValueNode) changed.canonical(tool);
+        // might be already in `added`, no problem adding it again.
+        added.add(canon);
+        rememberSubstitution(f, canon);
+        return canon;
+    }
+
+    /**
+     * In case of doubt (on whether a reduction actually triggered) it's always ok to invoke "
+     * <code>rememberSubstitution(f, downcast(f))</code>": this method records a map entry only if
+     * pre-image and image differ.
+     *
+     * @return the image of the substitution (ie, the second argument) unmodified.
+     */
+    private <M extends ValueNode> M rememberSubstitution(ValueNode from, M to) {
+        assert from != null && to != null;
+        if (from == to) {
+            return to;
+        }
+        // we don't track literals because they map to themselves
+        if (FlowUtil.isLiteralNode(from)) {
+            assert from == to;
+            return to;
+        }
+        /*
+         * It's ok for different keys (which were not unique in the graph after all) to map to the
+         * same value. However any given key can't map to different values.
+         */
+        ValueNode image = substs.get(from);
+        if (image != null) {
+            assert image == to;
+            return to;
+        }
+        substs.put(from, to);
+        return to;
+    }
+
+    /**
+     * The contract for this baseCase-style method is covered in
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify()}
+     *
+     * @return a {@link com.oracle.graal.nodes.calc.FloatingNode} different from the argument, in
+     *         case a reduction was made. The node being returned might be already in the graph. In
+     *         any case it's canonicalized already, the caller need not perform that again. In case
+     *         no reduction was made, this method returns the unmodified argument.
+     */
+    private FloatingNode baseCaseFloating(final FloatingNode f) {
+        if (f instanceof LogicNode) {
+            FloatingNode result = baseCaseLogicNode((LogicNode) f);
+            return rememberSubstitution(f, result);
+        }
+        return f;
+    }
+
+    /**
+     * <p>
+     * Reduce the argument based on the state at the program point for it (ie, based on
+     * "valid facts" only, without relying on any floating-guard-assumption).
+     * </p>
+     *
+     * <p>
+     * The inputs of the argument aren't traversed into, for that
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify()} should be used instead.
+     * </p>
+     * <p>
+     * This method must behave as a function (idempotent query method): it should refrain from
+     * changing the state, as well as from updating caches (other than DebugMetric-s).
+     * </p>
+     *
+     * @return a {@link com.oracle.graal.nodes.LogicNode} different from the argument, in case a
+     *         reduction was made. The node being returned might be already in the graph. In any
+     *         case it's canonicalized already, the caller need not perform that again. In case no
+     *         reduction was made, this method returns the unmodified argument.
+     *
+     */
+    public FloatingNode baseCaseLogicNode(LogicNode condition) {
+        assert condition != null;
+        if (condition instanceof LogicConstantNode) {
+            return condition;
+        } else if (state.trueFacts.containsKey(condition)) {
+            metricEquationalReasoning.increment();
+            return trueConstant;
+        } else if (state.falseFacts.containsKey(condition)) {
+            metricEquationalReasoning.increment();
+            return falseConstant;
+        } else {
+            if (condition instanceof InstanceOfNode) {
+                return baseCaseInstanceOfNode((InstanceOfNode) condition);
+            } else if (condition instanceof IsNullNode) {
+                return baseCaseIsNullNode((IsNullNode) condition);
+            } else if (condition instanceof ObjectEqualsNode) {
+                return baseCaseObjectEqualsNode((ObjectEqualsNode) condition);
+            }
+        }
+        return condition;
+    }
+
+    /**
+     * Actually the same result delivered by this method could be obtained by just letting
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify()} handle the argument in the default case for floating nodes
+     * (ie, deverbosify inputs followed by canonicalize). However it's done here for metrics
+     * purposes.
+     *
+     * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was made;
+     *         otherwise the unmodified argument.
+     *
+     */
+    private LogicNode baseCaseInstanceOfNode(InstanceOfNode instanceOf) {
+        ValueNode scrutinee = GraphUtil.unproxify(instanceOf.object());
+        if (!FlowUtil.hasLegalObjectStamp(scrutinee)) {
+            return instanceOf;
+        }
+        if (state.isNull(scrutinee)) {
+            metricInstanceOfRemoved.increment();
+            return falseConstant;
+        } else if (state.isNonNull(scrutinee) && state.knownToConform(scrutinee, instanceOf.type())) {
+            metricInstanceOfRemoved.increment();
+            return trueConstant;
+        }
+        return instanceOf;
+    }
+
+    /**
+     * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was
+     *         performed; otherwise the unmodified argument.
+     *
+     */
+    private FloatingNode baseCaseIsNullNode(IsNullNode isNull) {
+        ValueNode object = isNull.object();
+        if (!FlowUtil.hasLegalObjectStamp(object)) {
+            return isNull;
+        }
+        ValueNode scrutinee = GraphUtil.unproxify(isNull.object());
+        GuardingNode evidence = nonTrivialNullAnchor(scrutinee);
+        if (evidence != null) {
+            metricNullCheckRemoved.increment();
+            return trueConstant;
+        } else if (state.isNonNull(scrutinee)) {
+            metricNullCheckRemoved.increment();
+            return falseConstant;
+        }
+        return isNull;
+    }
+
+    /**
+     * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was made;
+     *         otherwise the unmodified argument.
+     */
+    private LogicNode baseCaseObjectEqualsNode(ObjectEqualsNode equals) {
+        if (!FlowUtil.hasLegalObjectStamp(equals.x()) || !FlowUtil.hasLegalObjectStamp(equals.y())) {
+            return equals;
+        }
+        ValueNode x = GraphUtil.unproxify(equals.x());
+        ValueNode y = GraphUtil.unproxify(equals.y());
+        if (state.isNull(x) && state.isNonNull(y) || state.isNonNull(x) && state.isNull(y)) {
+            metricObjectEqualsRemoved.increment();
+            return falseConstant;
+        } else if (state.isNull(x) && state.isNull(y)) {
+            metricObjectEqualsRemoved.increment();
+            return trueConstant;
+        }
+        return equals;
+    }
+
+    /**
+     * It's always ok to use "<code>downcast(object)</code>" instead of " <code>object</code>"
+     * because this method re-wraps the argument in a {@link com.oracle.graal.nodes.PiNode} only if
+     * the new stamp is strictly more refined than the original.
+     *
+     * <p>
+     * This method does not
+     * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)}
+     * .
+     * </p>
+     *
+     * @return One of:
+     *         <ul>
+     *         <li>a {@link com.oracle.graal.nodes.PiNode} with more precise stamp than the input if
+     *         the state warrants such downcasting</li>
+     *         <li>a {@link com.oracle.graal.nodes.java.CheckCastNode CheckCastNode} for the same
+     *         scrutinee in question</li>
+     *         <li>the unmodified argument otherwise.</li>
+     *         </ul>
+     */
+    ValueNode downcast(final ValueNode object) {
+
+        // -------------------------------------------------
+        // actions based only on the stamp of the input node
+        // -------------------------------------------------
+
+        if (!FlowUtil.hasLegalObjectStamp(object)) {
+            return object;
+        }
+        if (FlowUtil.isLiteralNode(object)) {
+            return object;
+        }
+        if (StampTool.isObjectAlwaysNull(object.stamp())) {
+            return object;
+        }
+
+        // ------------------------------------------
+        // actions based on the stamp and the witness
+        // ------------------------------------------
+
+        ValueNode scrutinee = GraphUtil.unproxify(object);
+
+        PiNode untrivialNull = nonTrivialNull(scrutinee);
+        if (untrivialNull != null) {
+            return untrivialNull;
+        }
+
+        Witness w = state.typeInfo(scrutinee);
+        if (w == null) {
+            // no additional hints being tracked for the scrutinee
+            return object;
+        }
+
+        assert !w.clueless();
+
+        ObjectStamp inputStamp = (ObjectStamp) object.stamp();
+        ObjectStamp witnessStamp = w.asStamp();
+        if (inputStamp.equals(witnessStamp) || !FlowUtil.isMorePrecise(witnessStamp, inputStamp)) {
+            // the witness offers no additional precision over current one
+            fixupTypeProfileStamp(object);
+            return object;
+        }
+
+        assert !FlowUtil.isMorePrecise(inputStamp.type(), w.type());
+
+        ValueNode result;
+        if (object instanceof ValueProxy) {
+            result = downcastValueProxy((ValueProxy) object, w);
+        } else {
+            result = downcastedUtil(object, w);
+        }
+
+        assert !BaseReduction.precisionLoss(object, result);
+
+        return result;
+    }
+
+    /**
+     * TODO TypeProfileProxyNode.inferStamp doesn't infer non-null from non-null payload
+     *
+     * <p>
+     * And there's a bunch of asserts in
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} that assert no
+     * type-precision gets lost. Thus the need to fix-up on our own, as done here.
+     * </p>
+     */
+    private static void fixupTypeProfileStamp(ValueNode object) {
+        if (!(object instanceof TypeProfileProxyNode)) {
+            return;
+        }
+        TypeProfileProxyNode profile = (TypeProfileProxyNode) object;
+        ObjectStamp outgoinStamp = (ObjectStamp) profile.stamp();
+        ObjectStamp payloadStamp = (ObjectStamp) profile.getObject().stamp();
+        if (payloadStamp.nonNull() && !outgoinStamp.nonNull()) {
+            profile.setStamp(FlowUtil.asNonNullStamp(outgoinStamp));
+        }
+    }
+
+    /**
+     * <p>
+     * Porcelain method.
+     * </p>
+     *
+     * <p>
+     * Utility to create, add to the graph,
+     * {@link EquationalReasoner#rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)}
+     * , and return a {@link com.oracle.graal.nodes.PiNode} that narrows into the given stamp,
+     * anchoring the payload.
+     * </p>
+     *
+     * <p>
+     * The resulting node might not have been in the graph already.
+     * </p>
+     */
+    private PiNode wrapInPiNode(ValueNode payload, GuardingNode anchor, ObjectStamp newStamp, boolean remember) {
+        try (Debug.Scope s = Debug.scope("Downcast", payload)) {
+            assert payload != anchor : payload.graph().toString();
+            metricDowncasting.increment();
+            PiNode result = graph.unique(new PiNode(payload, newStamp, anchor.asNode()));
+            // we've possibly got a new node in the graph --- bookkeeping is in order.
+            added.add(result);
+            if (remember) {
+                rememberSubstitution(payload, result);
+            }
+            Debug.log("Downcasting from %s to %s", payload, result);
+            return result;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    /**
+     * <p>
+     * If the argument is known null due to its stamp, there's no need to have an anchor for that
+     * fact and this method returns null.
+     * </p>
+     *
+     * <p>
+     * Otherwise, if an anchor is found it is returned, null otherwise.
+     * </p>
+     */
+    public GuardingNode nonTrivialNullAnchor(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        if (StampTool.isObjectAlwaysNull(object)) {
+            return null;
+        }
+        return state.knownNull.get(GraphUtil.unproxify(object));
+    }
+
+    /**
+     *
+     * This method returns:
+     * <ul>
+     * <li><b>null</b>, if the argument is known null due to its stamp. Otherwise,</li>
+     * <li><b>a PiNode</b> wrapping the null constant and an anchor offering evidence as to why the
+     * argument is known null, if such anchor is available. Otherwise,</li>
+     * <li><b>null</b></li>
+     * </ul>
+     * <p>
+     * This method does not
+     * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)}
+     * .
+     * </p>
+     */
+    public PiNode nonTrivialNull(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        GuardingNode anchor = nonTrivialNullAnchor(object);
+        if (anchor == null) {
+            return null;
+        }
+        if (object instanceof GuardedNode && StampTool.isObjectAlwaysNull(object.stamp())) {
+            return (PiNode) object;
+        }
+        // notice nullConstant is wrapped, not object
+        PiNode result = wrapInPiNode(nullConstant, anchor, (ObjectStamp) StampFactory.alwaysNull(), false);
+        return result;
+    }
+
+    // @formatter:off
+    /**
+     * <p>ValueProxys can be classified along two dimensions,
+     * in addition to the fixed-floating dichotomy.</p>
+     *
+     * <p>
+     *     First, we might be interested in separating those ValueProxys
+     *     that are entitled to change (usually narrow) their stamp from those that aren't.
+     *     In the first category are:
+     *       PiNode, PiArrayNode, GuardingPiNode,
+     *       CheckCastNode, UnsafeCastNode, and
+     *       GuardedValueNode.
+     * </p>
+     *
+     * <p>
+     *     A note on stamp-narrowing ValueProxys:
+     *     our state abstraction tracks only the type refinements induced by CheckCastNode and GuardingPiNode
+     *     (which are fixed nodes, unlike the other stamp-narrowing ValueProxys;
+     *     the reason being that the state abstraction can be updated only at fixed nodes).
+     *     As a result, the witness for a (PiNode, PiArrayNode, UnsafeCastNode, or GuardedValueNode)
+     *     may be less precise than the proxy's stamp. We don't want to lose such precision,
+     *     thus <code>downcast(proxy) == proxy</code> in such cases.
+     * </p>
+     *
+     * <p>
+     *     The second classification focuses on
+     *     the additional information that travels with the proxy
+     *     (in addition to its "payload", ie getOriginalValue(), and any narrowing-stamp).
+     *     Such additional information boils down to:
+     *
+     *   (a) type profile (TypeProfileProxyNode)
+     *   (b) type profile (CheckCastNode)
+     *   (c) anchor (GuardedValueNode)
+     *   (d) anchor (PiNode)
+     *   (e) anchor and array length (PiArrayNode)
+     *   (f) optional anchor (UnsafeCastNode)
+     *   (g) deopt-condition (GuardingPiNode)
+     *   (h) LocationIdentity (MemoryProxyNOde)
+     *   (i) control-flow dependency (FixedValueAnchorNode)
+     *   (j) proxyPoint (ProxyNode -- think loops)
+     *</p>
+     */
+    // @formatter:on
+    private ValueNode downcastValueProxy(ValueProxy proxy, Witness w) {
+        assert FlowUtil.hasLegalObjectStamp((ValueNode) proxy);
+        assert FlowUtil.hasLegalObjectStamp((proxy).getOriginalNode());
+        assert GraphUtil.unproxify((ValueNode) proxy) == GraphUtil.unproxify(proxy.getOriginalNode());
+
+        assert GraphUtil.unproxify((ValueNode) proxy) == GraphUtil.unproxify((proxy).getOriginalNode());
+
+        if (proxy instanceof PiNode) {
+            return downcastPiNodeOrPiArrayNode((PiNode) proxy, w);
+        } else if (proxy instanceof GuardingPiNode) {
+            return downcastGuardingPiNode((GuardingPiNode) proxy, w);
+        } else if (proxy instanceof TypeProfileProxyNode) {
+            return downcastTypeProfileProxyNode((TypeProfileProxyNode) proxy);
+        } else if (proxy instanceof CheckCastNode) {
+            return downcastCheckCastNode((CheckCastNode) proxy, w);
+        } else if (proxy instanceof ProxyNode || proxy instanceof GuardedValueNode) {
+            // TODO scaladacapo return downcastedUtil((ValueNode) proxy, w);
+            return (ValueNode) proxy;
+        }
+
+        assert false : "TODO case not yet handled";
+
+        // TODO complete the missing implementation for the cases not yet handled
+
+        return ((ValueNode) proxy);
+    }
+
+    /**
+     * <p>
+     * Why would we want to downcast a GuardingPiNode? Is it even possible? Like, for example, a
+     * GuardingPiNode originating in the lowering of a CheckCastNode (carried out by
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     * visitCheckCastNode()}).
+     * </p>
+     *
+     * <p>
+     * It's both possible and desirable. Example: <code>
+     *         Number n = (Number) o;
+     *         if (n instanceof Integer) {
+     *            return n.intValue();
+     *         }
+     *     </code>
+     *
+     * The receiver of intValue() is a usage of a previous checkCast, for which the current witness
+     * provides a more refined type (and an anchor). In this case, the advantage of downcasting a
+     * GuardingPiNode is clear: devirtualizing the `intValue()` callsite.
+     * </p>
+     *
+     * @see #downcastValueProxy
+     */
+    public ValueNode downcastGuardingPiNode(GuardingPiNode envelope, Witness w) {
+        assert envelope != w.guard().asNode() : "The stamp of " + envelope + " would lead to downcasting with that very same GuardingPiNode as guard.";
+        return downcastedUtil(envelope, w);
+    }
+
+    /**
+     * <p>
+     * This method accepts both {@link com.oracle.graal.nodes.PiNode} and
+     * {@link com.oracle.graal.nodes.PiArrayNode} argument.
+     * </p>
+     *
+     * <p>
+     * In case a witness reveals a strictly more precise type than the
+     * {@link com.oracle.graal.nodes.PiNode}'s stamp, this method wraps the argument in a new
+     * {@link com.oracle.graal.nodes.PiNode} with updated stamp, and returns it.
+     * </p>
+     *
+     * <p>
+     * A {@link com.oracle.graal.nodes.PiArrayNode} argument ends up wrapped in a
+     * {@link com.oracle.graal.nodes.PiNode}. Thus, the
+     * {@link com.oracle.graal.nodes.PiArrayNode#length} information doesn't get lost.
+     * </p>
+     *
+     * <p>
+     * Note: {@link com.oracle.graal.nodes.PiNode}'s semantics allow un-packing its payload as soon
+     * as it type conforms to that of the {@link com.oracle.graal.nodes.PiNode} (that's what
+     * {@link com.oracle.graal.nodes.PiNode#canonical(com.oracle.graal.graph.spi.CanonicalizerTool)
+     * PiNode.canonical()} does). Not clear the benefits of duplicating that logic here.
+     * </p>
+     *
+     * @see #downcastValueProxy
+     */
+    private ValueNode downcastPiNodeOrPiArrayNode(PiNode envelope, Witness w) {
+        return downcastedUtil(envelope, w);
+    }
+
+    /**
+     * <p>
+     * In a case the payload of the {@link com.oracle.graal.nodes.TypeProfileProxyNode} can be
+     * downcasted, this method returns a copy-on-write version with the downcasted payload.
+     * </p>
+     *
+     * <p>
+     * Otherwise returns the unmodified argument.
+     * </p>
+     *
+     * @see #downcastValueProxy
+     */
+    private ValueNode downcastTypeProfileProxyNode(TypeProfileProxyNode envelope) {
+        ValueNode payload = envelope.getOriginalNode();
+        ValueNode d = downcast(payload);
+        if (payload != d) {
+            TypeProfileProxyNode changed = (TypeProfileProxyNode) envelope.copyWithInputs();
+            added.add(changed);
+            // copyWithInputs() implies graph.unique(changed)
+            FlowUtil.replaceInPlace(changed, payload, d);
+            FlowUtil.inferStampAndCheck(changed);
+            fixupTypeProfileStamp(changed);
+            /*
+             * It's not prudent to (1) obtain the canonical() of the (changed) TypeProfileProxyNode
+             * to (2) replace its usages; because we're potentially walking a DAG (after all,
+             * TypeProfileProxyNode is a floating-node). Those steps, which admittedly are needed,
+             * are better performed upon replacing in-place the inputs of a FixedNode, or during
+             * Canonicalize.
+             */
+            return changed;
+        }
+        fixupTypeProfileStamp(envelope);
+        return envelope;
+    }
+
+    /**
+     * <p>
+     * Re-wrap the checkCast in a type-refining {@link com.oracle.graal.nodes.PiNode PiNode} only if
+     * the downcasted scrutinee does not conform to the checkCast's target-type.
+     * </p>
+     */
+    private ValueNode downcastCheckCastNode(CheckCastNode checkCast, Witness w) {
+
+        final ResolvedJavaType toType = checkCast.type();
+
+        if (checkCast.object() instanceof CheckCastNode) {
+            ValueNode innerMost = checkCast;
+            while (innerMost instanceof CheckCastNode) {
+                innerMost = ((CheckCastNode) innerMost).object();
+            }
+            ValueNode deepest = downcast(innerMost);
+            ResolvedJavaType deepestType = ((ObjectStamp) deepest.stamp()).type();
+            if ((deepestType != null && deepestType.equals(toType)) || FlowUtil.isMorePrecise(deepestType, toType)) {
+                assert !w.knowsBetterThan(deepest);
+                return deepest;
+            }
+        }
+
+        ValueNode subject = downcast(checkCast.object());
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        ResolvedJavaType subjectType = subjectStamp.type();
+
+        if (subjectType != null && toType.isAssignableFrom(subjectType)) {
+            assert !w.knowsBetterThan(subject);
+            return subject;
+        }
+
+        return downcastedUtil(checkCast, w);
+    }
+
+    /**
+     * <p>
+     * Porcelain method.
+     * </p>
+     *
+     * <p>
+     * This method wraps the argument in a new {@link com.oracle.graal.nodes.PiNode PiNode} (created
+     * to hold an updated stamp) provided the argument's stamp can be strictly refined, and returns
+     * it.
+     * </p>
+     */
+    private ValueNode downcastedUtil(ValueNode subject, Witness w) {
+
+        ObjectStamp originalStamp = (ObjectStamp) subject.stamp();
+        ObjectStamp outgoingStamp = originalStamp;
+
+        if (w.isNonNull() && !outgoingStamp.nonNull()) {
+            outgoingStamp = FlowUtil.asNonNullStamp(outgoingStamp);
+        }
+        if (FlowUtil.isMorePrecise(w.type(), outgoingStamp.type())) {
+            outgoingStamp = FlowUtil.asRefinedStamp(outgoingStamp, w.type());
+        }
+
+        if (outgoingStamp != originalStamp) {
+            assert FlowUtil.isMorePrecise(outgoingStamp, originalStamp);
+
+            boolean isWitnessGuardAnAliasForScrutinee = false;
+            if (w.guard() instanceof GuardingPiNode || w.guard() instanceof PiNode) {
+                /*
+                 * The guard offered by the witness canonicalizes into its subject (a possibly
+                 * type-refined scrutinee) provided its subject conforms as per stamp.
+                 */
+                if (w.guard().asNode().stamp().equals(outgoingStamp)) {
+                    isWitnessGuardAnAliasForScrutinee = true;
+                }
+            }
+
+            ValueNode result;
+            if (isWitnessGuardAnAliasForScrutinee) {
+                result = w.guard().asNode();
+                assert !w.knowsBetterThan(result);
+                return result; // TODO this works. explain why.
+            } else {
+                result = wrapInPiNode(subject, w.guard(), outgoingStamp, true);
+                assert !w.knowsBetterThan(result);
+                return result;
+            }
+
+        } else {
+            assert !w.knowsBetterThan(subject);
+            return subject;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,218 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+/**
+ * <p>
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.FixedGuardNode}.
+ * </p>
+ * 
+ * @see #visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)
+ */
+public abstract class FixedGuardReduction extends CheckCastReduction {
+
+    public FixedGuardReduction(FixedNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * In case the condition is constant,
+     * {@link com.oracle.graal.nodes.FixedGuardNode#simplify(com.oracle.graal.graph.spi.SimplifierTool)
+     * FixedGuardNode#simplify(SimplifierTool)} will eventually remove the
+     * {@link com.oracle.graal.nodes.FixedGuardNode} ("always succeeds") or kill the code that
+     * should be killed ("always fails").
+     * 
+     * <p>
+     * The only thing we do here is tracking as true fact (from this program point onwards) the
+     * condition of the {@link com.oracle.graal.nodes.FixedGuardNode FixedGuardNode}.
+     * </p>
+     * 
+     * <p>
+     * Precondition: the condition hasn't been deverbosified yet.
+     * </p>
+     */
+    protected final void visitFixedGuardNode(FixedGuardNode f) {
+
+        /*
+         * A FixedGuardNode with LogicConstantNode condition is left untouched.
+         */
+
+        if (f.condition() instanceof LogicConstantNode) {
+            if (FlowUtil.alwaysFails(f.isNegated(), f.condition())) {
+                state.impossiblePath();
+                // let FixedGuardNode(false).simplify() prune the dead-code control-path
+                return;
+            }
+            assert FlowUtil.alwaysSucceeds(f.isNegated(), f.condition());
+            return;
+        }
+
+        /*
+         * Attempt to eliminate the current FixedGuardNode by using another GuardingNode already in
+         * scope and with equivalent condition.
+         */
+
+        GuardingNode existingGuard = f.isNegated() ? state.falseFacts.get(f.condition()) : state.trueFacts.get(f.condition());
+        if (existingGuard != null) {
+            // assert existingGuard instanceof FixedGuardNode;
+            metricFixedGuardNodeRemoved.increment();
+            f.replaceAtUsages(existingGuard.asNode());
+            graph.removeFixed(f);
+            return;
+        }
+
+        final LogicNode cond = f.condition();
+        final boolean isTrue = !f.isNegated();
+
+        /*
+         * FixedGuardNode requires handling similar to that of GuardingPiNode, (ie the condition
+         * can't simply be deverbosified in place). A replacement anchor is needed, ie an anchor
+         * that amounts to the same combination of (negated, condition) for the FixedGuardNode at
+         * hand.
+         */
+
+        // TODO what about isDependencyTainted
+
+        if (cond instanceof IsNullNode) {
+            final IsNullNode isNullNode = (IsNullNode) cond;
+            if (isTrue) {
+                // grab an anchor attesting nullness
+                final GuardingNode replacement = reasoner.nonTrivialNullAnchor(isNullNode.object());
+                if (replacement != null) {
+                    removeFixedGuardNode(f, replacement);
+                    return;
+                }
+                if (state.isNonNull(isNullNode.object())) {
+                    markFixedGuardNodeAlwaysFails(f);
+                    return;
+                }
+                // can't produce evidence, fall-through to addFact
+            } else {
+                // grab an anchor attesting non-nullness
+                final Witness w = state.typeInfo(isNullNode.object());
+                if (w != null && w.isNonNull()) {
+                    removeFixedGuardNode(f, w.guard());
+                    return;
+                }
+                if (state.isNull(isNullNode.object())) {
+                    markFixedGuardNodeAlwaysFails(f);
+                    return;
+                }
+                // can't produce evidence, fall-through to addFact
+            }
+        } else if (cond instanceof InstanceOfNode) {
+            final InstanceOfNode iOf = (InstanceOfNode) cond;
+            final Witness w = state.typeInfo(iOf.object());
+            if (isTrue) {
+                // grab an anchor attesting instanceof
+                if (w != null) {
+                    if (w.isNonNull() && w.type() != null) {
+                        if (iOf.type().isAssignableFrom(w.type())) {
+                            removeFixedGuardNode(f, w.guard());
+                            return;
+                        }
+                        if (State.knownNotToConform(w.type(), iOf.type())) {
+                            markFixedGuardNodeAlwaysFails(f);
+                            return;
+                        }
+                    }
+                }
+                if (state.isNull(iOf.object())) {
+                    markFixedGuardNodeAlwaysFails(f);
+                    return;
+                }
+                // can't produce evidence, fall-through to addFact
+            } else {
+                // grab an anchor attesting not-instanceof
+                // (1 of 2) attempt determining nullness
+                final GuardingNode nullGuard = reasoner.nonTrivialNullAnchor(iOf.object());
+                if (nullGuard != null) {
+                    removeFixedGuardNode(f, nullGuard);
+                    return;
+                }
+                // (2 of 2) attempt determining known-not-to-conform
+                if (w != null && !w.cluelessAboutType()) {
+                    if (State.knownNotToConform(w.type(), iOf.type())) {
+                        removeFixedGuardNode(f, w.guard());
+                        return;
+                    }
+                }
+                // can't produce evidence, fall-through to addFact
+            }
+        } else if (isTrue && cond instanceof ShortCircuitOrNode) {
+            CastCheckExtractor cce = CastCheckExtractor.extract(cond);
+            if (cce != null && !State.isDependencyTainted(cce.subject, f)) {
+                // grab an anchor attesting check-cast
+                Witness w = state.typeInfo(cce.subject);
+                if (w != null && w.type() != null) {
+                    if (cce.type.isAssignableFrom(w.type())) {
+                        removeFixedGuardNode(f, w.guard());
+                        return;
+                    }
+                    if (State.knownNotToConform(w.type(), cce.type)) {
+                        markFixedGuardNodeAlwaysFails(f);
+                        return;
+                    }
+                }
+            }
+            // can't produce evidence, fall-through to addFact
+        }
+
+        state.addFact(isTrue, cond, f);
+    }
+
+    /**
+     * Porcelain method.
+     */
+    private void markFixedGuardNodeAlwaysFails(FixedGuardNode f) {
+        metricFixedGuardNodeRemoved.increment();
+        state.impossiblePath();
+        f.setCondition(f.isNegated() ? trueConstant : falseConstant);
+        // `f.condition()` if unused will be removed in finished()
+    }
+
+    /**
+     * Porcelain method.
+     * 
+     * <p>
+     * The `replacement` guard must be such that it implies the `old` guard.
+     * </p>
+     */
+    private void removeFixedGuardNode(FixedGuardNode old, GuardingNode replacement) {
+        if (replacement == null) {
+            return;
+        }
+        metricFixedGuardNodeRemoved.increment();
+        old.replaceAtUsages(replacement.asNode());
+        graph.removeFixed(old);
+        // `old.condition()` if unused will be removed in finished()
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,554 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.extended.LoadHubNode;
+import com.oracle.graal.nodes.extended.NullCheckNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.IllegalStamp;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import java.lang.reflect.Modifier;
+
+import static com.oracle.graal.api.meta.DeoptimizationAction.InvalidateReprofile;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+
+/**
+ * <p>
+ * All control-flow-sensitive reductions follow the common pattern of
+ * <ul>
+ * <li>Recognizing properties of interest (ie, LogicNode-s) at control-flow splits, as well as upon
+ * check-casts and fixed-guards.</li>
+ * <li>Using the information thus tracked to simplify
+ * <ul>
+ * <li>side-effects free expressions, via
+ * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+ * </li>
+ * <li>control-flow, eg. by eliminating redundant fixed-guards and check-casts, ie which are known
+ * always to hold.</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * </p>
+ *
+ * @see com.oracle.graal.phases.common.cfs.CheckCastReduction
+ * @see com.oracle.graal.phases.common.cfs.GuardingPiReduction
+ * @see com.oracle.graal.phases.common.cfs.FixedGuardReduction
+ *
+ */
+public class FlowSensitiveReduction extends FixedGuardReduction {
+
+    public FlowSensitiveReduction(FixedNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * <p>
+     * This method performs two kinds of cleanup:
+     * <ol>
+     * <li>
+     * marking as unreachable certain code-paths, as described in
+     * {@link com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt}</li>
+     * <li>
+     * Removing nodes not in use that were added during this phase, as described next.</li>
+     * </ol>
+     * </p>
+     *
+     *
+     * <p>
+     * Methods like
+     * {@link com.oracle.graal.phases.common.cfs.FlowUtil#replaceInPlace(com.oracle.graal.graph.Node, com.oracle.graal.graph.Node, com.oracle.graal.graph.Node)}
+     * may result in old inputs becoming disconnected from the graph. It's not advisable to
+     * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} at
+     * that moment, because one of the inputs that might get killed is one of {@link #nullConstant},
+     * {@link #falseConstant}, or {@link #trueConstant}; which thus could get killed too early,
+     * before another invocation of
+     * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+     * needs them. To recap,
+     * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} also
+     * recursively visits the inputs of the its argument.
+     * </p>
+     *
+     * <p>
+     * This method goes over all of the nodes that deverbosification might have added, which are
+     * either:
+     * <ul>
+     * <li>
+     * {@link com.oracle.graal.nodes.calc.FloatingNode}, added by
+     * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosifyFloatingNode(com.oracle.graal.nodes.calc.FloatingNode)}
+     * ; or</li>
+     * <li>
+     * {@link com.oracle.graal.nodes.java.MethodCallTargetNode}, added by
+     * {@link #deverbosifyInputsCopyOnWrite(com.oracle.graal.nodes.java.MethodCallTargetNode)}</li>
+     * </ul>
+     *
+     * Checking if they aren't in use, proceeding to remove them in that case.
+     * </p>
+     *
+     */
+    @Override
+    public void finished() {
+        if (!postponedDeopts.isEmpty()) {
+            for (PostponedDeopt postponed : postponedDeopts) {
+                postponed.doRewrite(falseConstant);
+            }
+            new DeadCodeEliminationPhase().apply(graph);
+        }
+        for (MethodCallTargetNode mcn : graph.getNodes().filter(MethodCallTargetNode.class)) {
+            if (mcn.isAlive() && FlowUtil.lacksUsages(mcn)) {
+                mcn.safeDelete();
+            }
+        }
+        for (Node n : graph.getNodes().filter(FloatingNode.class)) {
+            GraphUtil.tryKillUnused(n);
+        }
+        assert !isAliveWithoutUsages(trueConstant);
+        assert !isAliveWithoutUsages(falseConstant);
+        assert !isAliveWithoutUsages(nullConstant);
+    }
+
+    private static boolean isAliveWithoutUsages(FloatingNode node) {
+        return node.isAlive() && FlowUtil.lacksUsages(node);
+    }
+
+    private void registerControlSplit(Node pred, BeginNode begin) {
+        assert pred != null && begin != null;
+        assert !state.isUnreachable;
+
+        if (begin instanceof LoopExitNode) {
+            state.clear();
+        }
+
+        if (pred instanceof IfNode) {
+            registerIfNode((IfNode) pred, begin);
+        } else if (pred instanceof TypeSwitchNode) {
+            registerTypeSwitchNode((TypeSwitchNode) pred, begin);
+        }
+    }
+
+    private void registerIfNode(IfNode ifNode, BeginNode begin) {
+        final boolean isThenBranch = (begin == ifNode.trueSuccessor());
+
+        if (ifNode.condition() instanceof LogicConstantNode) {
+            final LogicConstantNode constCond = (LogicConstantNode) ifNode.condition();
+            if (isThenBranch != constCond.getValue()) {
+                state.impossiblePath();
+                // let IfNode(constant) prune the dead-code control-path
+            }
+        }
+
+        if (state.isUnreachable) {
+            if (!(ifNode.condition() instanceof LogicConstantNode)) {
+                // if condition constant, no need to add a Deopt node
+                postponedDeopts.addDeoptAfter(begin, UnreachedCode);
+            }
+        } else {
+            state.addFact(isThenBranch, ifNode.condition(), begin);
+        }
+    }
+
+    /**
+     * TODO When tracking integer-stamps, the state at each successor of a TypeSwitchNode should
+     * track an integer-stamp for the LoadHubNode (meet over the constants leading to that
+     * successor). However, are LoadHubNode-s shared frequently enough?
+     */
+    private void registerTypeSwitchNode(TypeSwitchNode typeSwitch, BeginNode begin) {
+        if (typeSwitch.value() instanceof LoadHubNode) {
+            LoadHubNode loadHub = (LoadHubNode) typeSwitch.value();
+            ResolvedJavaType type = null;
+            for (int i = 0; i < typeSwitch.keyCount(); i++) {
+                if (typeSwitch.keySuccessor(i) == begin) {
+                    if (type == null) {
+                        type = typeSwitch.typeAt(i);
+                    } else {
+                        type = FlowUtil.widen(type, typeSwitch.typeAt(i));
+                    }
+                }
+            }
+            if (type == null) {
+                // `begin` denotes the default case of the TypeSwitchNode
+                return;
+            }
+            if (state.knownNotToConform(loadHub.object(), type)) {
+                postponedDeopts.addDeoptAfter(begin, UnreachedCode);
+                state.impossiblePath();
+                return;
+            }
+            // it's unwarranted to assume loadHub.object() to be non-null
+            // it also seems unwarranted state.trackCC(loadHub.object(), type, begin);
+        }
+    }
+
+    /**
+     *
+     * <p>
+     * Reduce input nodes based on the state at the program point for the argument (ie, based on
+     * "valid facts" only, without relying on any floating-guard-assumption).
+     * </p>
+     *
+     * <p>
+     * For each (direct or indirect) child, a copy-on-write version is made in case any of its
+     * children changed, with the copy accommodating the updated children. If the parent was shared,
+     * copy-on-write prevents the updates from becoming visible to anyone but the invoker of this
+     * method.
+     * </p>
+     *
+     * <p>
+     * <b> Please note the parent node is mutated upon any descendant changing. No copy-on-write is
+     * performed for the parent node itself. </b>
+     * </p>
+     *
+     * <p>
+     * In more detail, for each direct {@link com.oracle.graal.nodes.ValueNode} input of the node at
+     * hand,
+     *
+     * <ol>
+     * <li>
+     * Obtain a lazy-copied version (via spanning tree) of the DAG rooted at the input-usage in
+     * question. Lazy-copying is done by walking a spanning tree of the original DAG, stopping at
+     * non-FloatingNodes but transitively walking FloatingNodes and their inputs. Upon arriving at a
+     * (floating) node N, the state's facts are checked to determine whether a constant C can be
+     * used instead in the resulting lazy-copied DAG. A NodeBitMap is used to realize the spanning
+     * tree.</li>
+     *
+     * <li>
+     * Provided one or more N-to-C node replacements took place, the resulting lazy-copied DAG has a
+     * parent different from the original (ie different object identity) which indicates the
+     * (copied, updated) DAG should replace the original via replaceFirstInput(), and inferStamp()
+     * should be invoked to reflect the updated inputs.</li>
+     *
+     * </ol>
+     * </p>
+     *
+     * @return whether any reduction was performed on the inputs of the arguments.
+     */
+    public boolean deverbosifyInputsInPlace(ValueNode parent) {
+        boolean changed = false;
+        for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) {
+            assert !(i instanceof GuardNode) : "ConditionalElim shouldn't run in MidTier";
+            ValueNode j = (ValueNode) reasoner.deverbosify(i);
+            if (i != j) {
+                changed = true;
+                FlowUtil.replaceInPlace(parent, i, j);
+            }
+        }
+        if (changed) {
+            FlowUtil.inferStampAndCheck(parent);
+        }
+        return changed;
+    }
+
+    /**
+     * Similar to {@link #deverbosifyInputsInPlace(com.oracle.graal.nodes.ValueNode)}, except that
+     * not the parent but a fresh clone is updated upon any of its children changing.
+     *
+     * @return the original parent if no updated took place, a copy-on-write version of it
+     *         otherwise.
+     *
+     */
+    private MethodCallTargetNode deverbosifyInputsCopyOnWrite(MethodCallTargetNode parent) {
+        MethodCallTargetNode changed = null;
+        for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) {
+            Node j = reasoner.deverbosify(i);
+            if (i != j) {
+                assert j != parent;
+                if (changed == null) {
+                    changed = (MethodCallTargetNode) parent.copyWithInputs();
+                    reasoner.added.add(changed);
+                    // copyWithInputs() implies graph.unique(changed)
+                    assert changed.isAlive();
+                    assert FlowUtil.lacksUsages(changed);
+                }
+                FlowUtil.replaceInPlace(changed, i, j);
+            }
+        }
+        if (changed == null) {
+            return parent;
+        }
+        FlowUtil.inferStampAndCheck(changed);
+        /*
+         * No need to rememberSubstitution() because not called from deverbosify(). In detail, it's
+         * only deverbosify() that skips visited nodes (thus we'd better have recorded any
+         * substitutions we want for them). Not this case.
+         */
+        return changed;
+    }
+
+    /**
+     * Precondition: This method assumes that either:
+     *
+     * <ul>
+     * <li>the state has already stabilized (ie no more pending iterations in the "iterative"
+     * dataflow algorithm); or</li>
+     * <li>any rewritings made based on the state in its current form are conservative enough to be
+     * safe.</li>
+     * </ul>
+     *
+     * <p>
+     * The overarching goal is to perform just enough rewriting to trigger other phases (
+     * {@link com.oracle.graal.graph.spi.SimplifierTool SimplifierTool},
+     * {@link com.oracle.graal.phases.common.DeadCodeEliminationPhase DeadCodeEliminationPhase},
+     * etc) to perform the bulk of rewriting, thus lowering the maintenance burden.
+     * </p>
+     *
+     */
+    @Override
+    protected void node(FixedNode node) {
+
+        assert node.isAlive();
+
+        /*-------------------------------------------------------------------------------------
+         * Step 1: Unreachable paths are still visited (PostOrderNodeIterator requires all ends
+         * of a merge to have been visited), but time is saved by neither updating the state nor
+         * rewriting anything while on an an unreachable path.
+         *-------------------------------------------------------------------------------------
+         */
+        if (state.isUnreachable) {
+            return;
+        }
+
+        /*-------------------------------------------------------------------------------------
+         * Step 2: For an AbstractBeginNode, determine whether this path is reachable, register
+         * any associated guards.
+         *-------------------------------------------------------------------------------------
+         */
+        if (node instanceof BeginNode) {
+            BeginNode begin = (BeginNode) node;
+            Node pred = node.predecessor();
+
+            if (pred != null) {
+                registerControlSplit(pred, begin);
+            }
+            return;
+        }
+
+        /*-------------------------------------------------------------------------------------
+         * Step 3: Check whether EquationalReasoner caches should be cleared upon state updates.
+         *-------------------------------------------------------------------------------------
+         */
+        reasoner.updateState(state);
+
+        /*-------------------------------------------------------------------------------------
+         * Step 4: Whatever special-case handling makes sense for the FixedNode at hand before
+         * its inputs are reduced.
+         *-------------------------------------------------------------------------------------
+         */
+
+        if (node instanceof AbstractEndNode) {
+            visitAbstractEndNode((AbstractEndNode) node);
+            return;
+        } else if (node instanceof Invoke) {
+            visitInvoke((Invoke) node);
+            return;
+        } else if (node instanceof CheckCastNode) {
+            // it's important not to call deverbosification for visitCheckCastNode()
+            visitCheckCastNode((CheckCastNode) node);
+            return;
+        } else if (node instanceof GuardingPiNode) {
+            visitGuardingPiNode((GuardingPiNode) node);
+            return;
+        } else if (node instanceof NullCheckNode) {
+            visitNullCheckNode((NullCheckNode) node);
+            return;
+        } else if (node instanceof FixedGuardNode) {
+            visitFixedGuardNode((FixedGuardNode) node);
+            return;
+        } else if (node instanceof ConditionAnchorNode) {
+            // ConditionAnchorNode shouldn't occur during HighTier
+            return;
+        }
+
+        /*-------------------------------------------------------------------------------------
+         * Step 5: After special-case handling, we do our best for those FixedNode-s
+         * where the effort to reduce their inputs might pay off.
+         *
+         * Why is this useful? For example, by the time the AbstractBeginNode for an If-branch
+         * is visited (in general a ControlSplitNode), the If-condition will have gone already
+         * through simplification (and thus potentially have been reduced to a
+         * LogicConstantNode).
+         *-------------------------------------------------------------------------------------
+         */
+        boolean paysOffToReduce = false;
+        if (node instanceof ControlSplitNode) {
+            // desire to simplify control flow
+            paysOffToReduce = true;
+        } else if (node instanceof ReturnNode) {
+            paysOffToReduce = true;
+        } else if (node instanceof AccessFieldNode || node instanceof AccessArrayNode) {
+            // desire to remove null-checks
+            paysOffToReduce = true;
+        }
+
+        // TODO comb the remaining FixedWithNextNode subclasses, pick those with good changes of
+        // paying-off
+
+        // TODO UnsafeLoadNode takes a condition
+
+        if (paysOffToReduce) {
+            deverbosifyInputsInPlace(node);
+        }
+
+        /*---------------------------------------------------------------------------------------
+         * Step 6: Any additional special-case handling, this time after having inputs reduced.
+         * For example, leverage anchors provided by the FixedNode, to add facts to the factbase.
+         *---------------------------------------------------------------------------------------
+         */
+
+        // TODO some nodes are GuardingNodes (eg, FixedAccessNode) we could use them to track state
+        // TODO others are additionally guarded (eg JavaReadNode), thus *their* guards could be
+        // simplified.
+
+    }
+
+    /**
+     * In case the scrutinee:
+     *
+     * <ul>
+     * <li>is known to be null, an unconditional deopt is added.</li>
+     * <li>is known to be non-null, the NullCheckNode is removed.</li>
+     * <li>otherwise, the NullCheckNode is lowered to a FixedGuardNode which then allows using it as
+     * anchor for state-tracking.</li>
+     * </ul>
+     *
+     * <p>
+     * Precondition: the input (ie, object) hasn't been deverbosified yet.
+     * </p>
+     */
+    private void visitNullCheckNode(NullCheckNode ncn) {
+        ValueNode object = ncn.getObject();
+        if (state.isNull(object)) {
+            postponedDeopts.addDeoptBefore(ncn, NullCheckException);
+            state.impossiblePath();
+            return;
+        }
+        if (state.isNonNull(object)) {
+            /*
+             * Redundant NullCheckNode. Unlike GuardingPiNode or FixedGuardNode, NullCheckNode-s
+             * aren't used as GuardingNode-s, thus in this case can be removed without further ado.
+             */
+            assert FlowUtil.lacksUsages(ncn);
+            graph.removeFixed(ncn);
+            return;
+        }
+        /*
+         * Lower the NullCheckNode to a FixedGuardNode which then allows using it as anchor for
+         * state-tracking. TODO the assumption here is that the code emitted for the resulting
+         * FixedGuardNode is as efficient as for NullCheckNode.
+         */
+        IsNullNode isNN = graph.unique(new IsNullNode(object));
+        reasoner.added.add(isNN);
+        FixedGuardNode nullCheck = graph.add(new FixedGuardNode(isNN, UnreachedCode, InvalidateReprofile, true));
+        graph.replaceFixedWithFixed(ncn, nullCheck);
+
+        state.trackNN(object, nullCheck);
+    }
+
+    /**
+     * The {@link com.oracle.graal.nodes.AbstractEndNode} at the end of the current code path
+     * contributes values to {@link com.oracle.graal.nodes.PhiNode}s. Now is a good time to
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify} those values.
+     *
+     * <p>
+     * Precondition: inputs haven't been deverbosified yet.
+     * </p>
+     */
+    private void visitAbstractEndNode(AbstractEndNode endNode) {
+        MergeNode merge = endNode.merge();
+        for (PhiNode phi : merge.phis()) {
+            if (phi instanceof ValuePhiNode && phi.getKind() == Kind.Object) {
+                assert phi.verify();
+                int index = merge.phiPredecessorIndex(endNode);
+                ValueNode original = phi.valueAt(index);
+                ValueNode reduced = (ValueNode) reasoner.deverbosify(original);
+                if (reduced != original) {
+                    phi.setValueAt(index, reduced);
+                    // `original` if unused will be removed in finished()
+                }
+            }
+        }
+    }
+
+    /**
+     * One or more arguments at `invoke` may have control-flow sensitive simplifications. In such
+     * case, a new {@link com.oracle.graal.nodes.java.MethodCallTargetNode MethodCallTargetNode} is
+     * prepared just for this callsite, consuming reduced arguments. This proves useful in
+     * connection with inlining, in order to specialize callees on the types of arguments other than
+     * the receiver (examples: multi-methods, the inlining problem, lambdas as arguments).
+     *
+     * <p>
+     * Precondition: inputs haven't been deverbosified yet.
+     * </p>
+     */
+    private void visitInvoke(Invoke invoke) {
+        if (invoke.asNode().stamp() instanceof IllegalStamp) {
+            return; // just to be safe
+        }
+        boolean isMethodCallTarget = invoke.callTarget() instanceof MethodCallTargetNode;
+        if (!isMethodCallTarget) {
+            return;
+        }
+        FlowUtil.replaceInPlace(invoke.asNode(), invoke.callTarget(), deverbosifyInputsCopyOnWrite((MethodCallTargetNode) invoke.callTarget()));
+        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+        if (callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Interface && callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Virtual) {
+            return;
+        }
+        ValueNode receiver = callTarget.receiver();
+        if (receiver == null) {
+            return;
+        }
+        if (!FlowUtil.hasLegalObjectStamp(receiver)) {
+            return;
+        }
+        Witness w = state.typeInfo(receiver);
+        ResolvedJavaType type;
+        ResolvedJavaType stampType = StampTool.typeOrNull(receiver);
+        if (w == null || w.cluelessAboutType()) {
+            // can't improve on stamp but wil try to devirtualize anyway
+            type = stampType;
+        } else {
+            type = FlowUtil.tighten(w.type(), stampType);
+        }
+        if (type == null) {
+            return;
+        }
+        ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod());
+        if (method == null) {
+            return;
+        }
+        if (method.canBeStaticallyBound() || Modifier.isFinal(type.getModifiers())) {
+            metricMethodResolved.increment();
+            callTarget.setInvokeKind(MethodCallTargetNode.InvokeKind.Special);
+            callTarget.setTargetMethod(method);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReductionPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,54 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+public class FlowSensitiveReductionPhase extends BasePhase<PhaseContext> {
+
+    private final MetaAccessProvider metaAccess;
+
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    public FlowSensitiveReductionPhase(MetaAccessProvider metaAccess) {
+        this.metaAccess = metaAccess;
+    }
+
+    @Override
+    protected final void run(StructuredGraph graph, PhaseContext context) {
+        try (Debug.Scope s = Debug.scope("FlowSensitiveReduction")) {
+            Debug.dump(graph, "FlowSensitiveReduction initial");
+            new FlowSensitiveReduction(graph.start(), new State(), context).apply();
+            Debug.dump(graph, "FlowSensitiveReduction done");
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,317 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugConfig;
+import com.oracle.graal.debug.DebugConfigScope;
+import com.oracle.graal.debug.internal.DebugScope;
+import com.oracle.graal.graph.InputType;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class FlowUtil {
+
+    private FlowUtil() {
+        // no instances of this class
+    }
+
+    public static boolean lacksUsages(Node n) {
+        return n.recordsUsages() && n.usages().isEmpty();
+    }
+
+    public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) {
+        if (a == null || b == null) {
+            return null;
+        } else if (a.equals(b)) {
+            return a;
+        } else {
+            return a.findLeastCommonAncestor(b);
+        }
+    }
+
+    /**
+     * @return whether the first argument is strictly more precise than the second.
+     */
+    public static boolean isMorePrecise(ResolvedJavaType a, ResolvedJavaType b) {
+        if (a == null) {
+            return false;
+        }
+        if (b == null) {
+            return true;
+        }
+        assert !a.isPrimitive();
+        assert !b.isPrimitive();
+        if (a.equals(b)) {
+            return false;
+        }
+        if (b.isInterface()) {
+            return b.isAssignableFrom(a);
+        }
+        if (a.isInterface()) {
+            return b.isInterface() && b.isAssignableFrom(a);
+        }
+        return b.isAssignableFrom(a);
+    }
+
+    public static ResolvedJavaType tighten(ResolvedJavaType a, ResolvedJavaType b) {
+        if (a == null) {
+            assert b == null || !b.isPrimitive();
+            return b;
+        }
+        if (b == null) {
+            assert !a.isPrimitive();
+            return a;
+        }
+        assert !a.isPrimitive();
+        assert !b.isPrimitive();
+        if (a.equals(b)) {
+            return a;
+        }
+        if (isMorePrecise(a, b)) {
+            return a;
+        } else if (isMorePrecise(b, a)) {
+            return b;
+        } else {
+            /*
+             * Not comparable, two cases:
+             * 
+             * Example 1: 'a' standing for j.l.Number and 'b' for j.l.String We return null for lack
+             * of a value representing NullType, the right answer. Same goes when both arguments are
+             * non-comparable interfaces.
+             * 
+             * Example 2: 'a' standing for sun/nio/ch/DirectBuffer (an interface) and b for
+             * java/nio/Buffer (an abstract class). The class always takes precedence.
+             */
+            if (a.isInterface()) {
+                return b.isInterface() ? null : b;
+            }
+            if (b.isInterface()) {
+                return a.isInterface() ? null : a;
+            }
+            return null; // a and b aren't comparable, can't tighten() them
+        }
+    }
+
+    /**
+     *
+     * There are "illegal" stamps that are not of type IllegalStamp.
+     *
+     * For example, there may be an IntegerStamp with upperBound < lowerBound that returns
+     * !isLegal() but we still know it's an integer and thus not of type IllegalStamp.
+     *
+     * An IllegalStamp should never happen. In contrast, !isLegal() values could happen due to dead
+     * code not yet removed, or upon some non-sideeffecting instructions floating out of a dead
+     * branch.
+     */
+    public static boolean isLegalObjectStamp(Stamp s) {
+        return isObjectStamp(s) && s.isLegal();
+    }
+
+    public static boolean hasLegalObjectStamp(ValueNode v) {
+        return isLegalObjectStamp(v.stamp());
+    }
+
+    public static boolean isObjectStamp(Stamp stamp) {
+        return stamp instanceof ObjectStamp;
+    }
+
+    public static void inferStampAndCheck(ValueNode n) {
+        n.inferStamp();
+        if (n.stamp() instanceof ObjectStamp) {
+            ObjectStamp objectStamp = (ObjectStamp) n.stamp();
+            assert !objectStamp.isExactType() || objectStamp.type() != null;
+        }
+    }
+
+    /**
+     * Compares the arguments along three dimensions (nullness, exactness, and type). For the first
+     * argument to be more precise than the second, it may not score lower in any dimension and must
+     * score higher in at least one dimension.
+     *
+     * When comparing types s and t, sameness counts as 0; while being more precise is awarded with
+     * a score of 1. In all other cases (non-comparable, or supertype) the score is -1.
+     *
+     * @return whether the first argument is strictly more precise than the second.
+     */
+    public static boolean isMorePrecise(ObjectStamp a, ObjectStamp b) {
+        int d0 = MINUS(a.alwaysNull(), b.alwaysNull());
+        if (d0 == -1) {
+            return false;
+        }
+        int d1 = MINUS(a.nonNull(), b.nonNull());
+        if (d1 == -1) {
+            return false;
+        }
+        int d2 = MINUS(a.isExactType(), b.isExactType());
+        if (d2 == -1) {
+            return false;
+        }
+        int d3;
+        ResolvedJavaType ta = a.type();
+        ResolvedJavaType tb = b.type();
+        if (ta == null) {
+            d3 = (tb == null) ? 0 : -1;
+        } else if (tb == null) {
+            d3 = 1;
+        } else if (isMorePrecise(ta, tb)) {
+            d3 = 1;
+        } else if (ta.equals(tb)) {
+            d3 = 0;
+        } else {
+            d3 = -1;
+        }
+        if (d3 == -1) {
+            return false;
+        }
+        int maxScore = Math.max(Math.max(d0, d1), Math.max(d2, d3));
+        return maxScore > 0;
+    }
+
+    private static int MINUS(boolean a, boolean b) {
+        int aa = a ? 1 : 0;
+        int bb = b ? 1 : 0;
+        return aa - bb;
+    }
+
+    public static LogicConstantNode asLogicConstantNode(LogicNode cond) {
+        return (cond instanceof LogicConstantNode) ? (LogicConstantNode) cond : null;
+    }
+
+    public static boolean isLiteralNode(ValueNode f) {
+        return f instanceof ConstantNode || f instanceof LogicConstantNode;
+    }
+
+    public static boolean isConstantTrue(LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && c.getValue();
+    }
+
+    public static boolean isConstantFalse(LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && !c.getValue();
+    }
+
+    public static boolean alwaysFails(boolean isNegated, LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && (c.getValue() == isNegated);
+    }
+
+    public static boolean alwaysSucceeds(boolean isNegated, LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && (c.getValue() != isNegated);
+    }
+
+    /**
+     * Returns (preserving order) the ValueNodes without duplicates found among the argument's
+     * direct inputs.
+     */
+    @SuppressWarnings("unchecked")
+    public static List<ValueNode> distinctValueAndConditionInputs(Node n) {
+        ArrayList<ValueNode> result = null;
+        NodeClass.NodeClassIterator iter = n.inputs().iterator();
+        while (iter.hasNext()) {
+            NodeClass.Position pos = iter.nextPosition();
+            InputType inputType = pos.getInputType(n);
+            boolean isReducibleInput = (inputType == InputType.Value || inputType == InputType.Condition);
+            if (isReducibleInput) {
+                ValueNode i = (ValueNode) pos.get(n);
+                if (!isLiteralNode(i)) {
+                    if (result == null) {
+                        result = new ArrayList<>();
+                    }
+                    if (!result.contains(i)) {
+                        result.add(i);
+                    }
+                }
+            }
+        }
+        return result == null ? Collections.EMPTY_LIST : result;
+    }
+
+    public static ObjectStamp asNonNullStamp(ObjectStamp stamp) {
+        ObjectStamp result = (ObjectStamp) stamp.join(StampFactory.objectNonNull());
+        assert result.isLegal();
+        return result;
+    }
+
+    public static ObjectStamp asRefinedStamp(ObjectStamp stamp, ResolvedJavaType joinType) {
+        assert !joinType.isInterface();
+        ObjectStamp result = (ObjectStamp) stamp.join(StampFactory.declared(joinType));
+        assert result.isLegal();
+        return result;
+    }
+
+    /**
+     * Start situation: the parent node has <code>oldInput</code> among its (direct) inputs. After
+     * this method has run, all such occurrences have been replaced with <code>newInput</code>. In
+     * case that makes <code>oldInput</code> disconnected, it is removed from the graph.
+     */
+    public static void replaceInPlace(Node parent, Node oldInput, Node newInput) {
+        assert parent != null;
+        assert parent.inputs().contains(oldInput);
+        if (oldInput == newInput) {
+            return;
+        }
+        assert oldInput != null && newInput != null;
+        assert !isLiteralNode((ValueNode) oldInput);
+        do {
+            parent.replaceFirstInput(oldInput, newInput);
+        } while (parent.inputs().contains(oldInput));
+        // `oldInput` if unused wil be removed in finished()
+    }
+
+    public static StructuredGraph visualize(StructuredGraph graph, String title) {
+        DebugConfig debugConfig = DebugScope.getConfig();
+        DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, debugConfig.dumpHandlers(), debugConfig.output());
+        try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
+            Debug.dump(graph, title);
+
+            return graph;
+        }
+    }
+
+    public static final String ANSI_RESET = "\u001B[0m";
+    public static final String ANSI_BLACK = "\u001B[30m";
+    public static final String ANSI_RED = "\u001B[31m";
+    public static final String ANSI_GREEN = "\u001B[32m";
+    public static final String ANSI_YELLOW = "\u001B[33m";
+    public static final String ANSI_BLUE = "\u001B[34m";
+    public static final String ANSI_PURPLE = "\u001B[35m";
+    public static final String ANSI_CYAN = "\u001B[36m";
+    public static final String ANSI_WHITE = "\u001B[37m";
+
+    public static void highlightInRed(String msg) {
+        System.out.println(ANSI_RED + msg + ANSI_RESET);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,373 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+/**
+ * <p>
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.GuardingPiNode}.
+ * </p>
+ * 
+ * @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+ */
+public abstract class GuardingPiReduction extends BaseReduction {
+
+    public GuardingPiReduction(FixedNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * <p>
+     * By the time a {@link com.oracle.graal.nodes.GuardingPiNode GuardingPiNode} is visited, the
+     * available type refinements may allow reductions similar to those performed for
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     * CheckCastNode}.
+     * </p>
+     * 
+     * <ol>
+     * <li>
+     * If the condition needs no reduction (ie, it's already a
+     * {@link com.oracle.graal.nodes.LogicConstantNode LogicConstantNode}), this method basically
+     * gives up (thus letting other phases take care of it).</li>
+     * <li>
+     * Otherwise, an attempt is made to find a {@link com.oracle.graal.nodes.extended.GuardingNode}
+     * that implies the combination of (negated, condition) of the
+     * {@link com.oracle.graal.nodes.GuardingPiNode} being visited. Details in
+     * {@link #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}. If found, the node
+     * can be removed.</li>
+     * <li>
+     * Otherwise, the node is lowered to a {@link com.oracle.graal.nodes.FixedGuardNode} and its
+     * usages replaced with {@link com.oracle.graal.nodes.PiNode}. Details in
+     * {@link #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}.</li>
+     * </ol>
+     * 
+     * <p>
+     * Precondition: the condition hasn't been deverbosified yet.
+     * </p>
+     * 
+     */
+    protected final void visitGuardingPiNode(GuardingPiNode envelope) {
+
+        if (!FlowUtil.hasLegalObjectStamp(envelope)) {
+            // this situation exercised by com.oracle.graal.jtt.optimize.NCE_FlowSensitive02
+            return;
+        }
+        if (!FlowUtil.hasLegalObjectStamp(envelope.object())) {
+            return;
+        }
+
+        /*
+         * (1 of 3) Cover the case of GuardingPiNode(LogicConstantNode, ...)
+         */
+
+        if (envelope.condition() instanceof LogicConstantNode) {
+            if (FlowUtil.alwaysFails(envelope.isNegated(), envelope.condition())) {
+                state.impossiblePath();
+                // let GuardingPiNode(false).canonical() prune the dead-code control-path
+                return;
+            }
+            // if not always-fails and condition-constant, then it always-succeeds!
+            assert FlowUtil.alwaysSucceeds(envelope.isNegated(), envelope.condition());
+            // let GuardingPiNode(true).canonical() replaceAtUsages
+            return;
+        }
+
+        /*
+         * The trick used in visitFixedGuardNode to look up an equivalent GuardingNode for the
+         * combination of (negated, condition) at hand doesn't work for GuardingPiNode, because the
+         * condition showing up here (a ShortCircuitOrNode that can be detected by
+         * CastCheckExtractor) doesn't appear as key in trueFacts, falseFacts. Good thing we have
+         * CastCheckExtractor!
+         */
+
+        /*
+         * (2 of 3) Cover the case of the condition known-to-be-false or known-to-be-true, but not
+         * LogicConstantNode.
+         * 
+         * If deverbosify(condition) == falseConstant, it would be safe to set:
+         * `envelope.setCondition(falseConstant)` (only the API won't allow).
+         * 
+         * On the other hand, it's totally unsafe to do something like that for trueConstant. What
+         * we can do about that case is the province of `tryRemoveGuardingPiNode(envelope)`
+         */
+
+        if (tryRemoveGuardingPiNode(envelope)) {
+            return;
+        }
+
+        /*
+         * Experience has shown that an attempt to eliminate the current GuardingPiNode by using a
+         * GuardingNode already in scope and with equivalent condition (grabbed from `trueFacts`
+         * resp. `falseFacts`) proves futile. Therefore we're not even attempting that here.
+         */
+
+        /*
+         * (3 of 3) Neither always-succeeds nor always-fails, ie we don't known. Converting to
+         * FixedGuardNode allows tracking the condition via a GuardingNode, thus potentially
+         * triggering simplifications down the road.
+         */
+        FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(envelope.condition(), envelope.getReason(), envelope.getAction(), envelope.isNegated()));
+        graph.addBeforeFixed(envelope, fixedGuard);
+
+        if (!FlowUtil.lacksUsages(envelope)) {
+            // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+            PiNode replacement = graph.unique(new PiNode(envelope.object(), envelope.stamp(), fixedGuard));
+            reasoner.added.add(replacement);
+            // before removing the GuardingPiNode replace its usages
+            envelope.replaceAtUsages(replacement);
+        }
+
+        graph.removeFixed(envelope);
+
+        state.addFact(!fixedGuard.isNegated(), fixedGuard.condition(), fixedGuard);
+
+    }
+
+    /**
+     * <p>
+     * Based on flow-sensitive knowledge, two pre-requisites have to be fulfilled in order to remove
+     * a {@link com.oracle.graal.nodes.GuardingPiNode}:
+     * 
+     * <ul>
+     * <li>the condition must refer only to the payload of the
+     * {@link com.oracle.graal.nodes.GuardingPiNode}</li>
+     * <li>the condition must check properties about which the state tracks not only a true/false
+     * answer, but also an anchor witnessing that fact</li>
+     * <li>the condition may not check anything else beyond what's stated in the items above.</li>
+     * </ul>
+     * </p>
+     * 
+     * <p>
+     * Provided a condition as above can be reduced to a constant (and an anchor obtained in the
+     * process), this method replaces all usages of the
+     * {@link com.oracle.graal.nodes.GuardingPiNode} (necessarily of
+     * {@link com.oracle.graal.graph.InputType#Value}) with a {@link com.oracle.graal.nodes.PiNode}
+     * that wraps the payload and the anchor in question.
+     * </p>
+     * 
+     * <p>
+     * Precondition: the condition hasn't been deverbosified yet.
+     * </p>
+     * 
+     * @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+     * 
+     */
+    private boolean tryRemoveGuardingPiNode(GuardingPiNode envelope) {
+
+        LogicNode cond = envelope.condition();
+        ValueNode payload = envelope.object();
+
+        ObjectStamp outgoingStamp = (ObjectStamp) envelope.stamp();
+        ObjectStamp payloadStamp = (ObjectStamp) payload.stamp();
+
+        if (isNullCheckOn(cond, payload)) {
+            if (envelope.isNegated()) {
+                /*
+                 * GuardingPiNode succeeds if payload non-null
+                 */
+                if (!outgoingStamp.equals(FlowUtil.asNonNullStamp(payloadStamp))) {
+                    warnAboutOutOfTheBlueGuardingPiNode(envelope);
+                }
+                return tryRemoveGuardingPiNodeNonNullCond(envelope);
+            } else {
+                /*
+                 * GuardingPiNode succeeds if payload null
+                 */
+                ValueNode replacement = StampTool.isObjectAlwaysNull(payload) ? payload : reasoner.nonTrivialNull(payload);
+                if (replacement != null) {
+                    // replacement == null means !isKnownNull(payload)
+                    removeGuardingPiNode(envelope, replacement);
+                    return true;
+                }
+                return false;
+            }
+        } else if (CastCheckExtractor.isInstanceOfCheckOn(cond, payload)) {
+            if (envelope.isNegated()) {
+                return false;
+            }
+            /*
+             * GuardingPiNode succeeds if payload instanceof <something>
+             */
+            InstanceOfNode io = (InstanceOfNode) cond;
+            assert io.type() != null;
+            Witness w = state.typeInfo(payload);
+            if (w != null && w.isNonNull() && isEqualOrMorePrecise(w.type(), io.type())) {
+                ValueNode d = reasoner.downcast(payload);
+                removeGuardingPiNode(envelope, d);
+                return true;
+            }
+            return false;
+        } else if (cond instanceof ShortCircuitOrNode) {
+            if (envelope.isNegated()) {
+                return false;
+            }
+            CastCheckExtractor cce = CastCheckExtractor.extract(cond);
+            if (cce == null || cce.subject != payload) {
+                return false;
+            }
+            /*
+             * GuardingPiNode succeeds if payload check-casts toType
+             */
+            return tryRemoveGuardingPiNodeCheckCastCond(envelope, cce.type);
+        }
+
+        return false;
+    }
+
+    /**
+     * Porcelain method.
+     * 
+     * This method handles the case where the GuardingPiNode succeeds if payload known to be
+     * non-null.
+     * 
+     * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+     */
+    private boolean tryRemoveGuardingPiNodeNonNullCond(GuardingPiNode envelope) {
+
+        ValueNode payload = envelope.object();
+
+        if (state.isNull(payload)) {
+            // the GuardingPiNode fails always
+            postponedDeopts.addDeoptBefore(envelope, envelope.getReason());
+            state.impossiblePath();
+            return true;
+        }
+
+        if (StampTool.isObjectNonNull(payload)) {
+            // payload needs no downcasting, it satisfies as-is the GuardingPiNode's condition.
+            if (precisionLoss(envelope, payload)) {
+                /*
+                 * TODO The GuardingPiNode has an outgoing stamp whose narrowing goes beyond what
+                 * the condition checks. That's suspicious.
+                 */
+                PiNode replacement = graph.unique(new PiNode(payload, envelope.stamp()));
+                reasoner.added.add(replacement);
+                removeGuardingPiNode(envelope, replacement);
+                return true;
+            } else {
+                removeGuardingPiNode(envelope, payload);
+                return true;
+            }
+        }
+        // if a non-null witness available, the GuardingPiNode can be removed
+
+        Witness w = state.typeInfo(payload);
+        GuardingNode nonNullAnchor = (w != null && w.isNonNull()) ? w.guard() : null;
+        if (nonNullAnchor != null) {
+            PiNode replacement = graph.unique(new PiNode(payload, envelope.stamp(), nonNullAnchor.asNode()));
+            reasoner.added.add(replacement);
+            removeGuardingPiNode(envelope, replacement);
+            return true;
+        }
+
+        /*
+         * TODO What about, nodes that always denote non-null values? (Even though their stamp
+         * forgot to make that clear) Candidates: ObjectGetClassNode, Parameter(0) on instance
+         */
+
+        return false;
+    }
+
+    /**
+     * Porcelain method.
+     * 
+     * This method handles the case where the GuardingPiNode succeeds if payload null or its actual
+     * type equal or subtype of `toType`
+     * 
+     * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+     * 
+     */
+    private boolean tryRemoveGuardingPiNodeCheckCastCond(GuardingPiNode envelope, ResolvedJavaType toType) {
+        assert toType != null;
+        ValueNode payload = envelope.object();
+
+        ObjectStamp outgoingStamp = (ObjectStamp) envelope.stamp();
+        ObjectStamp payloadStamp = (ObjectStamp) payload.stamp();
+
+        if (!outgoingStamp.equals(FlowUtil.asRefinedStamp(payloadStamp, toType))) {
+            warnAboutOutOfTheBlueGuardingPiNode(envelope);
+        }
+
+        ValueNode d = reasoner.downcast(payload);
+        if (d == null) {
+            return false;
+        }
+
+        if (StampTool.isObjectAlwaysNull(d)) {
+            removeGuardingPiNode(envelope, d);
+            return true;
+        }
+        ObjectStamp dStamp = (ObjectStamp) d.stamp();
+        if (isEqualOrMorePrecise(dStamp.type(), toType)) {
+            removeGuardingPiNode(envelope, d);
+            return true;
+        }
+        return false;
+    }
+
+    /*
+     * TODO There should be an assert in GuardingPiNode to detect that as soon as it happens
+     * (constructor, setStamp).
+     */
+    private static void warnAboutOutOfTheBlueGuardingPiNode(GuardingPiNode envelope) {
+        Debug.log(String.format("GuardingPiNode has an outgoing stamp whose narrowing goes beyond what its condition checks: %s", envelope));
+    }
+
+    private static boolean isNullCheckOn(LogicNode cond, ValueNode subject) {
+        if (!(cond instanceof IsNullNode)) {
+            return false;
+        }
+        IsNullNode isNull = (IsNullNode) cond;
+        return isNull.object() == subject;
+    }
+
+    /**
+     * Porcelain method.
+     */
+    private void removeGuardingPiNode(GuardingPiNode envelope, ValueNode replacement) {
+        assert !precisionLoss(envelope, replacement);
+        metricGuardingPiNodeRemoved.increment();
+        envelope.replaceAtUsages(replacement);
+        assert FlowUtil.lacksUsages(envelope);
+        graph.removeFixed(envelope);
+    }
+
+    public static boolean isEqualOrMorePrecise(ResolvedJavaType a, ResolvedJavaType b) {
+        return a.equals(b) || FlowUtil.isMorePrecise(a, b);
+    }
+
+    public static boolean isEqualOrMorePrecise(ObjectStamp a, ObjectStamp b) {
+        return a.equals(b) || FlowUtil.isMorePrecise(a, b);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Histogram.java	Tue Apr 29 12:43:27 2014 -0700
@@ -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.phases.common.cfs;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+public class Histogram extends TreeMap<Integer, Integer> {
+
+    private static final long serialVersionUID = 7188324319057387738L;
+
+    private final String prefix;
+
+    public Histogram(String prefix) {
+        this.prefix = prefix;
+    }
+
+    public void tick(int bucket) {
+        Integer entry = get(bucket);
+        put(bucket, entry == null ? 1 : entry + 1);
+    }
+
+    public void print() {
+
+        // printing takes time, allow concurrent updates during printing
+        Histogram histogram = clone();
+
+        float casesTotal = 0;
+        for (int i : histogram.values()) {
+            casesTotal += i;
+        }
+        for (Map.Entry<Integer, Integer> entry : histogram.entrySet()) {
+            int numCases = entry.getValue();
+            int percentOut = (int) (numCases / casesTotal * 100);
+            String msg = prefix + String.format("%d iters in %4d cases (%2d %%)", entry.getKey(), numCases, percentOut);
+            if (entry.getKey() > 3) {
+                FlowUtil.highlightInRed(msg);
+            } else {
+                System.out.println(msg);
+            }
+        }
+        System.out.println(prefix + "--------------------------");
+    }
+
+    @Override
+    public Histogram clone() {
+        return (Histogram) super.clone();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/IterativeFlowSensitiveReductionPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,90 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.util.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class IterativeFlowSensitiveReductionPhase extends BasePhase<PhaseContext> {
+
+    private static final int MAX_ITERATIONS = 256;
+
+    private final CanonicalizerPhase canonicalizer;
+
+    public IterativeFlowSensitiveReductionPhase(CanonicalizerPhase canonicalizer) {
+        this.canonicalizer = canonicalizer;
+    }
+
+    public static class CountingListener extends HashSetNodeChangeListener {
+
+        public int count;
+
+        @Override
+        public void nodeChanged(Node node) {
+            super.nodeChanged(node);
+        }
+
+    }
+
+    // private Histogram histogram = new Histogram("FSR-");
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        FlowSensitiveReductionPhase eliminate = new FlowSensitiveReductionPhase(context.getMetaAccess());
+        CountingListener listener = new CountingListener();
+        int count = 1;
+        while (true) {
+            listener.count = count;
+            graph.trackInputChange(listener);
+            graph.trackUsagesDroppedZero(listener);
+            eliminate.apply(graph, context);
+            graph.stopTrackingInputChange();
+            graph.stopTrackingUsagesDroppedZero();
+            if (listener.getChangedNodes().isEmpty()) {
+                // histogram.tick(count);
+                break;
+            }
+            for (Node node : graph.getNodes()) {
+                if (node instanceof Simplifiable) {
+                    listener.getChangedNodes().add(node);
+                }
+            }
+            canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
+            listener.getChangedNodes().clear();
+            if (++count > MAX_ITERATIONS) {
+                // System.out.println("Bailing out IterativeFlowSensitiveReductionPhase for graph: "
+                // + graph);
+                // FlowUtil.visualize(graph, "Bailout");
+                throw new BailoutException("Number of iterations in FlowSensitiveReductionPhase exceeds " + MAX_ITERATIONS);
+            }
+        }
+        // histogram.print();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,816 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.api.meta.Kind;
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.calc.ObjectEqualsNode;
+import com.oracle.graal.nodes.extended.GuardedNode;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.java.InstanceOfNode;
+import com.oracle.graal.nodes.spi.ValueProxy;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.graph.MergeableState;
+
+import java.lang.reflect.Modifier;
+import java.util.*;
+
+/**
+ * A State instance is mutated in place as each FixedNode is visited in a basic block of
+ * instructions. Basic block: starts with a {@link com.oracle.graal.nodes.BeginNode BeginNode}, ends
+ * at an {@link com.oracle.graal.nodes.EndNode EndNode} or
+ * {@link com.oracle.graal.nodes.ControlSinkNode ControlSinkNode} and lacks intervening control
+ * splits or merges.
+ */
+public final class State extends MergeableState<State> implements Cloneable {
+
+    private static final DebugMetric metricTypeRegistered = Debug.metric("TypeRegistered");
+    private static final DebugMetric metricNullnessRegistered = Debug.metric("NullnessRegistered");
+    private static final DebugMetric metricObjectEqualsRegistered = Debug.metric("ObjectEqualsRegistered");
+    private static final DebugMetric metricImpossiblePathDetected = Debug.metric("ImpossiblePathDetected");
+
+    /**
+     * <p>
+     * Each state update results in a higher {@link State#versionNr versionNr}. The
+     * {@link State#versionNr versionNr} of different State instances can't be meaningfully compared
+     * (ie, same {@link State#versionNr versionNr} just indicates they've gone through the same
+     * number of updates). In particular, the {@link State#versionNr versionNr} of a merged state
+     * doesn't guarantee any more than being different from those of the states being merged.
+     * </p>
+     *
+     * <p>
+     * Still, {@link State#versionNr versionNr} proves useful in two cases:
+     *
+     * <ul>
+     * <li>recording the {@link State#versionNr versionNr} right after {@link State State} cloning,
+     * allows finding out afterwards whether (a) both states have diverged, (b) just one of them, or
+     * (c) none of them.</li>
+     * <li>a {@link State State} may become {@link State#isUnreachable isUnreachable}. In such case,
+     * it may make a difference whether any updates were performed on the state from the time it was
+     * cloned. Those updates indicate information not available in the state is was cloned from. For
+     * the purposes of {@link FlowSensitiveReduction FlowSensitiveReduction} an unreachable state
+     * need not be merged with any other (because control-flow won't reach the merge point over the
+     * path of the unreachable state).</li>
+     * </ul>
+     * </p>
+     *
+     */
+    int versionNr = 0;
+
+    boolean isUnreachable = false;
+
+    /**
+     * Getting here implies an opportunity was detected for dead-code-elimination. A counterpoint
+     * argument goes as follows: perhaps we don't get here that often, in which case the effort to
+     * detect an "impossible path" could be shaved off.
+     *
+     * @see com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt
+     */
+    void impossiblePath() {
+        isUnreachable = true;
+        metricImpossiblePathDetected.increment();
+    }
+
+    /**
+     * <p>
+     * This map semantically tracks "facts" (ie, properties valid for the program-point the state
+     * refers to) as opposed to floating-guard-dependent properties. The
+     * {@link com.oracle.graal.nodes.extended.GuardingNode} being tracked comes handy at
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)}
+     * .
+     * </p>
+     *
+     * <p>
+     * On a related note, {@link #typeRefinements} also captures information the way
+     * {@link #trueFacts} and {@link #falseFacts} do, including "witnessing" guards. Why not just
+     * standardize on one of them, and drop the other? Because the {@link #typeRefinements} eagerly
+     * aggregates information for easier querying afterwards, e.g. when producing a "downcasted"
+     * value (which involves building a {@link com.oracle.graal.nodes.PiNode}, see
+     * {@link EquationalReasoner#downcast(com.oracle.graal.nodes.ValueNode) downcast()}
+     * </p>
+     *
+     */
+    private IdentityHashMap<ValueNode, Witness> typeRefinements;
+
+    IdentityHashMap<ValueNode, GuardingNode> knownNull;
+    IdentityHashMap<LogicNode, GuardingNode> trueFacts;
+    IdentityHashMap<LogicNode, GuardingNode> falseFacts;
+
+    public State() {
+        this.typeRefinements = new IdentityHashMap<>();
+        this.knownNull = new IdentityHashMap<>();
+        this.trueFacts = new IdentityHashMap<>();
+        this.falseFacts = new IdentityHashMap<>();
+    }
+
+    public State(State other) {
+        this.isUnreachable = other.isUnreachable;
+        this.versionNr = other.versionNr;
+        this.typeRefinements = new IdentityHashMap<>();
+        for (Map.Entry<ValueNode, Witness> entry : other.typeRefinements.entrySet()) {
+            this.typeRefinements.put(entry.getKey(), new Witness(entry.getValue()));
+        }
+        this.knownNull = new IdentityHashMap<>(other.knownNull);
+        this.trueFacts = new IdentityHashMap<>(other.trueFacts);
+        this.falseFacts = new IdentityHashMap<>(other.falseFacts);
+    }
+
+    /**
+     * @return A new list containing only those states that are reachable.
+     */
+    private static ArrayList<State> reachableStates(List<State> states) {
+        ArrayList<State> result = new ArrayList<>(states);
+        Iterator<State> iter = result.iterator();
+        while (iter.hasNext()) {
+            if (iter.next().isUnreachable) {
+                iter.remove();
+            }
+        }
+        return result;
+    }
+
+    private IdentityHashMap<ValueNode, Witness> mergeKnownTypes(MergeNode merge, ArrayList<State> withReachableStates) {
+        IdentityHashMap<ValueNode, Witness> newKnownTypes = new IdentityHashMap<>();
+
+        for (Map.Entry<ValueNode, Witness> entry : typeRefinements.entrySet()) {
+            ValueNode node = entry.getKey();
+            Witness type = new Witness(entry.getValue());
+
+            for (State other : withReachableStates) {
+                Witness otherType = other.typeInfo(node);
+                if (otherType == null) {
+                    type = null;
+                    break;
+                }
+                type.merge(otherType, merge);
+            }
+            if (type != null && type.knowsBetterThan(node)) {
+                assert node == GraphUtil.unproxify(node);
+                newKnownTypes.put(node, type);
+            }
+        }
+
+        return newKnownTypes;
+    }
+
+    private IdentityHashMap<ValueNode, GuardingNode> mergeKnownNull(MergeNode merge, ArrayList<State> withReachableStates) {
+        // newKnownNull starts empty
+        IdentityHashMap<ValueNode, GuardingNode> newKnownNull = new IdentityHashMap<>();
+        for (Map.Entry<ValueNode, GuardingNode> entry : knownNull.entrySet()) {
+            ValueNode key = entry.getKey();
+            GuardingNode newGN = entry.getValue();
+            boolean missing = false;
+
+            for (State other : withReachableStates) {
+                GuardingNode otherGuard = other.knownNull.get(key);
+                if (otherGuard == null) {
+                    missing = true;
+                    break;
+                }
+                if (otherGuard != newGN) {
+                    newGN = merge;
+                }
+            }
+            if (!missing) {
+                newKnownNull.put(key, newGN);
+            }
+        }
+        return newKnownNull;
+    }
+
+    /**
+     * <p>
+     * This method handles phis, by adding to the resulting state any information that can be gained
+     * (about type-refinement and nullness) based on the data available at each of the incoming
+     * branches.
+     * </p>
+     *
+     * <p>
+     * In more detail, <code>FlowSensitiveReduction#visitAbstractEndNode()</code> has already
+     * deverbosified the phi-values contributed by each reachable branch. The paths that
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction} determined to be
+     * unreachable will be eliminated by canonicalization and dead code elimination. For now they
+     * still exist, thus polluting the result of
+     * {@link com.oracle.graal.nodes.ValuePhiNode#inferPhiStamp()} but we are careful to skip them
+     * when merging type-witnesses and known-null maps.
+     * </p>
+     */
+    private void mergePhis(MergeNode merge, List<State> withStates, IdentityHashMap<ValueNode, Witness> newKnownPhiTypes, IdentityHashMap<ValueNode, GuardingNode> newKnownNullPhis) {
+
+        if (merge instanceof LoopBeginNode) {
+            return;
+        }
+
+        for (PhiNode phi : merge.phis()) {
+            assert phi == GraphUtil.unproxify(phi);
+            if (phi instanceof ValuePhiNode && phi.getKind() == Kind.Object) {
+                ArrayList<ValueNode> reachingValues = new ArrayList<>();
+                if (!isUnreachable) {
+                    reachingValues.add(phi.valueAt(0));
+                }
+                for (int i = 0; i < withStates.size(); i++) {
+                    State otherState = withStates.get(i);
+                    if (!otherState.isUnreachable) {
+                        reachingValues.add(phi.valueAt(i + 1));
+                    }
+                }
+                assert !reachingValues.isEmpty();
+                ObjectStamp phiStamp = (ObjectStamp) phi.stamp();
+                ObjectStamp nonPollutedStamp = (ObjectStamp) StampTool.meet(reachingValues);
+                Witness w = new Witness(nonPollutedStamp, merge);
+                if (FlowUtil.isMorePrecise(w.type(), phiStamp.type())) {
+                    // precision gain regarding type
+                    newKnownPhiTypes.put(phi, w);
+                    // confirm no precision loss regarding nullness
+                    assert implies(phiStamp.nonNull(), w.isNonNull());
+                } else if (w.isNonNull() && !phiStamp.nonNull()) {
+                    // precision gain regarding nullness
+                    newKnownPhiTypes.put(phi, w);
+                    // confirm no precision loss regarding type
+                    assert !FlowUtil.isMorePrecise(phiStamp.type(), w.type());
+                }
+                if (nonPollutedStamp.alwaysNull()) {
+                    newKnownNullPhis.put(phi, merge);
+                }
+            }
+        }
+
+    }
+
+    private static boolean implies(boolean a, boolean b) {
+        return !a || b;
+    }
+
+    @Override
+    public boolean merge(MergeNode merge, List<State> withStates) {
+
+        ArrayList<State> withReachableStates = reachableStates(withStates);
+        if (withReachableStates.isEmpty()) {
+            return true;
+        }
+
+        for (State other : withReachableStates) {
+            versionNr = Math.max(versionNr, other.versionNr) + 1;
+            if (!other.isUnreachable) {
+                isUnreachable = false;
+            }
+        }
+
+        if (isUnreachable) {
+            typeRefinements.clear();
+            knownNull.clear();
+            trueFacts.clear();
+            falseFacts.clear();
+            return true;
+        }
+
+        // may also get updated in a moment, during processing of phi nodes.
+        IdentityHashMap<ValueNode, Witness> newKnownTypes = mergeKnownTypes(merge, withReachableStates);
+        // may also get updated in a moment, during processing of phi nodes.
+        IdentityHashMap<ValueNode, GuardingNode> newKnownNull = mergeKnownNull(merge, withReachableStates);
+        mergePhis(merge, withStates, newKnownTypes, newKnownNull);
+        this.typeRefinements = newKnownTypes;
+        this.knownNull = newKnownNull;
+
+        this.trueFacts = mergeTrueFacts(withReachableStates, merge);
+        this.falseFacts = mergeFalseFacts(withReachableStates, merge);
+        return true;
+    }
+
+    private IdentityHashMap<LogicNode, GuardingNode> mergeTrueFacts(ArrayList<State> withReachableStates, GuardingNode merge) {
+        IdentityHashMap<LogicNode, GuardingNode> newTrueConditions = new IdentityHashMap<>();
+        for (Map.Entry<LogicNode, GuardingNode> entry : trueFacts.entrySet()) {
+            LogicNode check = entry.getKey();
+            GuardingNode guard = entry.getValue();
+
+            for (State other : withReachableStates) {
+                GuardingNode otherGuard = other.trueFacts.get(check);
+                if (otherGuard == null) {
+                    guard = null;
+                    break;
+                }
+                if (otherGuard != guard) {
+                    guard = merge;
+                }
+            }
+            if (guard != null) {
+                newTrueConditions.put(check, guard);
+            }
+        }
+        return newTrueConditions;
+    }
+
+    private IdentityHashMap<LogicNode, GuardingNode> mergeFalseFacts(ArrayList<State> withReachableStates, GuardingNode merge) {
+        IdentityHashMap<LogicNode, GuardingNode> newFalseConditions = new IdentityHashMap<>();
+        for (Map.Entry<LogicNode, GuardingNode> entry : falseFacts.entrySet()) {
+            LogicNode check = entry.getKey();
+            GuardingNode guard = entry.getValue();
+
+            for (State other : withReachableStates) {
+                GuardingNode otherGuard = other.falseFacts.get(check);
+                if (otherGuard == null) {
+                    guard = null;
+                    break;
+                }
+                if (otherGuard != guard) {
+                    guard = merge;
+                }
+            }
+            if (guard != null) {
+                newFalseConditions.put(check, guard);
+            }
+        }
+        return newFalseConditions;
+    }
+
+    /**
+     * @return null if no type-witness available for the argument, the witness otherwise.
+     */
+    public Witness typeInfo(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        return typeRefinements.get(GraphUtil.unproxify(object));
+    }
+
+    /**
+     * @return true iff the argument is known to stand for null.
+     */
+    public boolean isNull(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        return StampTool.isObjectAlwaysNull(object) || knownNull.containsKey(GraphUtil.unproxify(object));
+    }
+
+    /**
+     * <p>
+     * It makes a difference calling {@link Witness#isNonNull()} as opposed to
+     * {@link State#isNonNull(com.oracle.graal.nodes.ValueNode)}. The former guarantees the witness
+     * provides a guard certifying non-nullness. The latter just tells us there exists some guard
+     * that certifies the property we asked about.
+     * </p>
+     *
+     * <p>
+     * TODO improvement: isKnownNonNull could be made smarter by noticing some nodes always denote a
+     * non-null value (eg, ObjectGetClassNode). Similarly for isKnownNull. Code that looks at the
+     * stamp as well as code that looks for a non-null-witness would benefit from also checking such
+     * extended isKnownNonNull. Alternatively, the stamp of those nodes should always have
+     * is-non-null set.
+     * </p>
+     *
+     * @return true iff the argument is known to stand for non-null.
+     */
+    public boolean isNonNull(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        if (StampTool.isObjectNonNull(object)) {
+            return true;
+        }
+        Witness w = typeInfo(object);
+        return w == null ? false : w.isNonNull();
+    }
+
+    /**
+     * @return true iff the argument is known to stand for an object conforming to the given type.
+     */
+    public boolean knownToConform(ValueNode object, ResolvedJavaType to) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        assert !to.isPrimitive();
+        ResolvedJavaType stampType = StampTool.typeOrNull(object);
+        if (stampType != null && to.isAssignableFrom(stampType)) {
+            return true;
+        }
+        final ValueNode scrutinee = GraphUtil.unproxify(object);
+        if (isNull(scrutinee)) {
+            return true;
+        }
+        Witness w = typeInfo(scrutinee);
+        boolean witnessAnswer = w != null && w.type() != null && to.isAssignableFrom(w.type());
+        if (witnessAnswer) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @return true iff the argument is known to stand for an object that definitely does not
+     *         conform to the given type.
+     */
+    public boolean knownNotToConform(ValueNode object, ResolvedJavaType to) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        assert !to.isPrimitive();
+        final ValueNode scrutinee = GraphUtil.unproxify(object);
+        if (isNull(scrutinee)) {
+            return false;
+        }
+        ResolvedJavaType stampType = StampTool.typeOrNull(object);
+        if (stampType != null && knownNotToConform(stampType, to)) {
+            return true;
+        }
+        Witness w = typeInfo(scrutinee);
+        boolean witnessAnswer = w != null && !w.cluelessAboutType() && knownNotToConform(w.type(), to);
+        if (witnessAnswer) {
+            return true;
+        }
+        return false;
+    }
+
+    // @formatter:off
+    /**
+     *   \   |     |     |     |
+     *    \ b|     |     |     |
+     *   a \ |     |     |     |
+     *      \|iface|final|non-f|
+     *  -----+-----------------|
+     *  iface|  F  |  F  |  F  |
+     *  -----+-----------------|
+     *  final|  C  |  C  |  C  |
+     *  -----+-----------------|
+     *  non-f|  F  |  C  |  C  |
+     *  -----------------------+
+     *
+     *  where:
+     *    F:     false
+     *    C:     check
+     *    iface: interface
+     *    final: exact non-interface reference-type
+     *    non-f: non-exact non-interface reference-type
+     *
+     * @return true iff the first argument is known not to conform to the second argument.
+     */
+    // @formatter:on
+    public static boolean knownNotToConform(ResolvedJavaType a, ResolvedJavaType b) {
+        assert !a.isPrimitive();
+        assert !b.isPrimitive();
+        if (b.isAssignableFrom(a)) {
+            return false;
+        }
+        if (a.isInterface()) {
+            return false;
+        }
+        boolean aFinal = Modifier.isFinal(a.getModifiers());
+        if (b.isInterface() && !aFinal) {
+            return false;
+        }
+        if (a.isAssignableFrom(b)) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    @Override
+    public State clone() {
+        return new State(this);
+    }
+
+    /**
+     * Porcelain method.
+     */
+    private Witness getOrElseAddTypeInfo(ValueNode object) {
+        ValueNode scrutinee = GraphUtil.unproxify(object);
+        Witness w = typeRefinements.get(scrutinee);
+        if (w == null) {
+            w = new Witness();
+            typeRefinements.put(scrutinee, w);
+        }
+        return w;
+    }
+
+    /**
+     * <p>
+     * Updates this {@link State State} to account for an observation about the scrutinee being
+     * non-null. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.nodes.ValueNode, com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead.
+     * </p>
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller takes care of that.
+     * </p>
+     *
+     * @return whether state was updated (iff the observation added any new information)
+     */
+    public boolean trackNN(ValueNode object, GuardingNode anchor) {
+        if (isDependencyTainted(object, anchor)) {
+            return false;
+        }
+        assert anchor instanceof FixedNode;
+        ResolvedJavaType stampType = StampTool.typeOrNull(object);
+        if (stampType != null && !stampType.isInterface()) {
+            return trackIO(object, stampType, anchor);
+        }
+        Witness w = getOrElseAddTypeInfo(object);
+        if (w.trackNN(anchor)) {
+            versionNr++;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Updates this {@link State State} to account for an observation about the scrutinee conforming
+     * to a type. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.nodes.ValueNode, com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead.
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller must take care of that.
+     * </p>
+     *
+     * @return false iff the observed type is an interface, or doesn't provide any new information
+     *         not already known. Ie, this method returns true iff the observation resulted in
+     *         information gain.
+     */
+    public boolean trackCC(ValueNode object, ResolvedJavaType observed, GuardingNode anchor) {
+        if (observed.isInterface()) {
+            return false;
+        }
+        if (isDependencyTainted(object, anchor)) {
+            return false;
+        }
+        assert anchor instanceof FixedNode;
+        Witness w = getOrElseAddTypeInfo(object);
+        if (w.trackCC(observed, anchor)) {
+            versionNr++;
+            metricTypeRegistered.increment();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Updates this {@link State State} to account for an observation about the non-null scrutinee
+     * conforming to a type.
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller must take care of that.
+     * </p>
+     *
+     * @return whether state was updated (iff the observation added any new information)
+     */
+    public boolean trackIO(ValueNode object, ResolvedJavaType observed, GuardingNode anchor) {
+        assert !observed.isInterface() : "no infrastructure yet in State.Witness to support interfaces in general";
+        if (isDependencyTainted(object, anchor)) {
+            return false;
+        }
+        assert anchor instanceof FixedNode;
+        Witness w = getOrElseAddTypeInfo(object);
+        if (w.trackIO(observed, anchor)) {
+            versionNr++;
+            metricTypeRegistered.increment();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * This method increases {@link #versionNr} (thus potentially invalidating
+     * {@link EquationalReasoner EquationalReasoner}'s caches) only if the fact wasn't known
+     * already.
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller must take care of that.
+     * </p>
+     *
+     */
+    private void addFactPrimordial(LogicNode condition, IdentityHashMap<LogicNode, GuardingNode> to, GuardingNode anchor) {
+        assert condition != null;
+        if (!to.containsKey(condition)) {
+            versionNr++;
+            to.put(condition, anchor);
+        }
+    }
+
+    /**
+     * Ideas for the future:
+     * <ul>
+     * <li>track inferred less-than edges from (accumulated) CompareNode-s</li>
+     * <li>track set-representative for equality classes determined by (chained) IntegerTestNode</li>
+     * </ul>
+     *
+     */
+    public void addFact(boolean isTrue, LogicNode condition, GuardingNode anchor) {
+        assert anchor != null;
+        assert anchor instanceof FixedNode;
+        assert !isUnreachable;
+
+        if (condition instanceof LogicConstantNode) {
+            if (((LogicConstantNode) condition).getValue() != isTrue) {
+                impossiblePath();
+            }
+            return;
+        }
+
+        if (condition instanceof LogicNegationNode) {
+            addFact(!isTrue, ((LogicNegationNode) condition).getInput(), anchor);
+        } else if (condition instanceof ShortCircuitOrNode) {
+            /*
+             * We can register the conditions being or-ed as long as the anchor is a fixed node,
+             * because floating guards will be registered at a BeginNode but might be "valid" only
+             * later due to data flow dependencies. Therefore, registering both conditions of a
+             * ShortCircuitOrNode for a floating guard could lead to cycles in data flow, because
+             * the guard will be used as anchor for both conditions, and one condition could be
+             * depending on the other.
+             */
+            if (isTrue) {
+                CastCheckExtractor cce = CastCheckExtractor.extract(condition);
+                if (cce == null || isDependencyTainted(cce.subject, anchor)) {
+                    addFactPrimordial(condition, isTrue ? trueFacts : falseFacts, anchor);
+                } else {
+                    trackCC(cce.subject, cce.type, anchor);
+                }
+            } else {
+                ShortCircuitOrNode disjunction = (ShortCircuitOrNode) condition;
+                addFact(disjunction.isXNegated(), disjunction.getX(), anchor);
+                // previous addFact might have resulted in impossiblePath()
+                if (isUnreachable) {
+                    return;
+                }
+                addFact(disjunction.isYNegated(), disjunction.getY(), anchor);
+            }
+        } else if (condition instanceof InstanceOfNode) {
+            addFactInstanceOf(isTrue, (InstanceOfNode) condition, anchor);
+        } else if (condition instanceof IsNullNode) {
+            IsNullNode nullCheck = (IsNullNode) condition;
+            addNullness(isTrue, nullCheck.object(), anchor);
+        } else if (condition instanceof ObjectEqualsNode) {
+            addFactObjectEqualsNode(isTrue, (ObjectEqualsNode) condition, anchor);
+        } else {
+            addFactPrimordial(condition, isTrue ? trueFacts : falseFacts, anchor);
+        }
+    }
+
+    /**
+     * An instanceof hint is tracked differently depending on whether it's an interface-test or not
+     * (because type-refinements currently lacks the ability to track interface types).
+     *
+     */
+    private void addFactInstanceOf(boolean isTrue, InstanceOfNode instanceOf, GuardingNode anchor) {
+        ValueNode object = instanceOf.object();
+        if (isTrue) {
+            if (knownNotToConform(object, instanceOf.type())) {
+                impossiblePath();
+                return;
+            }
+            addNullness(false, object, anchor);
+            if (instanceOf.type().isInterface()) {
+                if (!knownToConform(object, instanceOf.type())) {
+                    addFactPrimordial(instanceOf, trueFacts, anchor);
+                }
+            } else {
+                trackIO(object, instanceOf.type(), anchor);
+            }
+        }
+    }
+
+    private void addFactObjectEqualsNode(boolean isTrue, ObjectEqualsNode equals, GuardingNode anchor) {
+        if (isDependencyTainted(equals.x(), anchor)) {
+            return;
+        }
+        if (isDependencyTainted(equals.y(), anchor)) {
+            return;
+        }
+        assert anchor instanceof FixedNode;
+        ValueNode x = GraphUtil.unproxify(equals.x());
+        ValueNode y = GraphUtil.unproxify(equals.y());
+        if (isTrue) {
+            if (isNull(x) && isNonNull(y)) {
+                impossiblePath();
+                return;
+            }
+            if (isNonNull(x) && isNull(y)) {
+                impossiblePath();
+                return;
+            }
+            if (isNull(x) || isNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(true, equals.x(), anchor);
+                addNullness(true, equals.y(), anchor);
+            } else if (isNonNull(x) || isNonNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(false, equals.x(), anchor);
+                addNullness(false, equals.y(), anchor);
+            }
+            Witness wx = typeInfo(x);
+            Witness wy = typeInfo(y);
+            if (wx == null && wy == null) {
+                return;
+            } else if (wx != null && wy != null) {
+                // tighten their type-hints, provided at least one available
+                // both witnesses may have seen == null, ie they may be NN witnesses
+                ResolvedJavaType best = FlowUtil.tighten(wx.type(), wy.type());
+                if (best != null) {
+                    assert !best.isInterface();
+                    // type tightening is enough, nullness already taken care of
+                    trackCC(equals.x(), best, anchor);
+                    trackCC(equals.y(), best, anchor);
+                }
+            } else if (wx == null) {
+                typeRefinements.put(x, new Witness(wy));
+            } else if (wy == null) {
+                typeRefinements.put(y, new Witness(wx));
+            }
+        } else {
+            if (isNull(x) && !isNonNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(false, equals.y(), anchor);
+            } else if (!isNonNull(x) && isNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(false, equals.x(), anchor);
+            }
+        }
+    }
+
+    /**
+     * Adds information about the nullness of a value. If isNull is true then the value is known to
+     * be null, otherwise the value is known to be non-null.
+     */
+    public void addNullness(boolean isNull, ValueNode value, GuardingNode anchor) {
+        if (isDependencyTainted(value, anchor)) {
+            return;
+        }
+        assert anchor instanceof FixedNode;
+        ValueNode original = GraphUtil.unproxify(value);
+        boolean wasNull = isNull(original);
+        boolean wasNonNull = isNonNull(original);
+        if (isNull) {
+            if (wasNonNull) {
+                impossiblePath();
+            } else {
+                metricNullnessRegistered.increment();
+                versionNr++;
+                knownNull.put(original, anchor);
+            }
+        } else {
+            if (wasNull) {
+                impossiblePath();
+            } else {
+                metricNullnessRegistered.increment();
+                trackNN(original, anchor);
+            }
+        }
+    }
+
+    /**
+     *
+     * @return true iff `value` may lose dependency not covered by `anchor`.
+     */
+    public static boolean isDependencyTainted(ValueNode value, GuardingNode anchor) {
+        assert anchor instanceof FixedNode;
+        if (value instanceof ValueProxy) {
+            if (value instanceof GuardedNode) {
+                GuardedNode gn = (GuardedNode) value;
+                GuardingNode guardian = gn.getGuard();
+                if (guardian != null) {
+                    boolean isGuardedByFixed = guardian instanceof FixedNode;
+                    if (!isGuardedByFixed) {
+                        return true;
+                    }
+                }
+            }
+            // if (value instanceof GuardingNode) {
+            // return true;
+            // }
+            ValueProxy proxy = (ValueProxy) value;
+            return isDependencyTainted(proxy.getOriginalNode(), anchor);
+        }
+        return false;
+    }
+
+    public void clear() {
+        versionNr = 0;
+        isUnreachable = false;
+        typeRefinements.clear();
+        knownNull.clear();
+        trueFacts.clear();
+        falseFacts.clear();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Witness.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,440 @@
+/*
+ * 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.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+
+/**
+ * <p>
+ * A witness progressively tracks more detailed properties about an object value (the scrutinee);
+ * the properties in question comprise whether the scrutinee has been observed:
+ *
+ * <ul>
+ * <li>as non-null,</li>
+ * <li>in a successful checkcast, or</li>
+ * <li>in a successful instanceof.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * A witness is updated only when doing so increases the information content of the witness. For
+ * example, upon visiting a {@link com.oracle.graal.nodes.java.CheckCastNode CheckCastNode} the
+ * witness gets a chance to become updated.
+ * </p>
+ *
+ * <p>
+ * Therefore, at any given time, a witness represents the most detailed knowledge available so far
+ * about the scrutinee, which is the knowledge most relevant for upcoming program-points.
+ * </p>
+ *
+ * <p>
+ * The availability of witnesses about both non-nullness and checkcast (for a given scrutinee)
+ * promotes to an instanceof-style witness . The "levels" of knowledge a witness may exhibit are
+ * captured by {@link com.oracle.graal.phases.common.cfs.Witness.LEVEL}. For conciseness, the
+ * following query methods are available for a {@link com.oracle.graal.phases.common.cfs.Witness}:
+ * <ul>
+ * <li>{@link #atNonNull()}</li>
+ * <li>{@link #atCheckCast()}</li>
+ * <li>{@link #atInstanceOf()}</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * Only non-interface object types (ie, class and array types) are tracked. Small extensions are
+ * required to track interfaces, extensions that might be added after the current scheme proves
+ * itself.
+ * </p>
+ *
+ * <p>
+ * Some useful facts about the Statechart implemented by {@link Witness Witness}:
+ *
+ * <ul>
+ * <li>the start-state is "clueless"</li>
+ * <li>
+ * A self-transition via trackCC from whichever the current state is to itself, without information
+ * gain, is always possible. Just give {@link Object java.lang.Object} as observed type.</li>
+ * </ul>
+ * </p>
+ *
+ */
+public class Witness implements Cloneable {
+
+    private static enum LEVEL {
+        CLUELESS,
+        NN,
+        CC,
+        IO
+    }
+
+    private boolean atNonNull() {
+        return level == LEVEL.NN;
+    }
+
+    private boolean atCheckCast() {
+        return level == LEVEL.CC;
+    }
+
+    private boolean atInstanceOf() {
+        return level == LEVEL.IO;
+    }
+
+    private void transition(LEVEL to, GuardingNode newAnchor) {
+        this.level = to;
+        this.gn = newAnchor;
+        assert repOK();
+    }
+
+    public Witness() {
+    }
+
+    public Witness(Witness other) {
+        level = other.level;
+        seen = other.seen;
+        gn = other.gn;
+    }
+
+    /**
+     * Counterpart to {@link #asStamp()}
+     */
+    public Witness(ObjectStamp stamp, GuardingNode anchor) {
+        assert stamp.isLegal();
+        assert anchor != null;
+        boolean isNonIface = (stamp.type() != null && !stamp.type().isInterface());
+        if (stamp.nonNull()) {
+            if (isNonIface) {
+                seen = stamp.type();
+                transition(LEVEL.IO, anchor);
+            } else {
+                seen = null;
+                transition(LEVEL.NN, anchor);
+            }
+        } else {
+            if (isNonIface) {
+                seen = stamp.type();
+                transition(LEVEL.CC, anchor);
+            } else {
+                seen = null;
+                transition(LEVEL.CLUELESS, null);
+                assert clueless();
+            }
+        }
+        assert repOK();
+    }
+
+    /**
+     * Type-witnesses aren't tracked for known-to-be-null. Therefore, although method
+     * {@link #isNonNull() isNonNull()} can be found in this class there's on purpose no companion
+     * <code>isNull()</code> .
+     */
+    public boolean isNonNull() {
+        return atNonNull() || atInstanceOf();
+    }
+
+    /**
+     * The most precise type known so far about the scrutinee. (Please notice that nothing can be
+     * deduced about the non-nullness-status of the scrutinee from invoking this method alone).
+     */
+    public ResolvedJavaType type() {
+        return seen;
+    }
+
+    public ObjectStamp asStamp() {
+        boolean isKnownExact = (seen != null && seen.equals(seen.asExactType()));
+        return new ObjectStamp(seen, isKnownExact, isNonNull(), false);
+    }
+
+    private LEVEL level = LEVEL.CLUELESS;
+    private ResolvedJavaType seen = null;
+
+    /**
+     * Evidence (ie, a {@link com.oracle.graal.nodes.extended.GuardingNode}) attesting to the status
+     * reported by this witness.
+     *
+     * May be one of:
+     *
+     * <ul>
+     * <li>
+     * {@link com.oracle.graal.nodes.BeginNode BeginNode},</li>
+     * <li>
+     * {@link com.oracle.graal.nodes.LoopExitNode LoopExitNode},</li>
+     * <li>
+     * {@link com.oracle.graal.nodes.FixedGuardNode FixedGuardNode}</li>
+     * <li>{@link com.oracle.graal.nodes.MergeNode MergeNode}, resulting from merging two witnesses
+     * with different values for this anchor</li>
+     * </ul>
+     *
+     * <p>
+     * An {@link com.oracle.graal.nodes.calc.ObjectEqualsNode ObjectEqualsNode} test results in the
+     * more-clueless of both scrutinees having its witness upgraded to that of the other (both
+     * scrutinees share the same {@link Witness Witness} instance from then on). For this reason,
+     * this field may also hold the anchors associated to an
+     * {@link com.oracle.graal.nodes.calc.ObjectEqualsNode ObjectEqualsNode} occurrence, ie nodes
+     * that can serve as {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} for the
+     * purposes of building a {@link com.oracle.graal.nodes.PiNode PiNode}.
+     * </p>
+     *
+     */
+    private GuardingNode gn = null;
+
+    /**
+     * Invariants of this class:
+     * <ul>
+     * <li>All fields holding null is ok, the hallmark of a {@link #clueless() clueless} witness.
+     * Another way for a witness to be clueless is by recording <code>java.lang.Object</code> as the
+     * seen type and nothing more.</li>
+     * <li>{@link #seen seen} may be null as long as the only hint being recorded is non-nullness</li>
+     * <li>A non-null value for {@link #seen seen} can't be tracked with NN, that combination
+     * amounts to IO and is tracked as such</li>
+     * <li>At most one of NN, CC, IO may be tracked at any given time</li>
+     * <li>A non-null CC or a non-null IO force {@link #seen seen} to be non-null</li>
+     * <li>{@link #seen seen} must be null or denote a non-interface reference type (ie, either a
+     * class-type or an array-type)</li>
+     * </ul>
+     */
+    private boolean repOK() {
+        if (clueless()) {
+            assert level == LEVEL.CLUELESS;
+            return true;
+        }
+        if (level == LEVEL.NN) {
+            assert seen == null;
+        }
+        if (seen != null) {
+            assert !seen.isInterface();
+            assert !seen.isPrimitive();
+        }
+        boolean gnOK = gn instanceof BeginNode || gn instanceof LoopExitNode || gn instanceof MergeNode || gn instanceof FixedGuardNode;
+        assert gnOK;
+        return true;
+    }
+
+    /**
+     * Helper method for readability in complex conditions.
+     */
+    public boolean clueless() {
+        return cluelessAboutType() && cluelessAboutNonNullness();
+    }
+
+    /**
+     * Helper method for readability in complex conditions.
+     */
+    public boolean cluelessAboutType() {
+        // TODO also clueless when `seen` is `java.lang.Object`
+        return seen == null;
+    }
+
+    /**
+     * Helper method for readability in complex conditions.
+     */
+    public boolean cluelessAboutNonNullness() {
+        return !atNonNull() && !atInstanceOf();
+    }
+
+    /**
+     * Whether this {@link Witness Witness} tracks information strictly more precise than that in
+     * the given {@link com.oracle.graal.compiler.common.type.ObjectStamp}.
+     */
+    boolean knowsBetterThan(ObjectStamp other) {
+        return FlowUtil.isMorePrecise(asStamp(), other);
+    }
+
+    /**
+     * Whether this {@link Witness Witness} tracks information strictly more precise than that in
+     * the {@link com.oracle.graal.compiler.common.type.ObjectStamp} of the given argument.
+     */
+    boolean knowsBetterThan(ValueNode other) {
+        return knowsBetterThan((ObjectStamp) other.stamp());
+    }
+
+    /**
+     * Porcelain method for internal use only, invoked upon a Facade method being notified about
+     * checkcast or instanceof.
+     *
+     * @return whether the state was updated (iff the observation adds any new information)
+     */
+    private boolean refinesSeenType(ResolvedJavaType observed) {
+        if (cluelessAboutType() || FlowUtil.isMorePrecise(observed, seen)) {
+            seen = observed;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Updates this {@link Witness Witness} to account for an observation about the scrutinee being
+     * non-null. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead
+     *
+     * @return whether this {@link Witness Witness} was updated (iff the observation adds any new
+     *         information)
+     */
+    public boolean trackNN(GuardingNode anchor) {
+        assert repOK();
+        try {
+            if (atInstanceOf()) {
+                return false;
+            }
+            if (atCheckCast()) {
+                transition(LEVEL.IO, anchor);
+                return true;
+            }
+            if (!atNonNull()) {
+                transition(LEVEL.NN, anchor);
+                return true;
+            }
+            return false;
+        } finally {
+            assert repOK();
+        }
+    }
+
+    /**
+     * Updates this {@link Witness Witness} to account for an observation about the scrutinee
+     * conforming to the provided type. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead.
+     *
+     * @return true iff information was gained.
+     */
+    public boolean trackCC(ResolvedJavaType observed, GuardingNode anchor) {
+        assert !observed.isInterface();
+        assert anchor != null;
+        assert repOK();
+        try {
+            boolean anchorObsolete = refinesSeenType(observed);
+            if (atInstanceOf()) {
+                /*
+                 * Statechart: self-transition at IO, potential information gain.
+                 */
+                if (anchorObsolete) {
+                    transition(LEVEL.IO, anchor);
+                    return true;
+                }
+                return false;
+            }
+            if (anchorObsolete) {
+                if (!atNonNull()) {
+                    /* Statechart: transition from clueless to CC. */
+                    transition(LEVEL.CC, anchor);
+                    return true;
+                } else {
+                    /* Statechart: transition from NN to IO. */
+                    transition(LEVEL.IO, anchor);
+                    return true;
+                }
+            }
+            /*
+             * Statechart: self-transition from whichever the current state is to itself, without
+             * information gain.
+             */
+            return false;
+        } finally {
+            assert repOK();
+        }
+    }
+
+    /**
+     * Updates this {@link Witness Witness} to account for an observation about the non-null
+     * scrutinee conforming to a type.
+     *
+     * @return whether this {@link Witness Witness} was updated (iff the observation adds any new
+     *         information)
+     */
+    public boolean trackIO(ResolvedJavaType observed, GuardingNode anchor) {
+        assert repOK();
+        try {
+            boolean gotMorePreciseType = refinesSeenType(observed);
+            if (!atInstanceOf() || gotMorePreciseType) {
+                transition(LEVEL.IO, anchor);
+                return true;
+            }
+            return gotMorePreciseType;
+        } finally {
+            assert repOK();
+        }
+    }
+
+    /**
+     * Shallow cloning is enough because what's reachable from {@link Witness} is primitive or used
+     * read-only when merging states.
+     */
+    @Override
+    public Witness clone() {
+        return new Witness(this);
+    }
+
+    /**
+     * @return null for a clueless method, non-null otherwise.
+     */
+    GuardingNode guard() {
+        return gn;
+    }
+
+    /**
+     * Merges another state into this one, by mutating this object, the other is left as is.
+     */
+    public void merge(Witness that, MergeNode merge) {
+        assert this.repOK();
+        assert that.repOK();
+
+        if (clueless()) {
+            return;
+        }
+
+        // umbrella type over the observations from both witnesses
+        ResolvedJavaType newSeen = (seen == null || that.seen == null) ? null : FlowUtil.widen(seen, that.seen);
+
+        // preserve guarding node only if matches other, otherwise settle on `merge`
+        final GuardingNode resultGuard = guard() == that.guard() ? guard() : merge;
+
+        /*
+         * guarantee on (both conformance and non-nullness) required from each input in order for
+         * the result to be able to offer such guarantee
+         */
+        final boolean resultIO = atInstanceOf() && that.atInstanceOf();
+        /* failing that, attempt to rescue type-conformance */
+        final boolean resultCC = !resultIO && (!cluelessAboutType() && !that.cluelessAboutType());
+        /* if all else fails, attempt to rescue non-nullness */
+        final boolean resultNN = !resultIO && !resultCC && (isNonNull() && that.isNonNull());
+
+        seen = newSeen;
+        level = resultIO ? LEVEL.IO : resultCC ? LEVEL.CC : resultNN ? LEVEL.NN : LEVEL.CLUELESS;
+        gn = resultGuard;
+
+        assert repOK();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(cluelessAboutType() ? "seen=?" : "seen=" + seen);
+        sb.append(";");
+        sb.append("gn=" + gn);
+        return sb.toString();
+    }
+
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -72,7 +72,7 @@
         try (TimerCloseable a = phaseTimer.start(); Scope s = Debug.scope(getClass(), this)) {
             BasePhase.this.run(graph, context);
             phaseMetric.increment();
-            if (dumpGraph) {
+            if (dumpGraph && Debug.isDumpEnabled()) {
                 Debug.dump(graph, "After phase %s", getName());
             }
             assert graph.verify();
@@ -81,13 +81,17 @@
         }
     }
 
+    protected CharSequence createName() {
+        String s = BasePhase.this.getClass().getSimpleName();
+        if (s.endsWith("Phase")) {
+            s = s.substring(0, s.length() - "Phase".length());
+        }
+        return s;
+    }
+
     public final CharSequence getName() {
         if (name == null) {
-            String s = BasePhase.this.getClass().getSimpleName();
-            if (s.endsWith("Phase")) {
-                s = s.substring(0, s.length() - "Phase".length());
-            }
-            name = s;
+            name = createName();
         }
         return name;
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -888,37 +888,114 @@
         return true;
     }
 
+    private static class SortState {
+        private Block block;
+        private NodeBitMap visited;
+        private NodeBitMap beforeLastLocation;
+        private List<ScheduledNode> sortedInstructions;
+        private List<FloatingReadNode> reads;
+
+        SortState(Block block, NodeBitMap visited, NodeBitMap beforeLastLocation, List<ScheduledNode> sortedInstructions) {
+            this.block = block;
+            this.visited = visited;
+            this.beforeLastLocation = beforeLastLocation;
+            this.sortedInstructions = sortedInstructions;
+            this.reads = null;
+        }
+
+        public Block currentBlock() {
+            return block;
+        }
+
+        void markVisited(Node n) {
+            visited.mark(n);
+        }
+
+        boolean isVisited(Node n) {
+            return visited.isMarked(n);
+        }
+
+        void markBeforeLastLocation(FloatingReadNode n) {
+            beforeLastLocation.mark(n);
+        }
+
+        void clearBeforeLastLocation(FloatingReadNode frn) {
+            beforeLastLocation.clear(frn);
+        }
+
+        boolean isBeforeLastLocation(FloatingReadNode n) {
+            return beforeLastLocation.isMarked(n);
+        }
+
+        void addRead(FloatingReadNode n) {
+            if (reads == null) {
+                reads = new ArrayList<>();
+            }
+            reads.add(n);
+        }
+
+        int readsSize() {
+            if (reads == null) {
+                return 0;
+            }
+            return reads.size();
+        }
+
+        void removeRead(ScheduledNode i) {
+            assert reads != null;
+            reads.remove(i);
+        }
+
+        List<FloatingReadNode> readsSnapshot() {
+            assert reads != null;
+            return new ArrayList<>(reads);
+        }
+
+        List<ScheduledNode> getSortedInstructions() {
+            return sortedInstructions;
+        }
+
+        boolean containsInstruction(ScheduledNode i) {
+            return sortedInstructions.contains(i);
+        }
+
+        void addInstruction(ScheduledNode i) {
+            sortedInstructions.add(i);
+        }
+    }
+
     /**
      * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over
      * all inputs. This means that a node is added to the list after all its inputs have been
      * processed.
      */
     private List<ScheduledNode> sortNodesWithinBlockLatest(Block b, NodeBitMap visited, NodeBitMap beforeLastLocation) {
+        SortState state = new SortState(b, visited, beforeLastLocation, new ArrayList<>(blockToNodesMap.get(b).size() + 2));
         List<ScheduledNode> instructions = blockToNodesMap.get(b);
-        List<ScheduledNode> sortedInstructions = new ArrayList<>(blockToNodesMap.get(b).size() + 2);
-        List<FloatingReadNode> reads = new ArrayList<>();
 
         if (memsched == MemoryScheduling.OPTIMAL) {
             for (ScheduledNode i : instructions) {
                 if (i instanceof FloatingReadNode) {
                     FloatingReadNode frn = (FloatingReadNode) i;
                     if (frn.location().getLocationIdentity() != FINAL_LOCATION) {
-                        reads.add(frn);
+                        state.addRead(frn);
                         if (nodesFor(b).contains(frn.getLastLocationAccess())) {
-                            assert !beforeLastLocation.isMarked(frn);
-                            beforeLastLocation.mark(frn);
+                            assert !state.isBeforeLastLocation(frn);
+                            state.markBeforeLastLocation(frn);
                         }
                     }
                 }
             }
         }
+
         for (ScheduledNode i : instructions) {
-            addToLatestSorting(b, i, sortedInstructions, visited, reads, beforeLastLocation);
+            addToLatestSorting(i, state);
         }
-        assert reads.size() == 0 : "not all reads are scheduled";
+        assert state.readsSize() == 0 : "not all reads are scheduled";
 
         // Make sure that last node gets really last (i.e. when a frame state successor hangs off
         // it).
+        List<ScheduledNode> sortedInstructions = state.getSortedInstructions();
         Node lastSorted = sortedInstructions.get(sortedInstructions.size() - 1);
         if (lastSorted != b.getEndNode()) {
             int idx = sortedInstructions.indexOf(b.getEndNode());
@@ -944,40 +1021,39 @@
         return sortedInstructions;
     }
 
-    private void processKillLocation(Block b, Node node, LocationIdentity identity, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads,
-                    NodeBitMap beforeLastLocation) {
-        for (FloatingReadNode frn : new ArrayList<>(reads)) { // TODO: change to iterator?
+    private void processKillLocation(Node node, LocationIdentity identity, SortState state) {
+        for (FloatingReadNode frn : state.readsSnapshot()) {
             LocationIdentity readLocation = frn.location().getLocationIdentity();
             assert readLocation != FINAL_LOCATION;
             if (frn.getLastLocationAccess() == node) {
                 assert identity == ANY_LOCATION || readLocation == identity : "location doesn't match: " + readLocation + ", " + identity;
-                beforeLastLocation.clear(frn);
-            } else if (!beforeLastLocation.isMarked(frn) && (readLocation == identity || (node != getCFG().graph.start() && ANY_LOCATION == identity))) {
-                reads.remove(frn);
-                addToLatestSorting(b, frn, sortedInstructions, visited, reads, beforeLastLocation);
+                state.clearBeforeLastLocation(frn);
+            } else if (!state.isBeforeLastLocation(frn) && (readLocation == identity || (node != getCFG().graph.start() && ANY_LOCATION == identity))) {
+                state.removeRead(frn);
+                addToLatestSorting(frn, state);
             }
         }
     }
 
-    private void addUnscheduledToLatestSorting(Block b, VirtualState state, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads, NodeBitMap beforeLastLocation) {
+    private void addUnscheduledToLatestSorting(VirtualState state, SortState sortState) {
         if (state != null) {
             // UnscheduledNodes should never be marked as visited.
-            if (visited.isMarked(state)) {
+            if (sortState.isVisited(state)) {
                 throw new SchedulingError();
             }
 
             for (Node input : state.inputs()) {
                 if (input instanceof VirtualState) {
-                    addUnscheduledToLatestSorting(b, (VirtualState) input, sortedInstructions, visited, reads, beforeLastLocation);
+                    addUnscheduledToLatestSorting((VirtualState) input, sortState);
                 } else {
-                    addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
+                    addToLatestSorting((ScheduledNode) input, sortState);
                 }
             }
         }
     }
 
-    private void addToLatestSorting(Block b, ScheduledNode i, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads, NodeBitMap beforeLastLocation) {
-        if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode) {
+    private void addToLatestSorting(ScheduledNode i, SortState state) {
+        if (i == null || state.isVisited(i) || cfg.getNodeToBlock().get(i) != state.currentBlock() || i instanceof PhiNode) {
             return;
         }
 
@@ -986,39 +1062,47 @@
             stateAfter = ((StateSplit) i).stateAfter();
         }
 
+        if (i instanceof LoopExitNode) {
+            for (ProxyNode proxy : ((LoopExitNode) i).proxies()) {
+                addToLatestSorting(proxy, state);
+            }
+        }
+
         for (Node input : i.inputs()) {
             if (input instanceof FrameState) {
                 if (input != stateAfter) {
-                    addUnscheduledToLatestSorting(b, (FrameState) input, sortedInstructions, visited, reads, beforeLastLocation);
+                    addUnscheduledToLatestSorting((FrameState) input, state);
                 }
             } else {
-                addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
+                if (!(i instanceof ProxyNode && input instanceof LoopExitNode)) {
+                    addToLatestSorting((ScheduledNode) input, state);
+                }
             }
         }
 
-        if (memsched == MemoryScheduling.OPTIMAL && reads.size() != 0) {
+        if (memsched == MemoryScheduling.OPTIMAL && state.readsSize() != 0) {
             if (i instanceof MemoryCheckpoint.Single) {
                 LocationIdentity identity = ((MemoryCheckpoint.Single) i).getLocationIdentity();
-                processKillLocation(b, i, identity, sortedInstructions, visited, reads, beforeLastLocation);
+                processKillLocation(i, identity, state);
             } else if (i instanceof MemoryCheckpoint.Multi) {
                 for (LocationIdentity identity : ((MemoryCheckpoint.Multi) i).getLocationIdentities()) {
-                    processKillLocation(b, i, identity, sortedInstructions, visited, reads, beforeLastLocation);
+                    processKillLocation(i, identity, state);
                 }
             }
             assert MemoryCheckpoint.TypeAssertion.correctType(i);
         }
 
-        addToLatestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited, reads, beforeLastLocation);
-        visited.mark(i);
-        addUnscheduledToLatestSorting(b, stateAfter, sortedInstructions, visited, reads, beforeLastLocation);
+        addToLatestSorting((ScheduledNode) i.predecessor(), state);
+        state.markVisited(i);
+        addUnscheduledToLatestSorting(stateAfter, state);
 
         // Now predecessors and inputs are scheduled => we can add this node.
-        if (!sortedInstructions.contains(i)) {
-            sortedInstructions.add(i);
+        if (!state.containsInstruction(i)) {
+            state.addInstruction(i);
         }
 
-        if (i instanceof FloatingReadNode) {
-            reads.remove(i);
+        if (state.readsSize() != 0 && i instanceof FloatingReadNode) {
+            state.removeRead(i);
         }
     }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Tue Apr 29 12:43:27 2014 -0700
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
 import com.oracle.graal.phases.schedule.*;
@@ -164,7 +165,8 @@
                         if (pendingStateAfter != null && node instanceof FixedNode) {
                             pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
                                 public void apply(Node usage, Node nonVirtualNode) {
-                                    assert currentState.isMarked(nonVirtualNode) : nonVirtualNode + " not available at virtualstate " + usage + " before " + node + " in block " + block + " \n" + list;
+                                    assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode : nonVirtualNode + " not available at virtualstate " + usage +
+                                                    " before " + node + " in block " + block + " \n" + list;
                                 }
                             });
                             pendingStateAfter = null;
@@ -199,7 +201,7 @@
                                             assert currentState.isMarked(nonVirtual) : nonVirtual + " not available at " + node + " in block " + block + "\n" + list;
                                         });
                                     } else {
-                                        assert currentState.isMarked(input) : input + " not available at " + node + " in block " + block + "\n" + list;
+                                        assert currentState.isMarked(input) || input instanceof VirtualObjectNode : input + " not available at " + node + " in block " + block + "\n" + list;
                                     }
                                 }
                             }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/Providers.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/Providers.java	Tue Apr 29 12:43:27 2014 -0700
@@ -31,7 +31,7 @@
 /**
  * A set of providers, some of which may not be present (i.e., null).
  */
-public class Providers implements LIRProviders {
+public class Providers implements CodeGenProviders {
 
     private final MetaAccessProvider metaAccess;
     private final CodeCacheProvider codeCache;
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,10 +24,11 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
@@ -37,7 +38,7 @@
 @ServiceProvider(ReplacementsProvider.class)
 public class AMD64Substitutions implements ReplacementsProvider {
 
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target) {
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         if (Intrinsify.getValue()) {
             replacements.registerSubstitutions(ArraysSubstitutions.class);
             replacements.registerSubstitutions(StringSubstitutions.class);
--- a/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -28,6 +28,7 @@
 import com.oracle.graal.compiler.hsail.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,10 +22,11 @@
  */
 package com.oracle.graal.replacements.test;
 
+import org.junit.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of checkcast, allowing profiling information to be manually specified.
@@ -41,7 +42,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         test("asNumber", profile(), 111);
         test("asNumber", profile(Integer.class), 111);
@@ -51,7 +52,7 @@
         test("asNumberExt", profile(Long.class, Short.class), 111);
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("asString", profile(), "111");
         test("asString", profile(String.class), "111");
@@ -67,27 +68,27 @@
         test("asStringExt", profile(String.class), "111");
     }
 
-    @LongTest
+    @Test
     public void test3() {
         test("asNumber", profile(), "111");
     }
 
-    @LongTest
+    @Test
     public void test4() {
         test("asString", profile(String.class), 111);
     }
 
-    @LongTest
+    @Test
     public void test5() {
         test("asNumberExt", profile(), "111");
     }
 
-    @LongTest
+    @Test
     public void test6() {
         test("asStringExt", profile(String.class), 111);
     }
 
-    @LongTest
+    @Test
     public void test7() {
         Throwable throwable = new Exception();
         test("asThrowable", profile(), throwable);
@@ -95,12 +96,12 @@
         test("asThrowable", profile(Exception.class, Error.class), throwable);
     }
 
-    @LongTest
+    @Test
     public void test8() {
         test("arrayStore", new Object[100], "111");
     }
 
-    @LongTest
+    @Test
     public void test801() {
         test("arrayFill", new Object[100], "111");
     }
@@ -197,7 +198,7 @@
         return (Cloneable) o;
     }
 
-    @LongTest
+    @Test
     public void test9() {
         Object o = new Depth13();
         test("asDepth12", profile(), o);
@@ -205,7 +206,7 @@
         test("asDepth12", profile(Depth13.class, Depth14.class), o);
     }
 
-    @LongTest
+    @Test
     public void test10() {
         Object o = new Depth13[3][];
         test("asDepth12Arr", o);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.replacements.test;
 
+import org.junit.*;
+
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests for {@link InstanceOfDynamicNode}.
@@ -35,7 +36,7 @@
         return value;
     }
 
-    @LongTest
+    @Test
     public void test100() {
         final Object nul = null;
         test("isStringDynamic", nul);
@@ -43,7 +44,7 @@
         test("isStringDynamic", Object.class);
     }
 
-    @LongTest
+    @Test
     public void test101() {
         final Object nul = null;
         test("isStringIntDynamic", nul);
@@ -51,7 +52,7 @@
         test("isStringIntDynamic", Object.class);
     }
 
-    @LongTest
+    @Test
     public void test103() {
         test("isInstanceDynamic", String.class, null);
         test("isInstanceDynamic", String.class, "object");
@@ -61,7 +62,7 @@
         test("isInstanceDynamic", int.class, Object.class);
     }
 
-    @LongTest
+    @Test
     public void test104() {
         test("isInstanceIntDynamic", String.class, null);
         test("isInstanceIntDynamic", String.class, "object");
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,6 +24,8 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.api.code.CompilationResult.Call;
 import com.oracle.graal.api.code.CompilationResult.Mark;
 import com.oracle.graal.api.code.CompilationResult.Site;
@@ -34,7 +36,6 @@
 import com.oracle.graal.replacements.test.CheckCastTest.Depth12;
 import com.oracle.graal.replacements.test.CheckCastTest.Depth13;
 import com.oracle.graal.replacements.test.CheckCastTest.Depth14;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of instanceof, allowing profiling information to be manually specified.
@@ -54,7 +55,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         test("isString", profile(), "object");
         test("isString", profile(String.class), "object");
@@ -63,7 +64,7 @@
         test("isString", profile(String.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("isStringInt", profile(), "object");
         test("isStringInt", profile(String.class), "object");
@@ -72,7 +73,7 @@
         test("isStringInt", profile(String.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test201() {
         test("isStringIntComplex", profile(), "object");
         test("isStringIntComplex", profile(String.class), "object");
@@ -81,7 +82,7 @@
         test("isStringIntComplex", profile(String.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test3() {
         Throwable throwable = new Exception();
         test("isThrowable", profile(), throwable);
@@ -93,7 +94,7 @@
         test("isThrowable", profile(Exception.class, Error.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test301() {
         onlyFirstIsException(new Exception(), new Error());
         test("onlyFirstIsException", profile(), new Exception(), new Error());
@@ -102,7 +103,7 @@
         test("onlyFirstIsException", profile(), new Error(), new Error());
     }
 
-    @LongTest
+    @Test
     public void test4() {
         Throwable throwable = new Exception();
         test("isThrowableInt", profile(), throwable);
@@ -114,7 +115,7 @@
         test("isThrowableInt", profile(Exception.class, Error.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test5() {
         Map<?, ?> map = new HashMap<>();
         test("isMap", profile(), map);
@@ -127,7 +128,7 @@
         test("isMap", profile(String.class, HashMap.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test6() {
         Map<?, ?> map = new HashMap<>();
         test("isMapInt", profile(), map);
@@ -139,7 +140,7 @@
         test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test7() {
         Object o = new Depth13();
         test("isDepth12", profile(), o);
@@ -153,7 +154,7 @@
         test("isDepth12", profile(String.class, HashMap.class), o);
     }
 
-    @LongTest
+    @Test
     public void test8() {
         Object o = new Depth13();
         test("isDepth12Int", profile(), o);
@@ -259,7 +260,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test9() {
         MyCall callAt63 = new MyCall(63);
         MyMark markAt63 = new MyMark(63);
@@ -276,11 +277,10 @@
         return s1.offset - s2.offset;
     }
 
-    @LongTest
+    @Test
     public void test10() {
-        Mark[] noMarks = {};
         Call callAt63 = new Call(null, 63, 5, true, null);
-        Mark markAt63 = new Mark(63, "1", noMarks);
+        Mark markAt63 = new Mark(63, "1");
         test("compareSites", callAt63, callAt63);
         test("compareSites", callAt63, markAt63);
         test("compareSites", markAt63, callAt63);
@@ -301,7 +301,7 @@
      * The test exists in this source file as the transformation was originally motivated by the
      * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}.
      */
-    @LongTest
+    @Test
     public void testRemoveIntermediateMaterialization() {
         List<String> list = Arrays.asList("1", "2", "3", "4");
         test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no");
@@ -356,7 +356,7 @@
         return o instanceof D[];
     }
 
-    @LongTest
+    @Test
     public void testArray() {
         Object aArray = new A[10];
         test("isArrayOfA", aArray);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -25,7 +25,6 @@
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of {@code [A]NEWARRAY}.
@@ -58,7 +57,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) {
             test("new" + type + "Array7");
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,7 +27,6 @@
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of {@code NEW}.
@@ -57,12 +56,12 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         test("newObject");
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("newObjectTwice");
     }
@@ -71,37 +70,37 @@
         return new Object();
     }
 
-    @LongTest
+    @Test
     public void test3() {
         test("newObjectLoop", 100);
     }
 
-    @LongTest
+    @Test
     public void test4() {
         test("newBigObject");
     }
 
-    @LongTest
+    @Test
     public void test5() {
         test("newSomeObject");
     }
 
-    @LongTest
+    @Test
     public void test6() {
         test("newEmptyString");
     }
 
-    @LongTest
+    @Test
     public void test7() {
         test("newString", "value");
     }
 
-    @LongTest
+    @Test
     public void test8() {
         test("newHashMap", 31);
     }
 
-    @LongTest
+    @Test
     public void test9() {
         test("newRegression", true);
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -25,12 +25,13 @@
 import java.lang.reflect.*;
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the lowering of the MULTIANEWARRAY instruction.
@@ -86,7 +87,7 @@
     Class<?> bottomClass;
     int[] dimensions;
 
-    @LongTest
+    @Test
     public void test1() {
         for (Class<?> clazz : new Class[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) {
             bottomClass = clazz;
@@ -117,7 +118,7 @@
         return new Object[10][9][8];
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("newMultiArrayException");
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.replacements.test;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.replacements.UnsafeSubstitutions.*;
 
 import java.lang.reflect.*;
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,6 +24,8 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
@@ -31,7 +33,6 @@
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
-import com.oracle.graal.test.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -53,7 +54,7 @@
         return installer.makeGraph(resolvedMethod, null, resolvedMethod, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
-    @LongTest
+    @Test
     public void construction() {
         long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L,
                         Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L};
@@ -65,7 +66,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void testArithmetic() {
         long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L,
                         Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L};
@@ -102,7 +103,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void testCompare() {
         long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE};
         for (long word1 : words) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Tue Apr 29 12:43:27 2014 -0700
@@ -25,7 +25,6 @@
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -57,7 +56,7 @@
 
         @Override
         public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) {
-            if (Modifier.isNative(method.getModifiers())) {
+            if (method.isNative()) {
                 return false;
             }
             if (method.getAnnotation(Fold.class) != null) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -35,7 +36,7 @@
 @ServiceProvider(ReplacementsProvider.class)
 public class GraalMethodSubstitutions implements ReplacementsProvider {
 
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         for (Class<?> clazz : BoxingSubstitutions.getClasses()) {
             replacements.registerSubstitutions(clazz);
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Tue Apr 29 12:43:27 2014 -0700
@@ -125,7 +125,7 @@
      * arguments.
      */
     public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
-        assert Modifier.isStatic(method.getModifiers()) == (invokeKind == InvokeKind.Static);
+        assert method.isStatic() == (invokeKind == InvokeKind.Static);
         Signature signature = method.getSignature();
         JavaType returnType = signature.getReturnType(null);
         assert checkArgs(method, args);
@@ -157,7 +157,7 @@
      */
     public boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) {
         Signature signature = method.getSignature();
-        boolean isStatic = Modifier.isStatic(method.getModifiers());
+        boolean isStatic = method.isStatic();
         if (signature.getParameterCount(!isStatic) != args.length) {
             throw new AssertionError(graph + ": wrong number of arguments to " + method);
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -81,7 +81,7 @@
         NodeIntrinsic intrinsic = getIntrinsic(target);
         if (intrinsic != null) {
             assert target.getAnnotation(Fold.class) == null;
-            assert Modifier.isStatic(target.getModifiers()) : "node intrinsic must be static: " + target;
+            assert target.isStatic() : "node intrinsic must be static: " + target;
 
             ResolvedJavaType[] parameterTypes = resolveJavaTypes(signatureToTypes(target), declaringClass);
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Apr 29 12:43:27 2014 -0700
@@ -96,7 +96,7 @@
     @Override
     public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry) {
         assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName();
-        assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : "Snippet must not be abstract or native";
+        assert !method.isAbstract() && !method.isNative() : "Snippet must not be abstract or native";
 
         StructuredGraph graph = UseSnippetGraphCache ? graphs.get(method) : null;
         if (graph == null) {
@@ -532,7 +532,7 @@
     }
 
     private static boolean isInlinable(final ResolvedJavaMethod method) {
-        return !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers());
+        return !method.isAbstract() && !method.isNative();
     }
 
     private static String originalName(Method substituteMethod, String methodSubstitution) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,8 +23,6 @@
 package com.oracle.graal.replacements;
 
 import java.lang.annotation.*;
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.replacements.nodes.*;
@@ -89,7 +87,7 @@
 
         @Override
         public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) {
-            if (Modifier.isNative(method.getModifiers())) {
+            if (method.isNative()) {
                 return false;
             }
             if (method.getAnnotation(Fold.class) != null) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,7 +24,7 @@
 
 //JaCoCo Exclude
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.io.*;
 import java.util.*;
@@ -32,15 +32,13 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.replacements.Snippet.Fold;
-import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.word.*;
 
 /**
  * A counter that can be safely {@linkplain #inc() incremented} from within a snippet for gathering
  * snippet specific metrics.
  */
 public class SnippetCounter implements Comparable<SnippetCounter> {
-    private static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter");
-
     /**
      * A group of related counters.
      */
@@ -107,7 +105,7 @@
 
     /**
      * Creates a counter.
-     * 
+     *
      * @param group the group to which the counter belongs. If this is null, the newly created
      *            counter is disabled and {@linkplain #inc() incrementing} is a no-op.
      * @param name the name of the counter
@@ -130,12 +128,20 @@
     }
 
     /**
+     * We do not want to use the {@link LocationIdentity} of the {@link #value} field, so that the
+     * usage in snippets is always possible. If a method accesses the counter via the field and the
+     * snippet, the result might not be correct though.
+     */
+    protected static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter");
+
+    /**
      * Increments the value of this counter. This method can be safely used in a snippet if it is
      * invoked on a compile-time constant {@link SnippetCounter} object.
      */
     public void inc() {
         if (group != null) {
-            DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1, SNIPPET_COUNTER_LOCATION);
+            long loadedValue = ObjectAccess.readLong(this, countOffset(), SNIPPET_COUNTER_LOCATION);
+            ObjectAccess.writeLong(this, countOffset(), loadedValue + 1, SNIPPET_COUNTER_LOCATION);
         }
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,9 +23,11 @@
 package com.oracle.graal.replacements;
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
+
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.debug.Debug.*;
 import static java.util.FormattableFlags.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -40,8 +42,8 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
@@ -102,7 +104,7 @@
             this.method = method;
             instantiationCounter = Debug.metric("SnippetInstantiationCount[%s]", method);
             instantiationTimer = Debug.timer("SnippetInstantiationTime[%s]", method);
-            assert Modifier.isStatic(method.getModifiers()) : "snippet method must be static: " + MetaUtil.format("%H.%n", method);
+            assert method.isStatic() : "snippet method must be static: " + MetaUtil.format("%H.%n", method);
             int count = method.getSignature().getParameterCount(false);
             constantParameters = new boolean[count];
             varargsParameters = new boolean[count];
@@ -965,7 +967,15 @@
          * 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";
+            LocationIdentity locationIdentity = frn.location().getLocationIdentity();
+            if (SnippetCounters.getValue()) {
+                // accesses to snippet counters are artificially introduced and violate the memory
+                // semantics.
+                if (locationIdentity == SnippetCounter.SNIPPET_COUNTER_LOCATION) {
+                    continue;
+                }
+            }
+            assert !kills.contains(locationIdentity) : frn + " reads from location \"" + locationIdentity + "\" but " + replacee + " does not kill this location";
         }
         return true;
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.lang.reflect.*;
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,8 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
@@ -36,7 +34,7 @@
 /**
  * Compares two arrays with the same length.
  */
-public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable, Virtualizable {
+public class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable {
 
     /** {@link Kind} of the arrays to compare. */
     private final Kind kind;
@@ -131,7 +129,7 @@
     public static native boolean equals(double[] array1, double[] array2, int length);
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitArrayEquals(kind, result, gen.operand(array1), gen.operand(array2), gen.operand(length));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,15 +24,14 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class BitCountNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitCountNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -65,7 +64,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitBitCount(result, gen.operand(value));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,15 +24,14 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class BitScanForwardNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitScanForwardNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -72,7 +71,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitBitScanForward(result, gen.operand(value));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,15 +24,14 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class BitScanReverseNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitScanReverseNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -79,7 +78,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.getLIRGeneratorTool().emitBitScanReverse(result, gen.operand(value));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.replacements.nodes;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.replacements.nodes;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.replacements.nodes;
 
-import static java.lang.reflect.Modifier.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
@@ -137,7 +135,7 @@
         if (replacementGraph != null) {
             // Pull out the receiver null check so that a replaced
             // receiver can be lowered if necessary
-            if (!isStatic(targetMethod.getModifiers())) {
+            if (!targetMethod.isStatic()) {
                 ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
                 if (nonNullReceiver instanceof Lowerable) {
                     ((Lowerable) nonNullReceiver).lower(tool);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -27,6 +27,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,15 +24,14 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class ReverseBytesNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class ReverseBytesNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -66,9 +65,9 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(value.getKind());
-        gen.getLIRGenerator().emitByteSwap(result, gen.operand(value));
+        gen.getLIRGeneratorTool().emitByteSwap(result, gen.operand(value));
         gen.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Tue Apr 29 12:43:27 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,28 +35,28 @@
  */
 public class SPARC extends Architecture {
 
-    // @formatter:off
-
     public static final RegisterCategory CPU = new RegisterCategory("CPU");
     public static final RegisterCategory FPU = new RegisterCategory("FPU");
 
     // General purpose registers
-    public static final Register r0  = new Register(0, 0, "g0", CPU);
-    public static final Register r1  = new Register(1, 1, "g1", CPU);
-    public static final Register r2  = new Register(2, 2, "g2", CPU);
-    public static final Register r3  = new Register(3, 3, "g3", CPU);
-    public static final Register r4  = new Register(4, 4, "g4", CPU);
-    public static final Register r5  = new Register(5, 5, "g5", CPU);
-    public static final Register r6  = new Register(6, 6, "g6", CPU);
-    public static final Register r7  = new Register(7, 7, "g7", CPU);
-    public static final Register r8  = new Register(8, 8, "o0", CPU);
-    public static final Register r9  = new Register(9, 9, "o1", CPU);
+    public static final Register r0 = new Register(0, 0, "g0", CPU);
+    public static final Register r1 = new Register(1, 1, "g1", CPU);
+    public static final Register r2 = new Register(2, 2, "g2", CPU);
+    public static final Register r3 = new Register(3, 3, "g3", CPU);
+    public static final Register r4 = new Register(4, 4, "g4", CPU);
+    public static final Register r5 = new Register(5, 5, "g5", CPU);
+    public static final Register r6 = new Register(6, 6, "g6", CPU);
+    public static final Register r7 = new Register(7, 7, "g7", CPU);
+
+    public static final Register r8 = new Register(8, 8, "o0", CPU);
+    public static final Register r9 = new Register(9, 9, "o1", CPU);
     public static final Register r10 = new Register(10, 10, "o2", CPU);
     public static final Register r11 = new Register(11, 11, "o3", CPU);
     public static final Register r12 = new Register(12, 12, "o4", CPU);
     public static final Register r13 = new Register(13, 13, "o5", CPU);
     public static final Register r14 = new Register(14, 14, "o6", CPU);
     public static final Register r15 = new Register(15, 15, "o7", CPU);
+
     public static final Register r16 = new Register(16, 16, "l0", CPU);
     public static final Register r17 = new Register(17, 17, "l1", CPU);
     public static final Register r18 = new Register(18, 18, "l2", CPU);
@@ -65,6 +65,7 @@
     public static final Register r21 = new Register(21, 21, "l5", CPU);
     public static final Register r22 = new Register(22, 22, "l6", CPU);
     public static final Register r23 = new Register(23, 23, "l7", CPU);
+
     public static final Register r24 = new Register(24, 24, "i0", CPU);
     public static final Register r25 = new Register(25, 25, "i1", CPU);
     public static final Register r26 = new Register(26, 26, "i2", CPU);
@@ -113,12 +114,14 @@
     public static final Register sp = o6;
     public static final Register fp = i6;
 
+    // @formatter:off
     public static final Register[] cpuRegisters = {
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
         r8,  r9,  r10, r11, r12, r13, r14, r15,
         r16, r17, r18, r19, r20, r21, r22, r23,
         r24, r25, r26, r27, r28, r29, r30, r31
     };
+    // @formatter:on
 
     // Floating point registers
     public static final Register f0 = new Register(32, 0, "f0", FPU);
@@ -130,6 +133,43 @@
     public static final Register f6 = new Register(38, 6, "f6", FPU);
     public static final Register f7 = new Register(39, 7, "f7", FPU);
 
+    public static final Register f8 = new Register(40, 8, "f8", FPU);
+    public static final Register f9 = new Register(41, 9, "f9", FPU);
+    public static final Register f10 = new Register(42, 10, "f10", FPU);
+    public static final Register f11 = new Register(43, 11, "f11", FPU);
+    public static final Register f12 = new Register(44, 12, "f12", FPU);
+    public static final Register f13 = new Register(45, 13, "f13", FPU);
+    public static final Register f14 = new Register(46, 14, "f14", FPU);
+    public static final Register f15 = new Register(47, 15, "f15", FPU);
+
+    public static final Register f16 = new Register(48, 16, "f16", FPU);
+    public static final Register f17 = new Register(49, 17, "f17", FPU);
+    public static final Register f18 = new Register(50, 18, "f18", FPU);
+    public static final Register f19 = new Register(51, 19, "f19", FPU);
+    public static final Register f20 = new Register(52, 20, "f20", FPU);
+    public static final Register f21 = new Register(53, 21, "f21", FPU);
+    public static final Register f22 = new Register(54, 22, "f22", FPU);
+    public static final Register f23 = new Register(55, 23, "f23", FPU);
+
+    public static final Register f24 = new Register(56, 24, "f24", FPU);
+    public static final Register f25 = new Register(57, 25, "f25", FPU);
+    public static final Register f26 = new Register(58, 26, "f26", FPU);
+    public static final Register f27 = new Register(59, 27, "f27", FPU);
+    public static final Register f28 = new Register(60, 28, "f28", FPU);
+    public static final Register f29 = new Register(61, 29, "f29", FPU);
+    public static final Register f30 = new Register(62, 30, "f30", FPU);
+    public static final Register f31 = new Register(63, 31, "f31", FPU);
+
+    // @formatter:off
+    public static final Register[] fpuRegisters = {
+        f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
+        f8,  f9,  f10, f11, f12, f13, f14, f15,
+        f16, f17, f18, f19, f20, f21, f22, f23,
+        f24, f25, f26, f27, f28, f29, f30, f31
+    };
+    // @formatter:on
+
+    // @formatter:off
     public static final Register[] allRegisters = {
         // CPU
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
@@ -138,9 +178,16 @@
         r24, r25, r26, r27, r28, r29, r30, r31,
         // FPU
         f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
+        f8,  f9,  f10, f11, f12, f13, f14, f15,
+        f16, f17, f18, f19, f20, f21, f22, f23,
+        f24, f25, f26, f27, f28, f29, f30, f31
     };
+    // @formatter:on
 
-    // @formatter:on
+    /**
+     * Stack bias for stack and frame pointer loads.
+     */
+    public static final int STACK_BIAS = 0x7ff;
 
     public SPARC() {
         super("SPARC", 8, ByteOrder.BIG_ENDIAN, false, allRegisters, LOAD_STORE | STORE_STORE, 1, r31.encoding + 1, 8);
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalLongUnitTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +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.test;
-
-import java.util.*;
-
-import org.junit.*;
-import org.junit.runners.*;
-import org.junit.runners.model.*;
-
-public class GraalLongUnitTest extends BlockJUnit4ClassRunner {
-
-    public GraalLongUnitTest(Class<?> klass) throws InitializationError {
-        super(klass);
-    }
-
-    @Override
-    protected List<FrameworkMethod> computeTestMethods() {
-        List<FrameworkMethod> methods = new ArrayList<>(5);
-        methods.addAll(getTestClass().getAnnotatedMethods(Test.class));
-        methods.addAll(getTestClass().getAnnotatedMethods(LongTest.class));
-        return methods;
-    }
-}
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -26,14 +26,12 @@
 import java.util.*;
 
 import org.junit.*;
-import org.junit.runner.*;
 
 /**
  * Base class for Graal tests.
  * <p>
  * This contains common utility methods that are used in multiple test projects.
  */
-@RunWith(GraalLongUnitTest.class)
 public class GraalTest {
 
     protected Method getMethod(String methodName) {
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/LongTest.java	Tue Apr 29 12:05:58 2014 -0700
+++ /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.test;
-
-import java.lang.annotation.*;
-
-/* copy of org.junit.Test */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.METHOD})
-public @interface LongTest {
-
-    static final class None extends Throwable {
-
-        private static final long serialVersionUID = 1L;
-
-        private None() {
-        }
-    }
-
-    Class<? extends Throwable> expected() default None.class;
-
-    long timeout() default 0L;
-}
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java	Tue Apr 29 12:43:27 2014 -0700
@@ -88,13 +88,12 @@
 
     public abstract CallTarget getTargetCallTarget();
 
-    public DirectCallNode getCallNode() {
+    public Node getCallNode() {
         Object receiver = stackFrame.getLocal(getNotifyIndex());
-        if (receiver instanceof DirectCallNode) {
-            return (DirectCallNode) receiver;
-        } else {
-            return null;
+        if (receiver instanceof DirectCallNode || receiver instanceof IndirectCallNode) {
+            return (Node) receiver;
         }
+        return null;
     }
 
     /**
@@ -146,10 +145,9 @@
     }
 
     /**
-     * This class represents a frame that is taken from the
-     * {@link RootCallTarget#callProxy(VirtualFrame)} method.
+     * This class represents a frame that is taken from the {@link OptimizedCallTarget#callProxy}
+     * method.
      */
-    @SuppressWarnings("javadoc")
     public static final class CallTargetFrame extends HotSpotFrameInstance {
         public static final Method METHOD;
         static {
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java	Tue Apr 29 12:43:27 2014 -0700
@@ -28,7 +28,6 @@
 import com.oracle.graal.api.code.CompilationResult.Mark;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.hotspot.meta.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Tue Apr 29 12:43:27 2014 -0700
@@ -247,16 +247,16 @@
         logInliningDecision(result);
     }
 
-    private void performInlining(TruffleInliningResult result) {
-        if (inliningPerformed) {
+    private static void performInlining(TruffleInliningResult result) {
+        if (result.getCallTarget().inliningPerformed) {
             return;
         }
-        inliningPerformed = true;
+        result.getCallTarget().inliningPerformed = true;
         for (TruffleInliningProfile profile : result) {
             profile.getCallNode().inline();
             TruffleInliningResult recursiveResult = profile.getRecursiveResult();
             if (recursiveResult != null) {
-                recursiveResult.getCallTarget().performInlining(recursiveResult);
+                performInlining(recursiveResult);
             }
         }
     }
@@ -275,7 +275,7 @@
         if (profiledReturnTypeAssumption == null) {
             if (TruffleReturnTypeSpeculation.getValue()) {
                 CompilerDirectives.transferToInterpreter();
-                profiledReturnType = result.getClass();
+                profiledReturnType = (result == null ? null : result.getClass());
                 profiledReturnTypeAssumption = Truffle.getRuntime().createAssumption("Profiled Return Type");
             }
         } else if (profiledReturnType != null) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Tue Apr 29 12:43:27 2014 -0700
@@ -171,7 +171,7 @@
                     }
                     if (node instanceof DirectCallNode) {
                         DirectCallNode callNode = (DirectCallNode) node;
-                        if (callNode.isInliningForced()) {
+                        if (callNode.isInlined()) {
                             callNode.getCurrentRootNode().accept(this);
                         }
                     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Apr 29 12:43:27 2014 -0700
@@ -25,7 +25,6 @@
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -87,7 +86,7 @@
             constantReceivers = new HashSet<>();
         }
 
-        final StructuredGraph graph = truffleCache.createRootGraph();
+        final StructuredGraph graph = truffleCache.createRootGraph(callTarget.toString());
         assert graph != null : "no graph for root method";
 
         try (Scope s = Debug.scope("CreateGraph", graph); Indent indent = Debug.logAndIndent("createGraph %s", graph.method())) {
@@ -202,7 +201,7 @@
                         }
 
                         StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
-                        if (inlineGraph == null && !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().canBeInlined()) {
+                        if (inlineGraph == null && !methodCallTargetNode.targetMethod().isNative() && methodCallTargetNode.targetMethod().canBeInlined()) {
                             inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext, false);
                         }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.truffle;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodes.*;
@@ -47,7 +45,7 @@
         if (node instanceof LoadFieldNode) {
             LoadFieldNode loadFieldNode = (LoadFieldNode) node;
             if (!loadFieldNode.isStatic() && loadFieldNode.object().isConstant() && !loadFieldNode.object().isNullConstant()) {
-                if (Modifier.isFinal(loadFieldNode.field().getModifiers()) || (loadFieldNode.getKind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) ||
+                if (loadFieldNode.field().isFinal() || (loadFieldNode.getKind() == 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);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Tue Apr 29 12:43:27 2014 -0700
@@ -33,7 +33,7 @@
     /**
      * Creates the graph for the root method, i.e. {@link OptimizedCallTarget#callBoundary}.
      */
-    StructuredGraph createRootGraph();
+    StructuredGraph createRootGraph(String name);
 
     /**
      * Returns a cached graph for a method with given arguments.
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Tue Apr 29 12:43:27 2014 -0700
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 import java.util.Map.Entry;
 
@@ -81,8 +80,8 @@
         }
     }
 
-    public StructuredGraph createRootGraph() {
-        StructuredGraph graph = new StructuredGraph(callBoundaryMethod);
+    public StructuredGraph createRootGraph(String name) {
+        StructuredGraph graph = new StructuredGraph(name, callBoundaryMethod);
         new GraphBuilderPhase.Instance(providers.getMetaAccess(), configForRootGraph, TruffleCompilerImpl.Optimizations).apply(graph);
         return graph;
     }
@@ -265,7 +264,7 @@
 
     private boolean shouldInline(final MethodCallTargetNode methodCallTargetNode) {
         boolean result = (methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) && methodCallTargetNode.targetMethod().canBeInlined() &&
-                        !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null &&
+                        !methodCallTargetNode.targetMethod().isNative() && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null &&
                         methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null &&
                         !methodCallTargetNode.targetMethod().getDeclaringClass().equals(stringBuilderClass);
         return result;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Apr 29 12:43:27 2014 -0700
@@ -63,7 +63,7 @@
     private final RuntimeProvider runtime;
     private final TruffleCache truffleCache;
 
-    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class};
+    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class, IllegalArgumentException.class};
 
     public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
                     OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Tue Apr 29 12:43:27 2014 -0700
@@ -54,7 +54,7 @@
     @Option(help = "Enable automatic inlining of call targets")
     public static final OptionValue<Boolean> TruffleFunctionInlining = new OptionValue<>(true);
     @Option(help = "Maximum number of Graal IR nodes during partial evaluation")
-    public static final OptionValue<Integer> TruffleGraphMaxNodes = new OptionValue<>(45000);
+    public static final OptionValue<Integer> TruffleGraphMaxNodes = new OptionValue<>(200000);
     @Option(help = "Stop inlining if caller's cumulative tree size would exceed this limit")
     public static final OptionValue<Integer> TruffleInliningMaxCallerSize = new OptionValue<>(2250);
     @Option(help = "Skip inlining candidate if its tree size exceeds this limit")
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,7 +23,6 @@
 package com.oracle.graal.truffle;
 
 import java.io.*;
-import java.lang.reflect.*;
 import java.util.*;
 import java.util.Map.Entry;
 
@@ -51,7 +50,7 @@
         int sourceMethodBci = callTarget.invoke().bci();
         ResolvedJavaMethod targetMethod = callTarget.targetMethod();
         ResolvedJavaType targetReceiverType = null;
-        if (!Modifier.isStatic(sourceMethod.getModifiers()) && callTarget.receiver().isConstant()) {
+        if (!sourceMethod.isStatic() && callTarget.receiver().isConstant()) {
             targetReceiverType = providers.getMetaAccess().lookupJavaType(callTarget.arguments().first().asConstant());
         }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Tue Apr 29 12:43:27 2014 -0700
@@ -117,7 +117,7 @@
     }
 
     private static double calculateFrequency(OptimizedCallTarget target, OptimizedDirectCallNode ocn) {
-        return (double) Math.max(1, target.getCompilationProfile().getCallCount()) / Math.max(1, ocn.getCallCount());
+        return (double) Math.max(1, ocn.getCallCount()) / (double) Math.max(1, target.getCompilationProfile().getCallCount());
     }
 
     private final static class ProfileScoreComparator implements Comparator<TruffleInliningProfile> {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -23,11 +23,10 @@
 package com.oracle.graal.truffle.nodes.frame;
 
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class ForceMaterializeNode extends FixedWithNextNode implements LIRGenLowerable {
+public class ForceMaterializeNode extends FixedWithNextNode implements LIRLowerable {
 
     @Input private ValueNode object;
 
@@ -36,7 +35,7 @@
         this.object = object;
     }
 
-    public void generate(NodeLIRBuilder generator) {
+    public void generate(NodeLIRBuilderTool generator) {
         // nothing to do
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -31,6 +31,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.cfs.IterativeFlowSensitiveReductionPhase;
 import com.oracle.graal.phases.tiers.*;
 
 public class IterativeInliningPhase extends AbstractInliningPhase {
@@ -70,9 +71,14 @@
 
                 new DeadCodeEliminationPhase().apply(graph);
 
-                if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
+                boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue();
+                if (reduceOrEliminate && OptCanonicalizer.getValue()) {
                     canonicalizer.apply(graph, context);
-                    new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context);
+                    if (FlowSensitiveReduction.getValue()) {
+                        new IterativeFlowSensitiveReductionPhase(canonicalizer).apply(graph, context);
+                    } else {
+                        new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context);
+                    }
                 }
                 if (!progress) {
                     break;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Tue Apr 29 12:43:27 2014 -0700
@@ -34,10 +34,10 @@
 
     static class ReadCacheEntry {
 
-        public final ResolvedJavaField identity;
+        public final LocationIdentity identity;
         public final ValueNode object;
 
-        public ReadCacheEntry(ResolvedJavaField identity, ValueNode object) {
+        public ReadCacheEntry(LocationIdentity identity, ValueNode object) {
             this.identity = identity;
             this.object = object;
         }
@@ -95,7 +95,7 @@
         return super.equivalentTo(other);
     }
 
-    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value, PartialEscapeClosure<?> closure) {
+    public void addReadCache(ValueNode object, LocationIdentity identity, ValueNode value, PartialEscapeClosure<?> closure) {
         ValueNode cacheObject;
         ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
@@ -107,7 +107,7 @@
         readCache.put(new ReadCacheEntry(identity, cacheObject), value);
     }
 
-    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity, PartialEscapeClosure<?> closure) {
+    public ValueNode getReadCache(ValueNode object, LocationIdentity identity, PartialEscapeClosure<?> closure) {
         ValueNode cacheObject;
         ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Tue Apr 29 12:43:27 2014 -0700
@@ -83,6 +83,17 @@
                 } else {
                     processIdentity(state, ANY_LOCATION);
                 }
+            } else if (node instanceof ArrayLengthNode) {
+                ArrayLengthNode length = (ArrayLengthNode) node;
+                ValueNode array = GraphUtil.unproxify(length.array());
+                ValueNode cachedValue = state.getReadCache(array, ARRAY_LENGTH_LOCATION, this);
+                if (cachedValue != null) {
+                    effects.replaceAtUsages(length, cachedValue);
+                    addScalarAlias(length, cachedValue);
+                    deleted = true;
+                } else {
+                    state.addReadCache(array, ARRAY_LENGTH_LOCATION, length, this);
+                }
             } else if (node instanceof MemoryCheckpoint.Single) {
                 METRIC_MEMORYCHECKPOINT.increment();
                 LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
@@ -183,7 +194,7 @@
             }
         }
 
-        private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List<PEReadEliminationBlockState> states) {
+        private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, List<PEReadEliminationBlockState> states) {
             ValueNode[] values = new ValueNode[phi.valueCount()];
             for (int i = 0; i < phi.valueCount(); i++) {
                 ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity, PEReadEliminationClosure.this);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Apr 29 12:43:27 2014 -0700
@@ -579,15 +579,29 @@
                 } else {
                     // all inputs are virtual: check if they're compatible and without identity
                     boolean compatible = true;
+                    boolean hasIdentity = false;
                     ObjectState firstObj = objStates[0];
                     for (int i = 0; i < objStates.length; i++) {
                         ObjectState obj = objStates[i];
-                        boolean hasIdentity = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual);
-                        if (hasIdentity || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) {
+                        hasIdentity |= obj.virtual.hasIdentity();
+                        boolean identitySurvives = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual);
+                        if (identitySurvives || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) {
                             compatible = false;
                             break;
                         }
                     }
+                    if (compatible && hasIdentity) {
+                        // we still need to check whether this value is referenced by any other phi
+                        outer: for (PhiNode otherPhi : merge.phis().filter(otherPhi -> otherPhi != phi)) {
+                            for (int i = 0; i < objStates.length; i++) {
+                                ObjectState otherPhiValueState = getObjectState(states.get(i), otherPhi.valueAt(i));
+                                if (Arrays.asList(objStates).contains(otherPhiValueState)) {
+                                    compatible = false;
+                                    break outer;
+                                }
+                            }
+                        }
+                    }
 
                     if (compatible) {
                         VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), phi.valueAt(0)).virtual);
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.word;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.lang.annotation.*;
 
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -30,6 +30,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -234,7 +234,7 @@
             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()));
+                Kind writeKind = asKind(targetMethod.getSignature().getParameterType(targetMethod.isStatic() ? 2 : 1, targetMethod.getDeclaringClass()));
                 LocationNode location;
                 if (arguments.size() == 3) {
                     location = makeLocation(graph, arguments.get(1), writeKind, LocationIdentity.ANY_LOCATION);
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Tue Apr 29 12:43:27 2014 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.word.phases;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
@@ -110,7 +108,7 @@
         if (method.getAnnotation(NodeIntrinsic.class) == null) {
             Invoke invoke = (Invoke) callTarget.usages().first();
             NodeInputList<ValueNode> arguments = callTarget.arguments();
-            boolean isStatic = Modifier.isStatic(method.getModifiers());
+            boolean isStatic = method.isStatic();
             int argc = 0;
             if (!isStatic) {
                 ValueNode receiver = arguments.get(argc);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * <h3>Inserting Extra Nodes into the AST Transparently</h3>
+ * 
+ * <p>
+ * The {@link Node} class provides a callback that is invoked whenever a node is adopted in an AST
+ * by insertion or replacement. Node classes can override the {@code onAdopt()} method to run extra
+ * functionality upon adoption.
+ * </p>
+ * 
+ * <p>
+ * This test demonstrates how node instances of a specific class can be automatically wrapped in
+ * extra nodes when they are inserted into the AST.
+ * </p>
+ */
+public class OnAdoptTest {
+
+    static class Root extends RootNode {
+
+        @Child private Base child1;
+        @Child private Base child2;
+
+        public Root(Base child1, Base child2) {
+            super(null);
+            this.child1 = child1;
+            this.child2 = child2;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return child1.executeInt(frame) + child2.executeInt(frame);
+        }
+
+    }
+
+    abstract static class Base extends Node {
+        public abstract int executeInt(VirtualFrame frame);
+    }
+
+    static class Wrapper extends Base {
+
+        @Child private Base wrappee;
+
+        public Wrapper(Base wrappee) {
+            this.wrappee = wrappee;
+        }
+
+        @Override
+        public int executeInt(VirtualFrame frame) {
+            return 1 + wrappee.executeInt(frame);
+        }
+
+    }
+
+    abstract static class GenBase extends Base {
+
+        private final int k;
+
+        public GenBase(int k) {
+            this.k = k;
+        }
+
+        @Override
+        public int executeInt(VirtualFrame frame) {
+            return k;
+        }
+
+    }
+
+    static class Gen extends GenBase {
+        public Gen(int k) {
+            super(k);
+        }
+    }
+
+    static class GenWrapped extends GenBase {
+
+        public GenWrapped(int k) {
+            super(k);
+        }
+
+        @Override
+        protected void onAdopt() {
+            Wrapper w = new Wrapper(this);
+            this.replace(w);
+        }
+
+    }
+
+    @Test
+    public void testOnInsert() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        Base b1 = new Gen(11);
+        Base b2 = new GenWrapped(11);
+        Root r = new Root(b1, b2);
+        CallTarget ct = runtime.createCallTarget(r);
+        Object result = ct.call();
+        Assert.assertEquals(23, result);
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java	Tue Apr 29 12:43:27 2014 -0700
@@ -34,12 +34,21 @@
     /**
      * Returns the name of this resource holding a guest language program. An example would be the
      * name of a guest language source code file.
-     * 
+     *
      * @return the name of the guest language program
      */
     String getName();
 
     /**
+     * Returns a short version of the name of the resource holding a guest language program (as
+     * described in @getName). For example, this could be just the name of the file, rather than a
+     * full path.
+     *
+     * @return the short name of the guest language program
+     */
+    String getShortName();
+
+    /**
      * The normalized, canonical name of the file.
      */
     String getPath();
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Tue Apr 29 12:43:27 2014 -0700
@@ -31,21 +31,21 @@
 
     /**
      * Returns the object representing the source program that contains this section.
-     * 
+     *
      * @return the source object
      */
     Source getSource();
 
     /**
      * Returns 1-based line number of the first character in this source section (inclusive).
-     * 
+     *
      * @return the starting line number
      */
     int getStartLine();
 
     /**
      * Returns the 1-based column number of the first character in this source section (inclusive).
-     * 
+     *
      * @return the starting column number
      */
     int getStartColumn();
@@ -55,7 +55,7 @@
      * <p>
      * The complete text of the source that contains this section can be retrieved via
      * {@link Source#getCode()}.
-     * 
+     *
      * @return the starting character index
      */
     int getCharIndex();
@@ -65,7 +65,7 @@
      * <p>
      * The complete text of the source that contains this section can be retrieved via
      * {@link Source#getCode()}.
-     * 
+     *
      * @return the number of characters in the section
      */
     int getCharLength();
@@ -73,42 +73,54 @@
     /**
      * 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
      */
     String getIdentifier();
 
     /**
      * Returns text of the code represented by this source section.
-     * 
+     *
      * @return the code as a String object
      */
     String getCode();
 
     /**
+     * Returns a short description of the source section, using just the file name, rather than its
+     * full path.
+     *
+     * @return a short description of the source section
+     */
+    String getShortDescription();
+
+    /**
      * Singleton instance with no content.
      */
     SourceSection NULL = new NullSourceSection() {
 
+        @Override
         public Source getSource() {
             return null;
         }
 
+        @Override
         public int getStartLine() {
             return 0;
         }
 
+        @Override
         public int getStartColumn() {
             return 0;
         }
 
+        @Override
         public int getCharIndex() {
             return 0;
         }
@@ -118,18 +130,26 @@
             return 0;
         }
 
+        @Override
         public int getCharEndIndex() {
             return 0;
         }
 
+        @Override
         public String getIdentifier() {
             return null;
         }
 
+        @Override
         public String getCode() {
             return null;
         }
 
+        @Override
+        public String getShortDescription() {
+            return "short";
+        }
+
     };
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java	Tue Apr 29 12:43:27 2014 -0700
@@ -40,9 +40,7 @@
 
     boolean isVirtualFrame();
 
-    DirectCallNode getCallNode();
+    Node getCallNode();
 
     CallTarget getCallTarget();
-
-    CallTarget getTargetCallTarget();
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java	Tue Apr 29 12:43:27 2014 -0700
@@ -53,7 +53,7 @@
      * 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
@@ -102,6 +102,10 @@
         return getSource().getCode().substring(charIndex, charIndex + charLength);
     }
 
+    public final String getShortDescription() {
+        return String.format("%s:%d", source.getShortName(), startLine);
+    }
+
     @Override
     public String toString() {
         return String.format("%s:%d", source.getName(), startLine);
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Tue Apr 29 12:43:27 2014 -0700
@@ -191,8 +191,12 @@
         if (newChild == this) {
             throw new IllegalStateException("The parent of a node can never be the node itself.");
         }
+        boolean isInserted = newChild.parent == null;
         newChild.parent = this;
         newChild.adoptHelper();
+        if (isInserted) {
+            newChild.onAdopt();
+        }
     }
 
     private void adoptHelper() {
@@ -209,8 +213,12 @@
         if (newChild == this) {
             throw new IllegalStateException("The parent of a node can never be the node itself.");
         }
+        boolean isInserted = newChild.parent == null;
         newChild.parent = this;
         newChild.adoptUnadoptedHelper();
+        if (isInserted) {
+            newChild.onAdopt();
+        }
     }
 
     private void adoptUnadoptedHelper() {
@@ -332,7 +340,6 @@
     }
 
     private void traceRewrite(Node newNode, CharSequence reason) {
-
         if (TruffleOptions.TraceRewritesFilterFromCost != null) {
             if (filterByKind(this, TruffleOptions.TraceRewritesFilterFromCost)) {
                 return;
@@ -352,8 +359,21 @@
             return;
         }
 
+        final SourceSection reportedSourceSection = getEncapsulatingSourceSection();
+
         PrintStream out = System.out;
-        out.printf("[truffle]   rewrite %-50s |From %-40s |To %-40s |Reason %s.%n", this.toString(), formatNodeInfo(this), formatNodeInfo(newNode), reason);
+        out.printf("[truffle]   rewrite %-50s |From %-40s |To %-40s |Reason %s%s%n", this.toString(), formatNodeInfo(this), formatNodeInfo(newNode), reason != null && reason.length() > 0 ? reason
+                        : "unknown", reportedSourceSection != null ? " at " + reportedSourceSection.getShortDescription() : "");
+    }
+
+    /**
+     * Subclasses of {@link Node} can implement this method to execute extra functionality when a
+     * node is effectively inserted into the AST. The {@code onAdopt} callback is called after the
+     * node has been effectively inserted, and it is guaranteed to be called only once for any given
+     * node.
+     */
+    protected void onAdopt() {
+        // empty default
     }
 
     private static String formatNodeInfo(Node node) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java	Tue Apr 29 12:43:27 2014 -0700
@@ -70,7 +70,7 @@
     /**
      * Gets the canonical representation of a source file, whose contents will be read lazily and
      * then cached.
-     * 
+     *
      * @param reset forces any existing {@link Source} cache to be cleared, forcing a re-read
      */
     public Source get(String fileName, boolean reset) {
@@ -227,6 +227,11 @@
         }
 
         @Override
+        public String getShortName() {
+            return name;
+        }
+
+        @Override
         public String getCode() {
             return code;
         }
@@ -292,6 +297,11 @@
         }
 
         @Override
+        public String getShortName() {
+            return file.getName();
+        }
+
+        @Override
         public String getCode() {
             if (code == null || timeStamp != file.lastModified()) {
                 try {
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java	Tue Apr 29 12:43:27 2014 -0700
@@ -44,7 +44,7 @@
  * <li>After execution of function {@code f2}: {@code I->D(f1)->D(f2)->U}
  * <li>After execution of function {@code f3}: {@code I->G}
  * </ol>
- * */
+ */
 public abstract class SLAbstractDispatchNode extends Node {
 
     protected static final int INLINE_CACHE_SIZE = 2;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java	Tue Apr 29 12:05:58 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java	Tue Apr 29 12:43:27 2014 -0700
@@ -29,7 +29,7 @@
  * there is always the danger of a spurious {@link NullPointerException}. Representing the guest
  * language {@code null} as a singleton, as in {@link #SINGLETON this class}, is the recommended
  * practice.
- * */
+ */
 public final class SLNull {
 
     /**
--- a/mx.cmd	Tue Apr 29 12:05:58 2014 -0700
+++ b/mx.cmd	Tue Apr 29 12:43:27 2014 -0700
@@ -1,1 +1,1 @@
-python mxtool/mx.py %*
+python %~dp0/mxtool/mx.py %*
--- a/mx/mx_graal.py	Tue Apr 29 12:05:58 2014 -0700
+++ b/mx/mx_graal.py	Tue Apr 29 12:43:27 2014 -0700
@@ -26,7 +26,7 @@
 #
 # ----------------------------------------------------------------------------------------------------
 
-import os, sys, shutil, zipfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing, StringIO
+import os, sys, shutil, zipfile, tarfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing, StringIO, socket
 from os.path import join, exists, dirname, basename, getmtime
 from argparse import ArgumentParser, RawDescriptionHelpFormatter, REMAINDER
 from outputparser import OutputParser, ValuesMatcher
@@ -35,6 +35,7 @@
 import sanitycheck
 import itertools
 import json, textwrap
+import fnmatch
 
 # This works because when mx loads this file, it makes sure __file__ gets an absolute path
 _graal_home = dirname(dirname(__file__))
@@ -162,49 +163,124 @@
         rmIfExists(mx.distribution('GRAAL').path)
 
 def export(args):
-    """create a GraalVM zip file for distribution"""
+    """create archives of builds split by vmbuild and vm"""
 
     parser = ArgumentParser(prog='mx export')
-    parser.add_argument('--omit-vm-build', action='store_false', dest='vmbuild', help='omit VM build step')
-    parser.add_argument('--omit-dist-init', action='store_false', dest='distInit', help='omit class files and IDE configurations from distribution')
-    parser.add_argument('zipfile', nargs=REMAINDER, metavar='zipfile')
-
     args = parser.parse_args(args)
 
-    tmp = tempfile.mkdtemp(prefix='tmp', dir=_graal_home)
-    if args.vmbuild:
-        # Make sure the product VM binary is up to date
-        with VM(vmbuild='product'):
-            build([])
+    # collect data about export
+    infos = dict()
+    infos['timestamp'] = time.time()
+
+    hgcfg = mx.HgConfig()
+    hgcfg.check()
+    infos['revision'] = hgcfg.tip('.') + ('+' if hgcfg.isDirty('.') else '')
+    # TODO: infos['repository']
+
+    infos['jdkversion'] = str(mx.java().version)
+
+    infos['architecture'] = _arch()
+    infos['platform'] = mx.get_os()
+
+    if mx.get_os != 'windows':
+        pass
+        # infos['ccompiler']
+        # infos['linker']
+
+    infos['hostname'] = socket.gethostname()
 
-    mx.log('Copying Java sources and mx files...')
-    mx.run(('hg archive -I graal -I mx -I mxtool -I mx.sh ' + tmp).split())
+    def _writeJson(suffix, properties):
+        d = infos.copy()
+        for k, v in properties.iteritems():
+            assert not d.has_key(k)
+            d[k] = v
+
+        jsonFileName = 'export-' + suffix + '.json'
+        with open(jsonFileName, 'w') as f:
+            print >> f, json.dumps(d)
+        return jsonFileName
+
+
+    def _genFileName(archivtype, middle):
+        idPrefix = infos['revision'] + '_'
+        idSuffix = '.tar.gz'
+        return join(_graal_home, "graalvm_" + archivtype + "_"  + idPrefix + middle + idSuffix)
+
+    def _genFileArchPlatformName(archivtype, middle):
+        return _genFileName(archivtype, infos['platform'] + '_' + infos['architecture'] + '_' + middle)
+
+
+    # archive different build types of hotspot
+    for vmBuild in _vmbuildChoices:
+        jdkpath = join(_jdksDir(), vmBuild)
+        if not exists(jdkpath):
+            mx.logv("skipping " + vmBuild)
+            continue
 
-    # Copy the GraalVM JDK
-    mx.log('Copying GraalVM JDK...')
-    src = _jdk()
-    dst = join(tmp, basename(src))
-    shutil.copytree(src, dst)
-    zfName = join(_graal_home, 'graalvm-' + mx.get_os() + '.zip')
-    zf = zipfile.ZipFile(zfName, 'w')
-    for root, _, files in os.walk(tmp):
-        for f in files:
-            name = join(root, f)
-            arcname = name[len(tmp) + 1:]
-            zf.write(join(tmp, name), arcname)
+        tarName = _genFileArchPlatformName('basejdk', vmBuild)
+        mx.logv("creating basejdk " + tarName)
+        vmSet = set()
+        with tarfile.open(tarName, 'w:gz') as tar:
+            for root, _, files in os.walk(jdkpath):
+                if basename(root) in _vmChoices.keys():
+                    # TODO: add some assert to check path assumption
+                    vmSet.add(root)
+                    continue
+
+                for f in files:
+                    name = join(root, f)
+                    # print name
+                    tar.add(name, name)
+
+            n = _writeJson("basejdk-" + vmBuild, {'vmbuild' : vmBuild})
+            tar.add(n, n)
+
+        # create a separate archive for each VM
+        for vm in vmSet:
+            bVm = basename(vm)
+            vmTarName = _genFileArchPlatformName('vm', vmBuild + '_' + bVm)
+            mx.logv("creating vm " + vmTarName)
 
-    # create class files and IDE configurations
-    if args.distInit:
-        mx.log('Creating class files...')
-        mx.run('mx build'.split(), cwd=tmp)
-        mx.log('Creating IDE configurations...')
-        mx.run('mx ideinit'.split(), cwd=tmp)
+            debugFiles = set()
+            with tarfile.open(vmTarName, 'w:gz') as tar:
+                for root, _, files in os.walk(vm):
+                    for f in files:
+                        # TODO: mac, windows, solaris?
+                        if any(map(f.endswith, [".debuginfo"])):
+                            debugFiles.add(f)
+                        else:
+                            name = join(root, f)
+                            # print name
+                            tar.add(name, name)
+
+                n = _writeJson("vm-" + vmBuild + "-" + bVm, {'vmbuild' : vmBuild, 'vm' : bVm})
+                tar.add(n, n)
 
-    # clean up temp directory
-    mx.log('Cleaning up...')
-    shutil.rmtree(tmp)
+            if len(debugFiles) > 0:
+                debugTarName = _genFileArchPlatformName('debugfilesvm', vmBuild + '_' + bVm)
+                mx.logv("creating debugfilesvm " + debugTarName)
+                with tarfile.open(debugTarName, 'w:gz') as tar:
+                    for f in debugFiles:
+                        name = join(root, f)
+                        # print name
+                        tar.add(name, name)
+
+                    n = _writeJson("debugfilesvm-" + vmBuild + "-" + bVm, {'vmbuild' : vmBuild, 'vm' : bVm})
+                    tar.add(n, n)
 
-    mx.log('Created distribution in ' + zfName)
+    # graal directory
+    graalDirTarName = _genFileName('classfiles', 'javac')
+    mx.logv("creating graal " + graalDirTarName)
+    with tarfile.open(graalDirTarName, 'w:gz') as tar:
+        for root, _, files in os.walk("graal"):
+            for f in [f for f in files if not f.endswith('.java')]:
+                name = join(root, f)
+                # print name
+                tar.add(name, name)
+
+        n = _writeJson("graal", {'javacompiler' : 'javac'})
+        tar.add(n, n)
+
 
 def _run_benchmark(args, availableBenchmarks, runBenchmark):
 
@@ -861,7 +937,7 @@
         projectscp = mx.classpath(projs)
 
     if whitelist:
-        classes = list(set(classes) & set(whitelist))
+        classes = [c for c in classes if any((glob.match(c) for glob in whitelist))]
 
     if len(classes) != 0:
         f_testfile = open(testfile, 'w')
@@ -905,10 +981,8 @@
 _unittestHelpSuffix = """
     Unittest options:
 
-      --short-only           run short testcases only
-      --long-only            run long testcases only
-      --baseline-whitelist   run only testcases which are known to
-                             work with the baseline compiler
+      --whitelist            run only testcases which are included
+                             in the given whitelist
 
     To avoid conflicts with VM options '--' can be used as delimiter.
 
@@ -945,10 +1019,7 @@
           formatter_class=RawDescriptionHelpFormatter,
           epilog=_unittestHelpSuffix,
         )
-    group = parser.add_mutually_exclusive_group()
-    group.add_argument('--short-only', action='store_true', help='run short testcases only')
-    group.add_argument('--long-only', action='store_true', help='run long testcases only')
-    parser.add_argument('--baseline-whitelist', action='store_true', help='run baseline testcases only')
+    parser.add_argument('--whitelist', help='run testcases specified in whitelist only', metavar='<path>')
 
     ut_args = []
     delimiter = False
@@ -968,33 +1039,19 @@
         parsed_args, args = parser.parse_known_args(ut_args)
 
     whitelist = None
-    if parsed_args.baseline_whitelist:
-        baseline_whitelist_file = 'test/baseline_whitelist.txt'
+    if parsed_args.whitelist:
         try:
-            with open(join(_graal_home, baseline_whitelist_file)) as fp:
-                whitelist = [l.rstrip() for l in fp.readlines()]
+            with open(join(_graal_home, parsed_args.whitelist)) as fp:
+                whitelist = [re.compile(fnmatch.translate(l.rstrip())) for l in fp.readlines() if not l.startswith('#')]
         except IOError:
-            mx.log('warning: could not read baseline whitelist: ' + baseline_whitelist_file)
+            mx.log('warning: could not read whitelist: ' + parsed_args.whitelist)
 
-    if parsed_args.long_only:
-        annotations = ['@LongTest', '@Parameters']
-    elif parsed_args.short_only:
-        annotations = ['@Test']
-    else:
-        annotations = ['@Test', '@LongTest', '@Parameters']
-
-    _unittest(args, annotations, whitelist=whitelist)
+    _unittest(args, ['@Test', '@Parameters'], whitelist=whitelist)
 
 def shortunittest(args):
-    """alias for 'unittest --short-only'{0}"""
-
-    args.insert(0, '--short-only')
-    unittest(args)
+    """alias for 'unittest --whitelist test/whitelist_shortunittest.txt'{0}"""
 
-def longunittest(args):
-    """alias for 'unittest --long-only'{0}"""
-
-    args.insert(0, '--long-only')
+    args = ['--whitelist', 'test/whitelist_shortunittest.txt'] + args
     unittest(args)
 
 def buildvms(args):
@@ -1104,6 +1161,11 @@
         unittest([])
         tasks.append(t.stop())
 
+    with VM('server', 'product'):  # hosted mode
+        t = Task('UnitTests-BaselineCompiler:hosted-product')
+        unittest(['--whitelist', 'test/whitelist_baseline.txt', '-G:+UseBaselineCompiler'])
+        tasks.append(t.stop())
+
     for vmbuild in ['fastdebug', 'product']:
         for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild) + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild):
             t = Task(str(test) + ':' + vmbuild)
@@ -1306,7 +1368,7 @@
         executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer')
 
     archive = join(libpath, 'c1visualizer_2014-04-22.zip')
-    if not exists(executable):
+    if not exists(executable) or not exists(archive):
         if not exists(archive):
             mx.download(archive, ['https://java.net/downloads/c1visualizer/c1visualizer_2014-04-22.zip'])
         zf = zipfile.ZipFile(archive, 'r')
@@ -1723,14 +1785,14 @@
     """make truffle.jar"""
 
     # Test with the built classes
-    _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@LongTest', '@Parameters'])
+    _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@Parameters'])
 
     # We use the DSL processor as the starting point for the classpath - this
     # therefore includes the DSL processor, the DSL and the API.
     packagejar(mx.classpath("com.oracle.truffle.dsl.processor").split(os.pathsep), "truffle.jar", None, "com.oracle.truffle.dsl.processor.TruffleProcessor")
 
     # Test with the JAR
-    _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@LongTest', '@Parameters'], "truffle.jar:")
+    _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@Parameters'], "truffle.jar:")
 
 
 def isGraalEnabled(vm):
@@ -1953,7 +2015,6 @@
         'gate' : [gate, '[-options]'],
         'bench' : [bench, '[-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'],
         'unittest' : [unittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
-        'longunittest' : [longunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
         'makejmhdeps' : [makejmhdeps, ''],
         'shortunittest' : [shortunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
         'jacocoreport' : [jacocoreport, '[output directory]'],
--- a/mx/projects	Tue Apr 29 12:05:58 2014 -0700
+++ b/mx/projects	Tue Apr 29 12:43:27 2014 -0700
@@ -42,19 +42,19 @@
 library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar
 library@DACAPO_SCALA@sha1=59b64c974662b5cf9dbd3cf9045d293853dd7a51
 
-library@OKRA@path=lib/okra-1.8.jar
-library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8.jar
-library@OKRA@sourcePath=lib/okra-1.8-src.jar
-library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-src.jar
+library@OKRA@path=lib/okra-1.9.jar
+library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9.jar
+library@OKRA@sourcePath=lib/okra-1.9-src.jar
+library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-src.jar
 
-library@OKRA_WITH_SIM@path=lib/okra-1.8-with-sim.jar
-library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim.jar
-library@OKRA_WITH_SIM@sourcePath=lib/okra-1.8-with-sim-src.jar
-library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim-src.jar
+library@OKRA_WITH_SIM@path=lib/okra-1.9-with-sim.jar
+library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim.jar
+library@OKRA_WITH_SIM@sourcePath=lib/okra-1.9-with-sim-src.jar
+library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim-src.jar
 
 library@JAVA_ALLOCATION_INSTRUMENTER@path=lib/java-allocation-instrumenter.jar
-library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-8f0db117e64e.jar
-library@JAVA_ALLOCATION_INSTRUMENTER@sha1=64c0a5329fbcb8284640e58d83252e0a3b08c23e
+library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-c7e3525a6b90.jar
+library@JAVA_ALLOCATION_INSTRUMENTER@sha1=128eb20a4cd3362a4d8b94614e66647808a2e37c
 
 library@VECMATH@path=lib/vecmath-1.3.1.jar
 library@VECMATH@urls=http://mirrors.ibiblio.org/pub/mirrors/maven/java3d/jars/vecmath-1.3.1.jar
@@ -283,7 +283,7 @@
 # graal.lir
 project@com.oracle.graal.lir@subDir=graal
 project@com.oracle.graal.lir@sourceDirs=src
-project@com.oracle.graal.lir@dependencies=com.oracle.graal.nodes,com.oracle.graal.asm
+project@com.oracle.graal.lir@dependencies=com.oracle.graal.debug,com.oracle.graal.compiler.common,com.oracle.graal.asm
 project@com.oracle.graal.lir@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.lir@javaCompliance=1.8
 project@com.oracle.graal.lir@workingSets=Graal,LIR
@@ -373,7 +373,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.api.replacements
+project@com.oracle.graal.nodes@dependencies=com.oracle.graal.graph,com.oracle.graal.api.replacements,com.oracle.graal.lir
 project@com.oracle.graal.nodes@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.nodes@javaCompliance=1.8
 project@com.oracle.graal.nodes@annotationProcessors=com.oracle.graal.replacements.verifier
@@ -422,10 +422,11 @@
 # graal.compiler
 project@com.oracle.graal.compiler@subDir=graal
 project@com.oracle.graal.compiler@sourceDirs=src
-project@com.oracle.graal.compiler@dependencies=com.oracle.graal.api.runtime,com.oracle.graal.virtual,com.oracle.graal.loop,com.oracle.graal.alloc,com.oracle.graal.lir
+project@com.oracle.graal.compiler@dependencies=com.oracle.graal.api.runtime,com.oracle.graal.virtual,com.oracle.graal.loop,com.oracle.graal.alloc
 project@com.oracle.graal.compiler@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.compiler@javaCompliance=1.8
 project@com.oracle.graal.compiler@annotationProcessors=com.oracle.graal.service.processor
+project@com.oracle.graal.compiler@annotationProcessorForDependents=true
 project@com.oracle.graal.compiler@workingSets=Graal
 
 # graal.compiler.amd64
--- a/mxtool/mx.py	Tue Apr 29 12:05:58 2014 -0700
+++ b/mxtool/mx.py	Tue Apr 29 12:43:27 2014 -0700
@@ -608,6 +608,17 @@
             else:
                 return None
 
+    def isDirty(self, sDir, abortOnError=True):
+        try:
+            return len(subprocess.check_output(['hg', 'status', '-R', sDir])) > 0
+        except OSError:
+            warn(self.missing)
+        except subprocess.CalledProcessError:
+            if abortOnError:
+                abort('failed to get status')
+            else:
+                return None
+
 class Suite:
     def __init__(self, mxDir, primary, load=True):
         self.dir = dirname(mxDir)
@@ -1800,11 +1811,13 @@
     parser.add_argument('--only', action='store', help='comma separated projects to build, without checking their dependencies (omit to build all projects)')
     parser.add_argument('--no-java', action='store_false', dest='java', help='do not build Java projects')
     parser.add_argument('--no-native', action='store_false', dest='native', help='do not build native projects')
-    parser.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not')
-    parser.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler (default: ' + defaultEcjPath + ')', default=defaultEcjPath, metavar='<path>')
     parser.add_argument('--jdt-warning-as-error', action='store_true', help='convert all Eclipse batch compiler warnings to errors')
     parser.add_argument('--jdt-show-task-tags', action='store_true', help='show task tags as Eclipse batch compiler warnings')
-    parser.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='<path>')
+    compilerSelect = parser.add_mutually_exclusive_group()
+    compilerSelect.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='<path>')
+    compilerSelect.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler (default: ' + defaultEcjPath + ')', default=defaultEcjPath, metavar='<path>')
+    compilerSelect.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not')
+
 
     if suppliedParser:
         parser.add_argument('remainder', nargs=REMAINDER, metavar='...')
@@ -1886,12 +1899,11 @@
 
         cp = classpath(p.name, includeSelf=True)
         sourceDirs = p.source_dirs()
-        mustBuild = args.force
-        if not mustBuild:
+        buildReason = 'forced build' if args.force else None
+        if not buildReason:
             for dep in p.all_deps([], False):
                 if dep.name in built:
-                    mustBuild = True
-
+                    buildReason = dep.name + ' rebuilt'
 
         jasminAvailable = None
         javafilelist = []
@@ -1940,20 +1952,19 @@
                         if exists(dirname(dst)) and (not exists(dst) or os.path.getmtime(dst) < os.path.getmtime(src)):
                             shutil.copyfile(src, dst)
 
-                if not mustBuild:
+                if not buildReason:
                     for javafile in javafiles:
                         classfile = TimeStampFile(outputDir + javafile[len(sourceDir):-len('java')] + 'class')
                         if not classfile.exists() or classfile.isOlderThan(javafile):
-                            mustBuild = True
+                            buildReason = 'class file(s) out of date'
                             break
 
         aps = p.annotation_processors()
         apsOutOfDate = p.update_current_annotation_processors_file()
         if apsOutOfDate:
-            logv('[annotation processors for {0} changed]'.format(p.name))
-            mustBuild = True
-
-        if not mustBuild:
+            buildReason = 'annotation processor(s) changed'
+
+        if not buildReason:
             logv('[all class files for {0} are up to date - skipping]'.format(p.name))
             continue
 
@@ -1985,10 +1996,14 @@
 
         toBeDeleted = [argfileName]
         try:
+
+            def logCompilation(p, compiler, reason):
+                log('Compiling Java sources for {} with {}... [{}]'.format(p.name, compiler, reason))
+
             if not jdtJar:
                 mainJava = java()
                 if not args.error_prone:
-                    log('Compiling Java sources for {0} with javac...'.format(p.name))
+                    logCompilation(p, 'javac', buildReason)
                     javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
                     if jdk.debug_port is not None:
                         javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
@@ -1999,7 +2014,7 @@
                         javacCmd.append('-XDignore.symbol.file')
                     run(javacCmd)
                 else:
-                    log('Compiling Java sources for {0} with javac (with error-prone)...'.format(p.name))
+                    logCompilation(p, 'javac (with error-prone)', buildReason)
                     javaArgs = ['-Xmx1g']
                     javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
                     javacArgs += processorArgs
@@ -2008,7 +2023,7 @@
                         javacArgs.append('-XDignore.symbol.file')
                     run_java(javaArgs + ['-cp', os.pathsep.join([mainJava.toolsjar, args.error_prone]), 'com.google.errorprone.ErrorProneCompiler'] + javacArgs)
             else:
-                log('Compiling Java sources for {0} with JDT...'.format(p.name))
+                logCompilation(p, 'JDT', buildReason)
 
                 jdtVmArgs = ['-Xmx1g', '-jar', jdtJar]
 
@@ -3843,7 +3858,7 @@
 
 
 def ideinit(args, refreshOnly=False, buildProcessorJars=True):
-    """(re)generate Eclipse and NetBeans project configurations"""
+    """(re)generate Eclipse, NetBeans and Intellij project configurations"""
     eclipseinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars)
     netbeansinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars)
     intellijinit(args, refreshOnly=refreshOnly)
@@ -3981,7 +3996,13 @@
             try:
                 log('Generating {2} for {0} in {1}'.format(p.name, out, docDir))
                 projectJava = java(p.javaCompliance)
-                run([java().javadoc, memory,
+
+                # Once https://bugs.openjdk.java.net/browse/JDK-8041628 is fixed,
+                # this should be reverted to:
+                # javadocExe = java().javadoc
+                javadocExe = projectJava.javadoc
+
+                run([javadocExe, memory,
                      '-XDignore.symbol.file',
                      '-classpath', cp,
                      '-quiet',
@@ -3991,6 +4012,7 @@
                      '-source', str(projectJava.javaCompliance),
                      '-bootclasspath', projectJava.bootclasspath(),
                      '-extdirs', projectJava.extdirs()] +
+                     ([] if projectJava.javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) +
                      links +
                      extraArgs +
                      nowarnAPI +
@@ -4028,115 +4050,19 @@
              '-quiet',
              '-d', out,
              '-sourcepath', sp] +
+             ([] if java().javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) +
              links +
              extraArgs +
              nowarnAPI +
              list(pkgs))
         log('Generated {2} for {0} in {1}'.format(', '.join(names), out, docDir))
 
-class Chunk:
-    def __init__(self, content, ldelim, rdelim=None):
-        lindex = content.find(ldelim)
-        if rdelim is not None:
-            rindex = content.find(rdelim)
-        else:
-            rindex = lindex + len(ldelim)
-        self.ldelim = ldelim
-        self.rdelim = rdelim
-        if lindex != -1 and rindex != -1 and rindex > lindex:
-            self.text = content[lindex + len(ldelim):rindex]
-        else:
-            self.text = None
-
-    def replace(self, content, repl):
-        lindex = content.find(self.ldelim)
-        if self.rdelim is not None:
-            rindex = content.find(self.rdelim)
-            rdelimLen = len(self.rdelim)
-        else:
-            rindex = lindex + len(self.ldelim)
-            rdelimLen = 0
-        old = content[lindex:rindex + rdelimLen]
-        return content.replace(old, repl)
-
-# Post-process an overview-summary.html file to move the
-# complete overview to the top of the page
-def _fix_overview_summary(path, topLink):
-    """
-    Processes an "overview-summary.html" generated by javadoc to put the complete
-    summary text above the Packages table.
-    """
-
-    # This uses scraping and so will break if the relevant content produced by javadoc changes in any way!
-    with open(path) as fp:
-        content = fp.read()
-
-    chunk1 = Chunk(content, """<div class="header">
-<div class="subTitle">
-<div class="block">""", """</div>
-</div>
-<p>See: <a href="#overview.description">Description</a></p>
-</div>""")
-
-    chunk2 = Chunk(content, """<div class="contentContainer"><a name="overview.description">
-<!--   -->
-</a>
-<div class="block">""", """</div>
-</div>
-<!-- ======= START OF BOTTOM NAVBAR ====== -->""")
-
-    assert chunk1.text, 'Could not find header section in ' + path
-    assert chunk2.text, 'Could not find footer section in ' + path
-
-    content = chunk1.replace(content, '<div class="header"><div class="subTitle"><div class="block">' + topLink + chunk2.text + '</div></div></div>')
-    content = chunk2.replace(content, '')
-
-    with open(path, 'w') as fp:
-        fp.write(content)
-
-
-# Post-process a package-summary.html file to move the
-# complete package description to the top of the page
-def _fix_package_summary(path):
-    """
-    Processes an "overview-summary.html" generated by javadoc to put the complete
-    summary text above the Packages table.
-    """
-
-    # This uses scraping and so will break if the relevant content produced by javadoc changes in any way!
-    with open(path) as fp:
-        content = fp.read()
-
-    chunk1 = Chunk(content, """<div class="header">
-<h1 title="Package" class="title">Package""", """<p>See:&nbsp;<a href="#package.description">Description</a></p>
-</div>""")
-
-    chunk2 = Chunk(content, """<a name="package.description">
-<!--   -->
-</a>""", """</div>
-</div>
-<!-- ======= START OF BOTTOM NAVBAR ====== -->""")
-
-    if chunk1.text:
-        if chunk2.text:
-            repl = re.sub(r'<h2 title=(.*) Description</h2>', r'<h1 title=\1</h1>', chunk2.text, 1)
-            content = chunk1.replace(content, '<div class="header">' + repl + '</div></div>')
-            content = chunk2.replace(content, '')
-
-            with open(path, 'w') as fp:
-                fp.write(content)
-        else:
-            log('warning: Could not find package description detail section in ' + path)
-
-    else:
-        # no package description given
-        pass
-
 def site(args):
     """creates a website containing javadoc and the project dependency graph"""
 
     parser = ArgumentParser(prog='site')
     parser.add_argument('-d', '--base', action='store', help='directory for generated site', required=True, metavar='<dir>')
+    parser.add_argument('--tmp', action='store', help='directory to use for intermediate results', metavar='<dir>')
     parser.add_argument('--name', action='store', help='name of overall documentation', required=True, metavar='<name>')
     parser.add_argument('--overview', action='store', help='path to the overview content for overall documentation', required=True, metavar='<path>')
     parser.add_argument('--projects', action='store', help='comma separated projects to process (omit to process all projects)')
@@ -4147,7 +4073,7 @@
     args = parser.parse_args(args)
 
     args.base = os.path.abspath(args.base)
-    tmpbase = tempfile.mkdtemp(prefix=basename(args.base) + '.', dir=dirname(args.base))
+    tmpbase = args.tmp if args.tmp else  tempfile.mkdtemp(prefix=basename(args.base) + '.', dir=dirname(args.base))
     unified = join(tmpbase, 'all')
 
     exclude_packages_arg = []
@@ -4196,6 +4122,9 @@
                  '--arg', '@-windowtitle', '--arg', '@' + title,
                  '--arg', '@-doctitle', '--arg', '@' + title,
                  '--arg', '@-overview', '--arg', '@' + args.overview] + exclude_packages_arg + projects_arg + extra_javadoc_args)
+
+        if exists(unified):
+            shutil.rmtree(unified)
         os.rename(join(tmpbase, 'javadoc'), unified)
 
         # Generate dependency graph with Graphviz
@@ -4249,29 +4178,17 @@
             with open(html, 'w') as fp:
                 print >> fp, '<html><body><object data="{}.svg" type="image/svg+xml"></object></body></html>'.format(args.dot_output_base)
 
-        top = join(tmpbase, 'all', 'overview-summary.html')
-        for root, _, files in os.walk(tmpbase):
-            for f in files:
-                if f == 'overview-summary.html':
-                    path = join(root, f)
-                    topLink = ''
-                    if top != path:
-                        link = os.path.relpath(join(tmpbase, 'all', 'index.html'), dirname(path))
-                        topLink = '<p><a href="' + link + '", target="_top"><b>[return to the overall ' + args.name + ' documentation]</b></a></p>'
-                    _fix_overview_summary(path, topLink)
-                elif f == 'package-summary.html':
-                    path = join(root, f)
-                    _fix_package_summary(path)
-
-
         if exists(args.base):
             shutil.rmtree(args.base)
-        shutil.move(tmpbase, args.base)
+        if args.tmp:
+            shutil.copytree(tmpbase, args.base)
+        else:
+            shutil.move(tmpbase, args.base)
 
         print 'Created website - root is ' + join(args.base, 'all', 'index.html')
 
     finally:
-        if exists(tmpbase):
+        if not args.tmp and exists(tmpbase):
             shutil.rmtree(tmpbase)
 
 def _kwArg(kwargs):
@@ -4345,6 +4262,7 @@
 
     parser = ArgumentParser(prog='exportlibs')
     parser.add_argument('-b', '--base', action='store', help='base name of archive (default: libs)', default='libs', metavar='<path>')
+    parser.add_argument('-a', '--include-all', action='store_true', help="include all defined libaries")
     parser.add_argument('--arc', action='store', choices=['tgz', 'tbz2', 'tar', 'zip'], default='tgz', help='the type of the archive to create')
     parser.add_argument('--no-sha1', action='store_false', dest='sha1', help='do not create SHA1 signature of archive')
     parser.add_argument('--no-md5', action='store_false', dest='md5', help='do not create MD5 signature of archive')
@@ -4365,9 +4283,44 @@
             else:
                 logv('[already added ' + path + ']')
 
-        for lib in _libs.itervalues():
-            if len(lib.urls) != 0 or args.include_system_libs:
-                add(lib.get_path(resolve=True), lib.path)
+        libsToExport = set()
+        if args.include_all:
+            for lib in _libs.itervalues():
+                libsToExport.add(lib)
+        else:
+            def isValidLibrary(dep):
+                if dep in _libs.iterkeys():
+                    lib = _libs[dep]
+                    if len(lib.urls) != 0 or args.include_system_libs:
+                        return lib
+                return None
+
+            # iterate over all project dependencies and find used libraries
+            for p in _projects.itervalues():
+                for dep in p.deps:
+                    r = isValidLibrary(dep)
+                    if r:
+                        libsToExport.add(r)
+
+            # a library can have other libraries as dependency
+            size = 0
+            while size != len(libsToExport):
+                size = len(libsToExport)
+                for lib in libsToExport.copy():
+                    for dep in lib.deps:
+                        r = isValidLibrary(dep)
+                        if r:
+                            libsToExport.add(r)
+
+        for lib in libsToExport:
+            add(lib.get_path(resolve=True), lib.path)
+            if lib.sha1:
+                add(lib.get_path(resolve=True) + ".sha1", lib.path + ".sha1")
+            if lib.sourcePath:
+                add(lib.get_source_path(resolve=True), lib.sourcePath)
+                if lib.sourceSha1:
+                    add(lib.get_source_path(resolve=True) + ".sha1", lib.sourcePath + ".sha1")
+
         if args.extras:
             for e in args.extras:
                 if os.path.isdir(e):
--- a/src/share/vm/code/debugInfoRec.cpp	Tue Apr 29 12:05:58 2014 -0700
+++ b/src/share/vm/code/debugInfoRec.cpp	Tue Apr 29 12:43:27 2014 -0700
@@ -235,16 +235,13 @@
 
 
 int DebugInformationRecorder::find_sharable_decode_offset(int stream_offset) {
-  // It's always a space win to share and Graal generates quite a bit
-  // of scopes data so always enable the sharing logic with Graal.
-  // Presumably this is disabled in regular HotSpot because it makes
-  // recording more expensive?
-#ifndef GRAAL
-  // Only pull this trick if non-safepoint recording
-  // is enabled, for now.
-  if (!recording_non_safepoints())
+  if (FLAG_IS_DEFAULT(ShareDebugInfo)) {
+    if (!ShareDebugInfo && !recording_non_safepoints()) {
+      return serialized_null;
+    }
+  } else if (!ShareDebugInfo) {
     return serialized_null;
-#endif
+  }
 
   NOT_PRODUCT(++dir_stats.chunks_queried);
   int stream_length = stream()->position() - stream_offset;
--- a/src/share/vm/code/nmethod.cpp	Tue Apr 29 12:05:58 2014 -0700
+++ b/src/share/vm/code/nmethod.cpp	Tue Apr 29 12:43:27 2014 -0700
@@ -142,6 +142,7 @@
   int handler_table_size;
   int nul_chk_table_size;
   int oops_size;
+  int metadata_size;
 
   void note_nmethod(nmethod* nm) {
     nmethod_count += 1;
@@ -151,6 +152,7 @@
     insts_size          += nm->insts_size();
     stub_size           += nm->stub_size();
     oops_size           += nm->oops_size();
+    metadata_size       += nm->metadata_size();
     scopes_data_size    += nm->scopes_data_size();
     scopes_pcs_size     += nm->scopes_pcs_size();
     dependencies_size   += nm->dependencies_size();
@@ -161,11 +163,13 @@
     if (nmethod_count == 0)  return;
     tty->print_cr("Statistics for %d bytecoded nmethods for %s:", nmethod_count, name);
     if (total_size != 0)          tty->print_cr(" total in heap  = %d", total_size);
+    if (nmethod_count != 0)       tty->print_cr(" header         = %d", nmethod_count * sizeof(nmethod));
     if (relocation_size != 0)     tty->print_cr(" relocation     = %d", relocation_size);
     if (consts_size != 0)         tty->print_cr(" constants      = %d", consts_size);
     if (insts_size != 0)          tty->print_cr(" main code      = %d", insts_size);
     if (stub_size != 0)           tty->print_cr(" stub code      = %d", stub_size);
     if (oops_size != 0)           tty->print_cr(" oops           = %d", oops_size);
+    if (metadata_size != 0)       tty->print_cr(" metadata       = %d", metadata_size);
     if (scopes_data_size != 0)    tty->print_cr(" scopes data    = %d", scopes_data_size);
     if (scopes_pcs_size != 0)     tty->print_cr(" scopes pcs     = %d", scopes_pcs_size);
     if (dependencies_size != 0)   tty->print_cr(" dependencies   = %d", dependencies_size);
@@ -180,12 +184,14 @@
   int native_relocation_size;
   int native_insts_size;
   int native_oops_size;
+  int native_metadata_size;
   void note_native_nmethod(nmethod* nm) {
     native_nmethod_count += 1;
     native_total_size       += nm->size();
     native_relocation_size  += nm->relocation_size();
     native_insts_size       += nm->insts_size();
     native_oops_size        += nm->oops_size();
+    native_metadata_size    += nm->metadata_size();
   }
   void print_native_nmethod_stats() {
     if (native_nmethod_count == 0)  return;
@@ -194,6 +200,7 @@
     if (native_relocation_size != 0)  tty->print_cr(" N. relocation  = %d", native_relocation_size);
     if (native_insts_size != 0)       tty->print_cr(" N. main code   = %d", native_insts_size);
     if (native_oops_size != 0)        tty->print_cr(" N. oops        = %d", native_oops_size);
+    if (native_metadata_size != 0)    tty->print_cr(" N. metadata    = %d", native_metadata_size);
   }
 };
 
@@ -229,11 +236,18 @@
 #ifdef GRAAL
 static java_nmethod_stats_struct graal_java_nmethod_stats;
 #endif
+#ifdef SHARK
+static java_nmethod_stats_struct shark_java_nmethod_stats;
+#endif
 static java_nmethod_stats_struct unknown_java_nmethod_stats;
 
 static native_nmethod_stats_struct native_nmethod_stats;
 static pc_nmethod_stats_struct pc_nmethod_stats;
 
+static void note_native_wrapper_nmethod(nmethod* nm) {
+  native_nmethod_stats.note_native_nmethod(nm);
+}
+
 static void note_java_nmethod(nmethod* nm) {
 #ifdef COMPILER1
   if (nm->is_compiled_by_c1()) {
@@ -250,6 +264,11 @@
     graal_java_nmethod_stats.note_nmethod(nm);
   } else
 #endif
+#ifdef SHARK
+  if (nm->is_compiled_by_shark()) {
+    shark_java_nmethod_stats.note_nmethod(nm);
+  } else
+#endif
   {
     unknown_java_nmethod_stats.note_nmethod(nm);
   }
@@ -556,7 +575,7 @@
                                             code_buffer, frame_size,
                                             basic_lock_owner_sp_offset,
                                             basic_lock_sp_offset, oop_maps);
-    if (nm != NULL)  note_java_nmethod(nm);
+    if (nm != NULL)  note_native_wrapper_nmethod(nm);
     if (PrintAssembly && nm != NULL) {
       Disassembler::decode(nm);
     }
@@ -3083,9 +3102,14 @@
 #ifdef GRAAL
   graal_java_nmethod_stats.print_nmethod_stats("Graal");
 #endif
+#ifdef SHARK
+  shark_java_nmethod_stats.print_nmethod_stats("Shark");
+#endif
   unknown_java_nmethod_stats.print_nmethod_stats("Unknown");
   DebugInformationRecorder::print_statistics();
+#ifndef PRODUCT
   pc_nmethod_stats.print_pc_stats();
+#endif
   Dependencies::print_statistics();
   if (xtty != NULL)  xtty->tail("statistics");
 }
--- a/src/share/vm/graal/graalGlobals.hpp	Tue Apr 29 12:05:58 2014 -0700
+++ b/src/share/vm/graal/graalGlobals.hpp	Tue Apr 29 12:43:27 2014 -0700
@@ -52,6 +52,9 @@
   COMPILERGRAAL_PRESENT(product(bool, BootstrapGraal, true,                 \
           "Bootstrap Graal before running Java main method"))               \
                                                                             \
+  product(bool, ForceGraalInitialization, false,                            \
+          "Force VM to initialize the compiler even if not used")           \
+                                                                            \
   product(intx, TraceGraal, 0,                                              \
           "Trace level for Graal")                                          \
                                                                             \
--- a/src/share/vm/prims/jni.cpp	Tue Apr 29 12:05:58 2014 -0700
+++ b/src/share/vm/prims/jni.cpp	Tue Apr 29 12:43:27 2014 -0700
@@ -5176,6 +5176,9 @@
 #ifdef GRAAL
     // GraalCompiler needs to have been created in compileBroker.cpp
     GraalCompiler* graal_compiler = GraalCompiler::instance();
+    if (ForceGraalInitialization && graal_compiler == NULL) {
+      graal_compiler = new GraalCompiler();
+    }
     if (graal_compiler != NULL) {
       graal_compiler->initialize();
     } else {
--- a/src/share/vm/runtime/globals.hpp	Tue Apr 29 12:05:58 2014 -0700
+++ b/src/share/vm/runtime/globals.hpp	Tue Apr 29 12:43:27 2014 -0700
@@ -980,6 +980,9 @@
   product(bool, PrintNMethodStatistics, false,                              \
           "Print a summary statistic for the generated nmethods")           \
                                                                             \
+  product(bool, ShareDebugInfo, IS_GRAAL_DEFINED,                           \
+          "Always tries to share similar debug info inside a nmethod")      \
+                                                                            \
   diagnostic(bool, PrintNMethods, false,                                    \
           "Print assembly code for nmethods when generated")                \
                                                                             \
--- a/src/share/vm/runtime/thread.cpp	Tue Apr 29 12:05:58 2014 -0700
+++ b/src/share/vm/runtime/thread.cpp	Tue Apr 29 12:43:27 2014 -0700
@@ -1680,9 +1680,11 @@
   if (_thread_stat != NULL) delete _thread_stat;
 
 #ifdef GRAAL
-  if (GraalCounterSize > 0 && graal_counters_include(threadObj())) {
-    for (int i = 0; i < GraalCounterSize; i++) {
-      _graal_old_thread_counters[i] += _graal_counters[i];
+  if (GraalCounterSize > 0) {
+    if (graal_counters_include(threadObj())) {
+      for (int i = 0; i < GraalCounterSize; i++) {
+        _graal_old_thread_counters[i] += _graal_counters[i];
+      }
     }
     FREE_C_HEAP_ARRAY(jlong, _graal_counters, mtInternal);
   }
--- a/test/baseline_whitelist.txt	Tue Apr 29 12:05:58 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-com.oracle.graal.jtt.loop.Loop03
-com.oracle.graal.jtt.loop.Loop04
-com.oracle.graal.jtt.loop.Loop08
-com.oracle.graal.jtt.loop.Loop11
-com.oracle.graal.jtt.bytecode.BC_iadd
-com.oracle.graal.jtt.bytecode.BC_iadd2
-com.oracle.graal.jtt.bytecode.BC_iadd3
-com.oracle.graal.jtt.bytecode.BC_ifeq_2
-com.oracle.graal.jtt.bytecode.BC_ifeq_3
-com.oracle.graal.jtt.bytecode.BC_ifeq
-com.oracle.graal.jtt.bytecode.BC_aload_3
-com.oracle.graal.jtt.bytecode.BC_aload_2
-com.oracle.graal.jtt.bytecode.BC_aload_1
-com.oracle.graal.jtt.bytecode.BC_aload_0
-com.oracle.graal.jtt.bytecode.BC_areturn
-com.oracle.graal.jtt.bytecode.BC_freturn
-com.oracle.graal.jtt.bytecode.BC_iconst
-com.oracle.graal.jtt.bytecode.BC_ireturn
-com.oracle.graal.jtt.bytecode.BC_lreturn
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/whitelist_baseline.txt	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,19 @@
+# com.oracle.graal.jtt.loop.Loop03
+# com.oracle.graal.jtt.loop.Loop04
+# com.oracle.graal.jtt.loop.Loop08
+# com.oracle.graal.jtt.loop.Loop11
+com.oracle.graal.jtt.bytecode.BC_iadd
+com.oracle.graal.jtt.bytecode.BC_iadd2
+com.oracle.graal.jtt.bytecode.BC_iadd3
+com.oracle.graal.jtt.bytecode.BC_ifeq_2
+com.oracle.graal.jtt.bytecode.BC_ifeq_3
+com.oracle.graal.jtt.bytecode.BC_ifeq
+com.oracle.graal.jtt.bytecode.BC_aload_3
+com.oracle.graal.jtt.bytecode.BC_aload_2
+com.oracle.graal.jtt.bytecode.BC_aload_1
+com.oracle.graal.jtt.bytecode.BC_aload_0
+com.oracle.graal.jtt.bytecode.BC_areturn
+com.oracle.graal.jtt.bytecode.BC_freturn
+com.oracle.graal.jtt.bytecode.BC_iconst
+com.oracle.graal.jtt.bytecode.BC_ireturn
+com.oracle.graal.jtt.bytecode.BC_lreturn
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/whitelist_shortunittest.txt	Tue Apr 29 12:43:27 2014 -0700
@@ -0,0 +1,1 @@
+com.oracle.graal.jtt.bytecode.*