changeset 15945:57303ce74a21

Merge with 5c73b162eec248fc2d06f59d8f25860871a21be5
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Tue, 27 May 2014 21:20:01 -0700
parents eedf6c293639 (current diff) 5c73b162eec2 (diff)
children b2c18c498f13 6ee370b4d452
files
diffstat 98 files changed, 2496 insertions(+), 745 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java	Tue May 27 21:20:01 2014 -0700
@@ -63,7 +63,7 @@
         assert NULL_OBJECT.isNull();
     }
 
-    protected Constant(Kind kind) {
+    protected Constant(PlatformKind kind) {
         super(kind);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Service.java	Tue May 27 21:20:01 2014 -0700
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.runtime;
+
+/**
+ * Denotes a service that may be efficiently loaded by {@link Services#load(Class)}.
+ */
+public interface Service {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Services.java	Tue May 27 21:20:01 2014 -0700
@@ -0,0 +1,63 @@
+/*
+ * 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.runtime;
+
+import static java.lang.String.*;
+
+import java.util.*;
+
+/**
+ * A mechanism on top of the standard {@link ServiceLoader} that enables a runtime to efficiently
+ * load services marked by {@link Service}. This may be important for services loaded early in the
+ * runtime initialization process.
+ */
+public class Services {
+
+    private static final ClassValue<List<Service>> cache = new ClassValue<List<Service>>() {
+        @Override
+        protected List<Service> computeValue(Class<?> type) {
+            Service[] names = getServiceImpls(type);
+            if (names == null || names.length == 0) {
+                throw new InternalError(format("No implementations for %s found (ensure %s extends %s)", type.getSimpleName(), type.getSimpleName(), Service.class));
+            }
+            return Arrays.asList(names);
+        }
+    };
+
+    /**
+     * Gets an {@link Iterable} of the implementations available for a given service.
+     */
+    @SuppressWarnings("unchecked")
+    public static <S> Iterable<S> load(Class<S> service) {
+        if (Service.class.isAssignableFrom(service)) {
+            try {
+                return (Iterable<S>) cache.get(service);
+            } catch (UnsatisfiedLinkError e) {
+                // Fall back to standard SerivceLoader
+            }
+        }
+        return ServiceLoader.loadInstalled(service);
+    }
+
+    private static native <S> S[] getServiceImpls(Class<?> service);
+}
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java	Tue May 27 21:20:01 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
@@ -48,7 +48,7 @@
 
     /**
      * Closes this buffer. No extra data can be written to this buffer after this call.
-     * 
+     *
      * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not
      *            including) {@code position()} is returned
      * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
@@ -68,7 +68,7 @@
 
     /**
      * Copies the data from this buffer into a given array.
-     * 
+     *
      * @param dst the destination array
      * @param off starting position in {@code dst}
      * @param len number of bytes to copy
@@ -114,7 +114,7 @@
     }
 
     public int emitByte(int b, int pos) {
-        assert NumUtil.isUByte(b);
+        assert NumUtil.isUByte(b) || NumUtil.isByte(b);
         int newPos = pos + 1;
         ensureSize(newPos);
         data[pos] = (byte) (b & 0xFF);
@@ -139,7 +139,7 @@
 
         @Override
         public int emitShort(int b, int pos) {
-            assert NumUtil.isUShort(b);
+            assert NumUtil.isUShort(b) || NumUtil.isShort(b);
             int newPos = pos + 2;
             ensureSize(pos + 2);
             data[pos] = (byte) ((b >> 8) & 0xFF);
@@ -188,7 +188,7 @@
 
         @Override
         public int emitShort(int b, int pos) {
-            assert NumUtil.isUShort(b);
+            assert NumUtil.isUShort(b) || NumUtil.isShort(b);
             int newPos = pos + 2;
             ensureSize(newPos);
             data[pos] = (byte) (b & 0xFF);
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue May 27 21:20:01 2014 -0700
@@ -131,13 +131,7 @@
 
     @Override
     public Variable emitMove(Value input) {
-        PlatformKind kind;
-        if (input instanceof Constant) {
-            kind = input.getKind().getStackKind();
-        } else {
-            kind = input.getPlatformKind();
-        }
-        Variable result = newVariable(kind);
+        Variable result = newVariable(input.getPlatformKind());
         emitMove(result, input);
         return result;
     }
@@ -248,18 +242,10 @@
     public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
         boolean mirrored = emitCompare(cmpKind, left, right);
         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());
+        if (cmpKind == Kind.Float || cmpKind == Kind.Double) {
+            append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
+        } else {
+            append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
         }
     }
 
@@ -267,18 +253,10 @@
                     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());
+        if (cmpKind == Kind.Float || cmpKind == Kind.Double) {
+            append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
+        } else {
+            append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
         }
     }
 
@@ -299,18 +277,10 @@
         Condition finalCondition = mirrored ? cond.mirror() : cond;
 
         Variable result = newVariable(trueValue.getKind());
-        switch (left.getKind().getStackKind()) {
-            case Int:
-            case Long:
-            case Object:
-                append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue)));
-                break;
-            case Float:
-            case Double:
-                append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere("" + left.getKind());
+        if (cmpKind == Kind.Float || cmpKind == Kind.Double) {
+            append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
+        } else {
+            append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue)));
         }
         return result;
     }
@@ -376,13 +346,13 @@
             emitCompareRegMemoryOp(cmpKind, left, b, state);
             mirrored = false;
         } else {
-            emitCompareMemoryConOp(cmpKind, b, a, state);
+            emitCompareMemoryConOp(cmpKind, b, (Constant) a, state);
             mirrored = true;
         }
         return mirrored;
     }
 
-    protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, Value value, LIRFrameState state) {
+    protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, Constant value, LIRFrameState state) {
         assert kind.getStackKind() == value.getKind().getStackKind();
         switch (kind) {
             case Byte:
@@ -399,6 +369,10 @@
             case Long:
                 append(new CompareMemoryOp(LCMP, kind, address, value, state));
                 break;
+            case Object:
+                assert value.isNull();
+                append(new CompareMemoryOp(ACMP, kind, address, value, state));
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java	Tue May 27 21:20:01 2014 -0700
@@ -53,6 +53,12 @@
     }
 
     @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        ResolvedJavaType constType = c.isNull() ? null : meta.lookupJavaType(c);
+        return copyWith(constType, c.isNonNull(), c.isNonNull(), c.isNull());
+    }
+
+    @Override
     public boolean isLegal() {
         return !exactType || (type != null && (isConcreteType(type)));
     }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Tue May 27 21:20:01 2014 -0700
@@ -54,6 +54,12 @@
     }
 
     @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        assert c.getKind().isNumericFloat() && c.getKind().getBitCount() == getBits();
+        return StampFactory.forConstant(c);
+    }
+
+    @Override
     public boolean isLegal() {
         return lowerBound <= upperBound || !nonNaN;
     }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java	Tue May 27 21:20:01 2014 -0700
@@ -55,6 +55,11 @@
     }
 
     @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        throw GraalInternalError.shouldNotReachHere("illegal stamp has no value");
+    }
+
+    @Override
     public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
         throw GraalInternalError.shouldNotReachHere("illegal stamp has no Java type");
     }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Tue May 27 21:20:01 2014 -0700
@@ -64,6 +64,12 @@
     }
 
     @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        long value = c.asLong();
+        return StampFactory.forInteger(getBits(), value, value);
+    }
+
+    @Override
     public boolean isLegal() {
         return lowerBound <= upperBound;
     }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Tue May 27 21:20:01 2014 -0700
@@ -88,6 +88,15 @@
     public abstract Stamp illegal();
 
     /**
+     * If it is possible to represent single value stamps of this kind, this method returns the
+     * stamp representing the single value c. stamp.constant(c).asConstant() should be equal to c.
+     * <p>
+     * If it is not possible to represent single value stamps, this method returns a stamp that
+     * includes c, and is otherwise as narrow as possible.
+     */
+    public abstract Stamp constant(Constant c, MetaAccessProvider meta);
+
+    /**
      * Test whether two stamps have the same base type.
      */
     public abstract boolean isCompatible(Stamp other);
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampFactory.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampFactory.java	Tue May 27 21:20:01 2014 -0700
@@ -195,7 +195,6 @@
     }
 
     public static Stamp forConstant(Constant value, MetaAccessProvider metaAccess) {
-        assert value.getKind() == Kind.Object;
         if (value.getKind() == Kind.Object) {
             ResolvedJavaType type = value.isNull() ? null : metaAccess.lookupJavaType(value);
             return new ObjectStamp(type, value.isNonNull(), value.isNonNull(), value.isNull());
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java	Tue May 27 21:20:01 2014 -0700
@@ -102,6 +102,11 @@
         return true;
     }
 
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        throw GraalInternalError.shouldNotReachHere("void stamp has no value");
+    }
+
     private static VoidStamp instance = new VoidStamp();
 
     static VoidStamp getInstance() {
--- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java	Tue May 27 21:20:01 2014 -0700
@@ -54,7 +54,7 @@
 
     private static synchronized void installSubstitutions() {
         if (!substitutionsInstalled) {
-            getHSAILBackend().getProviders().getReplacements().registerSubstitutions(ForceDeoptSubstitutions.class);
+            getHSAILBackend().getProviders().getReplacements().registerSubstitutions(GraalKernelTester.class, ForceDeoptSubstitutions.class);
             substitutionsInstalled = true;
         }
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue May 27 21:20:01 2014 -0700
@@ -89,7 +89,7 @@
 
     private void installSubstitutions() {
         if (!substitutionsInstalled) {
-            this.providers.getReplacements().registerSubstitutions(InjectProfileDataSubstitutions.class);
+            this.providers.getReplacements().registerSubstitutions(GraalCompilerTest.class, InjectProfileDataSubstitutions.class);
             substitutionsInstalled = true;
         }
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Tue May 27 21:20:01 2014 -0700
@@ -69,45 +69,60 @@
          */
         public Interval any;
 
-        public RegisterBindingLists(Interval fixed, Interval any) {
+        /**
+         * List of intervals whose binding is currently {@link RegisterBinding#Stack}.
+         */
+        public Interval stack;
+
+        public RegisterBindingLists(Interval fixed, Interval any, Interval stack) {
             this.fixed = fixed;
             this.any = any;
+            this.stack = stack;
         }
 
         /**
          * Gets the list for a specified binding.
-         * 
+         *
          * @param binding specifies the list to be returned
          * @return the list of intervals whose binding is {@code binding}
          */
         public Interval get(RegisterBinding binding) {
-            if (binding == RegisterBinding.Any) {
-                return any;
+            switch (binding) {
+                case Any:
+                    return any;
+                case Fixed:
+                    return fixed;
+                case Stack:
+                    return stack;
             }
-            assert binding == RegisterBinding.Fixed;
-            return fixed;
+            throw GraalInternalError.shouldNotReachHere();
         }
 
         /**
          * Sets the list for a specified binding.
-         * 
+         *
          * @param binding specifies the list to be replaced
          * @param list a list of intervals whose binding is {@code binding}
          */
         public void set(RegisterBinding binding, Interval list) {
             assert list != null;
-            if (binding == RegisterBinding.Any) {
-                any = list;
-            } else {
-                assert binding == RegisterBinding.Fixed;
-                fixed = list;
+            switch (binding) {
+                case Any:
+                    any = list;
+                    break;
+                case Fixed:
+                    fixed = list;
+                    break;
+                case Stack:
+                    stack = list;
+                    break;
             }
         }
 
         /**
          * Adds an interval to a list sorted by {@linkplain Interval#currentFrom() current from}
          * positions.
-         * 
+         *
          * @param binding specifies the list to be updated
          * @param interval the interval to add
          */
@@ -134,7 +149,7 @@
         /**
          * Adds an interval to a list sorted by {@linkplain Interval#from() start} positions and
          * {@linkplain Interval#firstUsage(RegisterPriority) first usage} positions.
-         * 
+         *
          * @param binding specifies the list to be updated
          * @param interval the interval to add
          */
@@ -157,7 +172,7 @@
 
         /**
          * Removes an interval from a list.
-         * 
+         *
          * @param binding specifies the list to be updated
          * @param i the interval to remove
          */
@@ -234,7 +249,12 @@
         /**
          * Interval has no specific register requirements.
          */
-        Any;
+        Any,
+
+        /**
+         * Interval is bound to a stack slot.
+         */
+        Stack;
 
         public static final RegisterBinding[] VALUES = values();
     }
@@ -310,7 +330,7 @@
      * List of use positions. Each entry in the list records the use position and register priority
      * associated with the use position. The entries in the list are in descending order of use
      * position.
-     * 
+     *
      */
     public static final class UsePosList {
 
@@ -318,7 +338,7 @@
 
         /**
          * Creates a use list.
-         * 
+         *
          * @param initialCapacity the initial capacity of the list in terms of entries
          */
         public UsePosList(int initialCapacity) {
@@ -333,7 +353,7 @@
          * Splits this list around a given position. All entries in this list with a use position
          * greater or equal than {@code splitPos} are removed from this list and added to the
          * returned list.
-         * 
+         *
          * @param splitPos the position for the split
          * @return a use position list containing all entries removed from this list that have a use
          *         position greater or equal than {@code splitPos}
@@ -355,7 +375,7 @@
 
         /**
          * Gets the use position at a specified index in this list.
-         * 
+         *
          * @param index the index of the entry for which the use position is returned
          * @return the use position of entry {@code index} in this list
          */
@@ -365,7 +385,7 @@
 
         /**
          * Gets the register priority for the use position at a specified index in this list.
-         * 
+         *
          * @param index the index of the entry for which the register priority is returned
          * @return the register priority of entry {@code index} in this list
          */
@@ -863,6 +883,32 @@
         return true;
     }
 
+    // returns the interval that covers the given opId or null if there is none
+    Interval getIntervalCoveringOpId(int opId) {
+        assert opId >= 0 : "invalid opId";
+        assert opId < to() : "can only look into the past";
+
+        if (opId >= from()) {
+            return this;
+        }
+
+        Interval parent = splitParent();
+        Interval result = null;
+
+        assert !parent.splitChildren.isEmpty() : "no split children available";
+        int len = parent.splitChildren.size();
+
+        for (int i = len - 1; i >= 0; i--) {
+            Interval cur = parent.splitChildren.get(i);
+            if (cur.from() <= opId && opId < cur.to()) {
+                assert result == null : "covered by multiple split children " + result + " and " + cur;
+                result = cur;
+            }
+        }
+
+        return result;
+    }
+
     // returns the last split child that ends before the given opId
     Interval getSplitChildBeforeOpId(int opId) {
         assert opId >= 0 : "invalid opId";
@@ -1044,7 +1090,7 @@
      * When a split child is split again, the new created interval is a direct child of the original
      * parent. That is, there is no tree of split children stored, just a flat list. All split
      * children are spilled to the same {@linkplain #spillSlot spill slot}.
-     * 
+     *
      * @param splitPos the position at which to split this interval
      * @param allocator the register allocator context
      * @return the child interval split off from this interval
@@ -1094,7 +1140,7 @@
     /**
      * Splits this interval at a specified position and returns the head as a new interval (this
      * interval is the tail).
-     * 
+     *
      * Currently, only the first range can be split, and the new interval must not have split
      * positions
      */
@@ -1196,7 +1242,7 @@
 
     /**
      * Gets a single line string for logging the details of this interval to a log stream.
-     * 
+     *
      * @param allocator the register allocator context
      */
     public String logString(LinearScan allocator) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/IntervalWalker.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/IntervalWalker.java	Tue May 27 21:20:01 2014 -0700
@@ -36,22 +36,17 @@
     /**
      * Sorted list of intervals, not live before the current position.
      */
-    RegisterBindingLists unhandledLists;
+    protected RegisterBindingLists unhandledLists;
 
     /**
      * Sorted list of intervals, live at the current position.
      */
-    RegisterBindingLists activeLists;
+    protected RegisterBindingLists activeLists;
 
     /**
      * Sorted list of intervals in a life time hole at the current position.
      */
-    RegisterBindingLists inactiveLists;
-
-    /**
-     * The current interval (taken from the unhandled list) being processed.
-     */
-    protected Interval currentInterval;
+    protected RegisterBindingLists inactiveLists;
 
     /**
      * The current position (intercept point through the intervals).
@@ -64,14 +59,12 @@
     protected RegisterBinding currentBinding;
 
     /**
-     * Processes the {@linkplain #currentInterval} interval in an attempt to allocate a physical
-     * register to it and thus allow it to be moved to a list of {@linkplain #activeLists active}
-     * intervals.
-     * 
-     * @return {@code true} if a register was allocated to the {@linkplain #currentInterval}
-     *         interval
+     * Processes the {@code currentInterval} interval in an attempt to allocate a physical register
+     * to it and thus allow it to be moved to a list of {@linkplain #activeLists active} intervals.
+     *
+     * @return {@code true} if a register was allocated to the {@code currentInterval} interval
      */
-    boolean activateCurrent() {
+    protected boolean activateCurrent(@SuppressWarnings({"unused"}) Interval currentInterval) {
         return true;
     }
 
@@ -85,7 +78,7 @@
 
     /**
      * Creates a new interval walker.
-     * 
+     *
      * @param allocator the register allocator context
      * @param unhandledFixed the list of unhandled {@linkplain RegisterBinding#Fixed fixed}
      *            intervals
@@ -95,15 +88,13 @@
     IntervalWalker(LinearScan allocator, Interval unhandledFixed, Interval unhandledAny) {
         this.allocator = allocator;
 
-        unhandledLists = new RegisterBindingLists(unhandledFixed, unhandledAny);
-        activeLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker);
-        inactiveLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker);
+        unhandledLists = new RegisterBindingLists(unhandledFixed, unhandledAny, Interval.EndMarker);
+        activeLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker, Interval.EndMarker);
+        inactiveLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker, Interval.EndMarker);
         currentPosition = -1;
-        currentInterval = null;
-        nextInterval();
     }
 
-    void removeFromList(Interval interval) {
+    protected void removeFromList(Interval interval) {
         if (interval.state == State.Active) {
             activeLists.remove(RegisterBinding.Any, interval);
         } else {
@@ -112,7 +103,7 @@
         }
     }
 
-    void walkTo(State state, int from) {
+    private void walkTo(State state, int from) {
         assert state == State.Active || state == State.Inactive : "wrong state";
         for (RegisterBinding binding : RegisterBinding.VALUES) {
             Interval prevprev = null;
@@ -176,7 +167,16 @@
         }
     }
 
-    void nextInterval() {
+    /**
+     * Get the next interval from {@linkplain #unhandledLists} which starts before or at
+     * {@code toOpId}. The returned interval is removed and {@link #currentBinding} is set.
+     *
+     * @postcondition all intervals in {@linkplain #unhandledLists} start after {@code toOpId}.
+     *
+     * @return The next interval or null if there is no {@linkplain #unhandledLists unhandled}
+     *         interval at position {@code toOpId}.
+     */
+    private Interval nextInterval(int toOpId) {
         RegisterBinding binding;
         Interval any = unhandledLists.any;
         Interval fixed = unhandledLists.fixed;
@@ -191,42 +191,61 @@
         } else if (fixed != Interval.EndMarker) {
             binding = RegisterBinding.Fixed;
         } else {
-            currentInterval = null;
-            return;
+            return null;
         }
+        Interval currentInterval = unhandledLists.get(binding);
+
+        if (toOpId < currentInterval.from()) {
+            return null;
+        }
+
         currentBinding = binding;
-        currentInterval = unhandledLists.get(binding);
         unhandledLists.set(binding, currentInterval.next);
         currentInterval.next = Interval.EndMarker;
         currentInterval.rewindRange();
+        return currentInterval;
     }
 
-    void walkTo(int toOpId) {
+    /**
+     * Walk up to {@code toOpId}.
+     *
+     * @postcondition {@link #currentPosition} is set to {@code toOpId}, {@link #activeLists} and
+     *                {@link #inactiveLists} are populated and {@link Interval#state}s are up to
+     *                date.
+     */
+    protected void walkTo(int toOpId) {
         assert currentPosition <= toOpId : "can not walk backwards";
-        while (currentInterval != null) {
-            boolean isActive = currentInterval.from() <= toOpId;
-            int opId = isActive ? currentInterval.from() : toOpId;
+        for (Interval currentInterval = nextInterval(toOpId); currentInterval != null; currentInterval = nextInterval(toOpId)) {
+            int opId = currentInterval.from();
 
             // set currentPosition prior to call of walkTo
             currentPosition = opId;
 
+            // update unhandled stack intervals
+            updateUnhandledStackIntervals(opId);
+
             // call walkTo even if currentPosition == id
             walkTo(State.Active, opId);
             walkTo(State.Inactive, opId);
 
-            if (isActive) {
-                try (Indent indent = Debug.logAndIndent("walk to op %d", opId)) {
-                    currentInterval.state = State.Active;
-                    if (activateCurrent()) {
-                        activeLists.addToListSortedByCurrentFromPositions(currentBinding, currentInterval);
-                        intervalMoved(currentInterval, State.Unhandled, State.Active);
-                    }
+            try (Indent indent = Debug.logAndIndent("walk to op %d", opId)) {
+                currentInterval.state = State.Active;
+                if (activateCurrent(currentInterval)) {
+                    activeLists.addToListSortedByCurrentFromPositions(currentBinding, currentInterval);
+                    intervalMoved(currentInterval, State.Unhandled, State.Active);
+                }
+            }
+        }
+        // set currentPosition prior to call of walkTo
+        currentPosition = toOpId;
 
-                    nextInterval();
-                }
-            } else {
-                return;
-            }
+        if (currentPosition <= allocator.maxOpId()) {
+            // update unhandled stack intervals
+            updateUnhandledStackIntervals(toOpId);
+
+            // call walkTo if still in range
+            walkTo(State.Active, toOpId);
+            walkTo(State.Inactive, toOpId);
         }
     }
 
@@ -237,4 +256,29 @@
             Debug.log("interval moved from %s to %s: %s", from, to, interval.logString(allocator));
         }
     }
+
+    /**
+     * Move {@linkplain #unhandledLists unhandled} stack intervals to
+     * {@linkplain IntervalWalker #activeLists active}.
+     *
+     * Note that for {@linkplain RegisterBinding#Fixed fixed} and {@linkplain RegisterBinding#Any
+     * any} intervals this is done in {@link #nextInterval(int)}.
+     */
+    private void updateUnhandledStackIntervals(int opId) {
+        Interval currentInterval = unhandledLists.get(RegisterBinding.Stack);
+        while (currentInterval != Interval.EndMarker && currentInterval.from() <= opId) {
+            Interval next = currentInterval.next;
+            if (currentInterval.to() > opId) {
+                currentInterval.state = State.Active;
+                activeLists.addToListSortedByCurrentFromPositions(RegisterBinding.Stack, currentInterval);
+                intervalMoved(currentInterval, State.Unhandled, State.Active);
+            } else {
+                currentInterval.state = State.Handled;
+                intervalMoved(currentInterval, State.Unhandled, State.Handled);
+            }
+            currentInterval = next;
+        }
+        unhandledLists.set(RegisterBinding.Stack, currentInterval);
+    }
+
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Tue May 27 21:20:01 2014 -0700
@@ -1396,7 +1396,12 @@
             notPrecoloredIntervals = result.second;
 
             // allocate cpu registers
-            LinearScanWalker lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals);
+            LinearScanWalker lsw;
+            if (OptimizingLinearScanWalker.Options.LSRAOptimization.getValue()) {
+                lsw = new OptimizingLinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals);
+            } else {
+                lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals);
+            }
             lsw.walk();
             lsw.finishAllocation();
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Tue May 27 21:20:01 2014 -0700
@@ -42,14 +42,14 @@
 
 /**
  */
-final class LinearScanWalker extends IntervalWalker {
+class LinearScanWalker extends IntervalWalker {
 
-    private Register[] availableRegs;
+    protected Register[] availableRegs;
 
-    private final int[] usePos;
-    private final int[] blockPos;
+    protected final int[] usePos;
+    protected final int[] blockPos;
 
-    private List<Interval>[] spillIntervals;
+    protected List<Interval>[] spillIntervals;
 
     private MoveResolver moveResolver; // for ordering spill moves
 
@@ -430,7 +430,7 @@
 
             splitPart.setInsertMoveWhenActivated(moveNecessary);
 
-            assert splitPart.from() >= currentInterval.currentFrom() : "cannot append new interval before current walk position";
+            assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
             unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart);
 
             if (Debug.isLogEnabled()) {
@@ -466,6 +466,7 @@
                     assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition";
 
                     allocator.assignSpillSlot(interval);
+                    handleSpillSlot(interval);
                     allocator.changeSpillState(interval, minSplitPos);
 
                     // Also kick parent intervals out of register to memory when they have no use
@@ -480,6 +481,7 @@
                                 // parent is never used, so kick it out of its assigned register
                                 Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
                                 allocator.assignSpillSlot(parent);
+                                handleSpillSlot(parent);
                             } else {
                                 // do not go further back because the register is actually used by
                                 // the interval
@@ -508,6 +510,7 @@
 
                     Interval spilledPart = interval.split(optimalSplitPos, allocator);
                     allocator.assignSpillSlot(spilledPart);
+                    handleSpillSlot(spilledPart);
                     allocator.changeSpillState(spilledPart, optimalSplitPos);
 
                     if (!allocator.isBlockBegin(optimalSplitPos)) {
@@ -528,6 +531,14 @@
         }
     }
 
+    /**
+     * This is called for every interval that is assigned to a stack slot.
+     */
+    protected void handleSpillSlot(Interval interval) {
+        assert interval.location() != null && (interval.canMaterialize() || isStackSlot(interval.location())) : "interval not assigned to a stack slot " + interval;
+        // Do nothing. Stack slots are not processed in this implementation.
+    }
+
     void splitStackInterval(Interval interval) {
         int minSplitPos = currentPosition + 1;
         int maxSplitPos = Math.min(interval.firstUsage(RegisterPriority.ShouldHaveRegister), interval.to());
@@ -836,8 +847,7 @@
 
     // allocate a physical register or memory location to an interval
     @Override
-    boolean activateCurrent() {
-        Interval interval = currentInterval;
+    protected boolean activateCurrent(Interval interval) {
         boolean result = true;
 
         try (Indent indent = Debug.logAndIndent("activating interval %s,  splitParent: %d", interval, interval.splitParent().operandNumber)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/OptimizingLinearScanWalker.java	Tue May 27 21:20:01 2014 -0700
@@ -0,0 +1,247 @@
+/*
+ * 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.alloc;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.alloc.Interval.RegisterBinding;
+import com.oracle.graal.compiler.alloc.Interval.RegisterBindingLists;
+import com.oracle.graal.compiler.alloc.Interval.State;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.options.*;
+
+public class OptimizingLinearScanWalker extends LinearScanWalker {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable LSRA optimization")
+        public static final OptionValue<Boolean> LSRAOptimization = new OptionValue<>(true);
+        @Option(help = "LSRA optimization: Only split but do not reassign")
+        public static final OptionValue<Boolean> LSRAOptSplitOnly = new OptionValue<>(false);
+        // @formatter:on
+    }
+
+    OptimizingLinearScanWalker(LinearScan allocator, Interval unhandledFixedFirst, Interval unhandledAnyFirst) {
+        super(allocator, unhandledFixedFirst, unhandledAnyFirst);
+    }
+
+    @Override
+    protected void handleSpillSlot(Interval interval) {
+        assert interval.location() != null : "interval  not assigned " + interval;
+        if (interval.canMaterialize()) {
+            assert !isStackSlot(interval.location()) : "interval can materialize but assigned to a stack slot " + interval;
+            return;
+        }
+        assert isStackSlot(interval.location()) : "interval not assigned to a stack slot " + interval;
+        try (Scope s1 = Debug.scope("LSRAOptimization")) {
+            Debug.log("adding stack to unhandled list %s", interval);
+            unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Stack, interval);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static void printRegisterBindingList(RegisterBindingLists list, RegisterBinding binding) {
+        for (Interval interval = list.get(binding); interval != Interval.EndMarker; interval = interval.next) {
+            Debug.log("%s", interval);
+        }
+    }
+
+    @Override
+    void walk() {
+        try (Scope s = Debug.scope("OptimizingLinearScanWalker")) {
+            for (AbstractBlock<?> block : allocator.sortedBlocks) {
+                int nextBlock = allocator.getFirstLirInstructionId(block);
+                try (Scope s1 = Debug.scope("LSRAOptimization")) {
+                    Debug.log("next block: %s (%d)", block, nextBlock);
+                }
+                try (Indent indent0 = Debug.indent()) {
+                    walkTo(nextBlock);
+
+                    try (Scope s1 = Debug.scope("LSRAOptimization")) {
+                        boolean changed = true;
+                        // we need to do this because the active lists might change
+                        loop: while (changed) {
+                            changed = false;
+                            try (Indent indent1 = Debug.logAndIndent("Active intervals: (block %s [%d])", block, nextBlock)) {
+                                for (Interval active = activeLists.get(RegisterBinding.Any); active != Interval.EndMarker; active = active.next) {
+                                    Debug.log("active   (any): %s", active);
+                                    if (optimize(nextBlock, block, active, RegisterBinding.Any)) {
+                                        changed = true;
+                                        break loop;
+                                    }
+                                }
+                                for (Interval active = activeLists.get(RegisterBinding.Stack); active != Interval.EndMarker; active = active.next) {
+                                    Debug.log("active (stack): %s", active);
+                                    if (optimize(nextBlock, block, active, RegisterBinding.Stack)) {
+                                        changed = true;
+                                        break loop;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        super.walk();
+    }
+
+    private boolean optimize(int currentPos, AbstractBlock<?> currentBlock, Interval currentInterval, RegisterBinding binding) {
+        // BEGIN initialize and sanity checks
+        assert currentBlock != null : "block must not be null";
+        assert currentInterval != null : "interval must not be null";
+
+        if (currentBlock.getPredecessorCount() != 1) {
+            // more than one predecessors -> optimization not possible
+            return false;
+        }
+        if (!currentInterval.isSplitChild()) {
+            // interval is not a split child -> no need for optimization
+            return false;
+        }
+
+        if (currentInterval.from() == currentPos) {
+            // the interval starts at the current position so no need for splitting
+            return false;
+        }
+
+        // get current location
+        AllocatableValue currentLocation = currentInterval.location();
+        assert currentLocation != null : "active intervals must have a location assigned!";
+
+        // get predecessor stuff
+        AbstractBlock<?> predecessorBlock = currentBlock.getPredecessors().get(0);
+        int predEndId = allocator.getLastLirInstructionId(predecessorBlock);
+        Interval predecessorInterval = currentInterval.getIntervalCoveringOpId(predEndId);
+        assert predecessorInterval != null : "variable not live at the end of the only predecessor! " + predecessorBlock + " -> " + currentBlock + " interval: " + currentInterval;
+        AllocatableValue predecessorLocation = predecessorInterval.location();
+        assert predecessorLocation != null : "handled intervals must have a location assigned!";
+
+        // END initialize and sanity checks
+
+        if (currentLocation.equals(predecessorLocation)) {
+            // locations are already equal -> nothing to optimize
+            return false;
+        }
+
+        if (!isStackSlot(predecessorLocation) && !isRegister(predecessorLocation)) {
+            assert predecessorInterval.canMaterialize();
+            // value is materialized -> no need for optimization
+            return false;
+        }
+
+        assert isStackSlot(currentLocation) || isRegister(currentLocation) : "current location not a register or stack slot " + currentLocation;
+
+        try (Indent indent = Debug.logAndIndent("location differs: %s vs. %s", predecessorLocation, currentLocation)) {
+            // split current interval at current position
+            Debug.log("splitting at position %d", currentPos);
+
+            assert allocator.isBlockBegin(currentPos) && ((currentPos & 1) == 0) : "split pos must be even when on block boundary";
+
+            Interval splitPart = currentInterval.split(currentPos, allocator);
+            activeLists.remove(binding, currentInterval);
+
+            assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
+
+            // the currentSplitChild is needed later when moves are inserted for reloading
+            assert splitPart.currentSplitChild() == currentInterval : "overwriting wrong currentSplitChild";
+            splitPart.makeCurrentSplitChild();
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("left interval  : %s", currentInterval.logString(allocator));
+                Debug.log("right interval : %s", splitPart.logString(allocator));
+            }
+
+            if (Options.LSRAOptSplitOnly.getValue()) {
+                // just add the split interval to the unhandled list
+                unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart);
+            } else {
+                if (isRegister(predecessorLocation)) {
+                    splitRegisterInterval(splitPart, asRegister(predecessorLocation));
+                } else {
+                    assert isStackSlot(predecessorLocation);
+                    Debug.log("assigning interval %s to %s", splitPart, predecessorLocation);
+                    splitPart.assignLocation(predecessorLocation);
+                    // activate interval
+                    activeLists.addToListSortedByCurrentFromPositions(RegisterBinding.Stack, splitPart);
+                    splitPart.state = State.Active;
+
+                    splitStackInterval(splitPart);
+                }
+            }
+        }
+        return true;
+    }
+
+    private void splitRegisterInterval(Interval interval, Register reg) {
+        // collect current usage of registers
+        initVarsForAlloc(interval);
+        initUseLists(false);
+        spillExcludeActiveFixed();
+        // spillBlockUnhandledFixed(cur);
+        assert unhandledLists.get(RegisterBinding.Fixed) == Interval.EndMarker : "must not have unhandled fixed intervals because all fixed intervals have a use at position 0";
+        spillBlockInactiveFixed(interval);
+        spillCollectActiveAny();
+        spillCollectInactiveAny(interval);
+
+        if (Debug.isLogEnabled()) {
+            try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
+                for (Register register : availableRegs) {
+                    int i = register.number;
+                    try (Indent indent3 = Debug.logAndIndent("reg %d: usePos: %d, blockPos: %d, intervals: ", i, usePos[i], blockPos[i])) {
+                        for (int j = 0; j < spillIntervals[i].size(); j++) {
+                            Debug.log("%d ", spillIntervals[i].get(j).operandNumber);
+                        }
+                    }
+                }
+            }
+        }
+
+        // the register must be free at least until this position
+        boolean needSplit = blockPos[reg.number] <= interval.to();
+
+        int splitPos = blockPos[reg.number];
+
+        assert splitPos > 0 : "invalid splitPos";
+        assert needSplit || splitPos > interval.from() : "splitting interval at from";
+
+        Debug.log("assigning interval %s to %s", interval, reg);
+        interval.assignLocation(reg.asValue(interval.kind()));
+        if (needSplit) {
+            // register not available for full interval : so split it
+            splitWhenPartialRegisterAvailable(interval, splitPos);
+        }
+
+        // perform splitting and spilling for all affected intervals
+        splitAndSpillIntersectingIntervals(reg);
+
+        // activate interval
+        activeLists.addToListSortedByCurrentFromPositions(RegisterBinding.Any, interval);
+        interval.state = State.Active;
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java	Tue May 27 21:20:01 2014 -0700
@@ -0,0 +1,137 @@
+/*
+ * 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.graph.test;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.graal.graph.*;
+
+public class NodeMapTest {
+
+    private static class TestNode extends Node {
+    }
+
+    private Graph graph;
+    private TestNode[] nodes = new TestNode[100];
+    private NodeMap<Integer> map;
+
+    @Before
+    public void before() {
+        graph = new Graph();
+        for (int i = 0; i < nodes.length; i++) {
+            nodes[i] = graph.add(new TestNode());
+        }
+        map = new NodeMap<>(graph);
+        for (int i = 0; i < nodes.length; i += 2) {
+            map.set(nodes[i], i);
+        }
+    }
+
+    @Test
+    public void testEmpty() {
+        NodeMap<Integer> emptyMap = new NodeMap<>(graph);
+        for (TestNode node : nodes) {
+            assertEquals(null, emptyMap.get(node));
+        }
+    }
+
+    @Test
+    public void testSimple() {
+        for (int i = 0; i < nodes.length; i++) {
+            if ((i & 1) == 0) {
+                assertEquals((Integer) i, map.get(nodes[i]));
+            } else {
+                assertEquals(null, map.get(nodes[i]));
+            }
+        }
+    }
+
+    @Test
+    public void testSimpleChanged() {
+        for (TestNode node : nodes) {
+            map.set(node, 1);
+        }
+        for (TestNode node : nodes) {
+            map.set(node, null);
+        }
+        for (int i = 0; i < nodes.length; i += 2) {
+            map.set(nodes[i], i);
+        }
+
+        for (int i = 0; i < nodes.length; i++) {
+            if ((i & 1) == 0) {
+                assertEquals((Integer) i, map.get(nodes[i]));
+            } else {
+                assertEquals(null, map.get(nodes[i]));
+            }
+        }
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testNewGet() {
+        /*
+         * Failing here is not required, but if this behavior changes, usages of get need to be
+         * checked for compatibility.
+         */
+        TestNode newNode = graph.add(new TestNode());
+        map.get(newNode);
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testNewSet() {
+        /*
+         * Failing here is not required, but if this behavior changes, usages of set need to be
+         * checked for compatibility.
+         */
+        TestNode newNode = graph.add(new TestNode());
+        map.set(newNode, 1);
+    }
+
+    @Test
+    public void testNewGetAndGrow() {
+        TestNode newNode = graph.add(new TestNode());
+        assertEquals(null, map.getAndGrow(newNode));
+    }
+
+    @Test
+    public void testNewSetAndGrow() {
+        TestNode newNode = graph.add(new TestNode());
+        map.setAndGrow(newNode, 1);
+        assertEquals((Integer) 1, map.get(newNode));
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testNewSetAndGrowMultiple() {
+        TestNode newNode = graph.add(new TestNode());
+        map.setAndGrow(newNode, 1);
+        assertEquals((Integer) 1, map.get(newNode));
+        /*
+         * Failing here is not required, but if this behavior changes, usages of getAndGrow and
+         * setAndGrow need to be checked for compatibility.
+         */
+        TestNode newNode2 = graph.add(new TestNode());
+        map.get(newNode2);
+    }
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Tue May 27 21:20:01 2014 -0700
@@ -46,6 +46,19 @@
         return (T) values[getNodeId(node)];
     }
 
+    @SuppressWarnings("unchecked")
+    public T getAndGrow(Node node) {
+        checkAndGrow(node);
+        return (T) values[getNodeId(node)];
+    }
+
+    private void checkAndGrow(Node node) {
+        if (isNew(node)) {
+            this.values = Arrays.copyOf(values, graph.nodeIdCount());
+        }
+        assert check(node);
+    }
+
     public boolean isEmpty() {
         return !entries().iterator().hasNext();
     }
@@ -78,6 +91,11 @@
         values[getNodeId(node)] = value;
     }
 
+    public void setAndGrow(Node node, T value) {
+        checkAndGrow(node);
+        values[getNodeId(node)] = value;
+    }
+
     public int size() {
         return values.length;
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue May 27 21:20:01 2014 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer.*;
+
 import java.util.*;
 
 import com.oracle.graal.amd64.*;
@@ -30,6 +32,7 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
@@ -98,26 +101,65 @@
         assert host == null;
         TargetDescription target = createTarget(runtime.getConfig());
 
-        HotSpotRegistersProvider registers = createRegisters();
-        HotSpotMetaAccessProvider metaAccess = createMetaAccess(runtime);
-        HotSpotCodeCacheProvider codeCache = createCodeCache(runtime, target);
-        HotSpotConstantReflectionProvider constantReflection = createConstantReflection(runtime);
-        Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig());
-        HotSpotHostForeignCallsProvider foreignCalls = createForeignCalls(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters);
-        HotSpotLoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, target);
-        // Replacements cannot have speculative optimizations since they have
-        // to be valid for the entire run of the VM.
-        Assumptions assumptions = new Assumptions(false);
-        Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null);
-        HotSpotSnippetReflectionProvider snippetReflection = createSnippetReflection();
-        Replacements replacements = createReplacements(runtime, assumptions, p, snippetReflection);
-        HotSpotDisassemblerProvider disassembler = createDisassembler(runtime);
-        HotSpotSuitesProvider suites = createSuites(runtime);
-        HotSpotMethodHandleAccessProvider methodHandleAccess = new HotSpotMethodHandleAccessProvider();
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection,
-                        methodHandleAccess);
-
-        return createBackend(runtime, providers);
+        HotSpotProviders providers;
+        HotSpotRegistersProvider registers;
+        HotSpotCodeCacheProvider codeCache;
+        HotSpotConstantReflectionProvider constantReflection;
+        HotSpotHostForeignCallsProvider foreignCalls;
+        Value[] nativeABICallerSaveRegisters;
+        HotSpotMetaAccessProvider metaAccess;
+        HotSpotLoweringProvider lowerer;
+        HotSpotSnippetReflectionProvider snippetReflection;
+        Replacements replacements;
+        HotSpotDisassemblerProvider disassembler;
+        HotSpotSuitesProvider suites;
+        HotSpotMethodHandleAccessProvider methodHandleAccess;
+        try (InitTimer t = timer("create providers")) {
+            try (InitTimer rt = timer("create HotSpotRegisters provider")) {
+                registers = createRegisters();
+            }
+            try (InitTimer rt = timer("create MetaAccess provider")) {
+                metaAccess = createMetaAccess(runtime);
+            }
+            try (InitTimer rt = timer("create CodeCache provider")) {
+                codeCache = createCodeCache(runtime, target);
+            }
+            try (InitTimer rt = timer("create ConstantReflection provider")) {
+                constantReflection = createConstantReflection(runtime);
+            }
+            try (InitTimer rt = timer("create NativeABICallerSaveRegisters")) {
+                nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig());
+            }
+            try (InitTimer rt = timer("create ForeignCalls provider")) {
+                foreignCalls = createForeignCalls(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters);
+            }
+            try (InitTimer rt = timer("create Lowerer provider")) {
+                lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, target);
+            }
+            // Replacements cannot have speculative optimizations since they have
+            // to be valid for the entire run of the VM.
+            Assumptions assumptions = new Assumptions(false);
+            Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null);
+            try (InitTimer rt = timer("create SnippetReflection provider")) {
+                snippetReflection = createSnippetReflection();
+            }
+            try (InitTimer rt = timer("create Replacements provider")) {
+                replacements = createReplacements(runtime, assumptions, p, snippetReflection);
+            }
+            try (InitTimer rt = timer("create Disassembler provider")) {
+                disassembler = createDisassembler(runtime);
+            }
+            try (InitTimer rt = timer("create Suites provider")) {
+                suites = createSuites(runtime);
+            }
+            try (InitTimer rt = timer("create MethodHandleAccess provider")) {
+                methodHandleAccess = new HotSpotMethodHandleAccessProvider();
+            }
+            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection, methodHandleAccess);
+        }
+        try (InitTimer rt = timer("instantiate backend")) {
+            return createBackend(runtime, providers);
+        }
     }
 
     protected AMD64HotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompare.java	Tue May 27 21:20:01 2014 -0700
@@ -0,0 +1,150 @@
+/*
+ * 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.api.code.ValueUtil.*;
+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.common.*;
+import com.oracle.graal.hotspot.data.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.type.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64Move.MemOp;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64HotSpotCompare {
+
+    @Opcode("NCMP")
+    public static class HotSpotCompareNarrowOp extends AMD64LIRInstruction {
+
+        @Use({REG}) protected AllocatableValue x;
+        @Use({REG, STACK}) protected AllocatableValue y;
+
+        public HotSpotCompareNarrowOp(AllocatableValue x, AllocatableValue y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(y)) {
+                masm.cmpl(asRegister(x), asRegister(y));
+            } else {
+                assert isStackSlot(y);
+                masm.cmpl(asRegister(x), (AMD64Address) crb.asAddress(y));
+            }
+        }
+
+        @Override
+        protected void verify() {
+            assert x.getPlatformKind() == NarrowOopStamp.NarrowOop && y.getPlatformKind() == NarrowOopStamp.NarrowOop;
+        }
+    }
+
+    @Opcode("CMP")
+    public static class HotSpotCompareConstantOp extends AMD64LIRInstruction {
+
+        @Use({REG}) protected AllocatableValue x;
+        protected Constant y;
+
+        public HotSpotCompareConstantOp(AllocatableValue x, Constant y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            assert isRegister(x);
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(y)) {
+                // compressed null
+                masm.testl(asRegister(x), asRegister(x));
+            } else if (y instanceof HotSpotObjectConstant) {
+                if (HotSpotObjectConstant.isCompressed(y)) {
+                    // compressed oop
+                    crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(y), true));
+                    masm.cmpl(asRegister(x), 0xDEADDEAD);
+                } else {
+                    // uncompressed oop
+                    AMD64Address patch = (AMD64Address) crb.recordDataReferenceInCode(new OopData(8, HotSpotObjectConstant.asObject(y), false));
+                    masm.cmpq(asRegister(x), patch);
+                }
+            } else if (y instanceof HotSpotMetaspaceConstant) {
+                if (y.getKind() == Kind.Int) {
+                    // compressed metaspace pointer
+                    crb.recordInlineDataInCode(new MetaspaceData(0, y.asInt(), HotSpotMetaspaceConstant.getMetaspaceObject(y), true));
+                    masm.cmpl(asRegister(x), y.asInt());
+                } else {
+                    // uncompressed metaspace pointer
+                    AMD64Address patch = (AMD64Address) crb.recordDataReferenceInCode(new MetaspaceData(8, y.asLong(), HotSpotObjectConstant.asObject(y), false));
+                    masm.cmpq(asRegister(x), patch);
+                }
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    @Opcode("CMP")
+    public static class HotSpotCompareMemoryConstantOp extends MemOp {
+
+        protected Constant y;
+
+        public HotSpotCompareMemoryConstantOp(Kind kind, AMD64AddressValue x, Constant y, LIRFrameState state) {
+            super(kind, x, state);
+            this.y = y;
+        }
+
+        @Override
+        protected void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(y)) {
+                // compressed null
+                masm.cmpl(address.toAddress(), 0);
+            } else if (y instanceof HotSpotObjectConstant) {
+                if (HotSpotObjectConstant.isCompressed(y) && crb.target.inlineObjects) {
+                    // compressed oop
+                    crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(y), true));
+                    masm.cmpl(address.toAddress(), 0xDEADDEAD);
+                } else {
+                    // uncompressed oop
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+            } else if (y instanceof HotSpotMetaspaceConstant) {
+                if (y.getKind() == Kind.Int) {
+                    // compressed metaspace pointer
+                    crb.recordInlineDataInCode(new MetaspaceData(0, y.asInt(), HotSpotMetaspaceConstant.getMetaspaceObject(y), true));
+                    masm.cmpl(address.toAddress(), y.asInt());
+                } else {
+                    // uncompressed metaspace pointer
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Tue May 27 21:20:01 2014 -0700
@@ -26,13 +26,12 @@
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.api.meta.Value.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
 import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
-import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.*;
 import static com.oracle.graal.hotspot.replacements.CRC32Substitutions.*;
-import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue May 27 21:20:01 2014 -0700
@@ -24,8 +24,8 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import java.util.*;
@@ -39,6 +39,7 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
+import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.HotSpotStoreConstantOp;
 import com.oracle.graal.hotspot.data.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -55,7 +56,6 @@
 import com.oracle.graal.lir.amd64.AMD64Move.LoadOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
-import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.gen.*;
@@ -480,7 +480,7 @@
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
             if (canStoreConstant(c, false)) {
-                append(new StoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
+                append(new HotSpotStoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
                 return;
             }
         }
@@ -499,8 +499,7 @@
             Variable result = newVariable(Kind.Int);
             AllocatableValue base = Value.ILLEGAL;
             if (encoding.base != 0) {
-                base = newVariable(Kind.Long);
-                append(new AMD64Move.MoveToRegOp(Kind.Long, base, Constant.forLong(encoding.base)));
+                base = emitMove(Constant.forLong(encoding.base));
             }
             append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
             return result;
@@ -518,8 +517,7 @@
             Variable result = newVariable(Kind.Long);
             AllocatableValue base = Value.ILLEGAL;
             if (encoding.base != 0) {
-                base = newVariable(Kind.Long);
-                append(new AMD64Move.MoveToRegOp(Kind.Long, base, Constant.forLong(encoding.base)));
+                base = emitMove(Constant.forLong(encoding.base));
             }
             append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
             return result;
@@ -528,7 +526,9 @@
 
     @Override
     protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) {
-        if (dst.getPlatformKind() == NarrowOopStamp.NarrowOop) {
+        if (src instanceof Constant) {
+            return new AMD64HotSpotMove.HotSpotLoadConstantOp(dst, (Constant) src);
+        } else if (dst.getPlatformKind() == NarrowOopStamp.NarrowOop) {
             if (isRegister(src) || isStackSlot(dst)) {
                 return new MoveFromRegOp(Kind.Int, dst, src);
             } else {
@@ -641,4 +641,35 @@
         assert address.getKind() == Kind.Object : address + " - " + address.getKind() + " not an object!";
         append(new AMD64Move.NullCheckOp(load(address), state));
     }
+
+    @Override
+    protected void emitCompareOp(PlatformKind cmpKind, Variable left, Value right) {
+        if (right instanceof HotSpotConstant) {
+            append(new AMD64HotSpotCompare.HotSpotCompareConstantOp(left, (Constant) right));
+        } else if (cmpKind == NarrowOopStamp.NarrowOop) {
+            append(new AMD64HotSpotCompare.HotSpotCompareNarrowOp(left, asAllocatable(right)));
+        } else {
+            super.emitCompareOp(cmpKind, left, right);
+        }
+    }
+
+    @Override
+    protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, Constant value, LIRFrameState state) {
+        if (value instanceof HotSpotConstant) {
+            append(new AMD64HotSpotCompare.HotSpotCompareMemoryConstantOp(kind, address, value, state));
+        } else {
+            super.emitCompareMemoryConOp(kind, address, value, state);
+        }
+    }
+
+    @Override
+    public boolean canInlineConstant(Constant c) {
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+            return true;
+        } else if (c instanceof HotSpotObjectConstant) {
+            return HotSpotObjectConstant.isCompressed(c);
+        } else {
+            return super.canInlineConstant(c);
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java	Tue May 27 21:20:01 2014 -0700
@@ -36,6 +36,7 @@
 import com.oracle.graal.hotspot.data.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.amd64.AMD64Move.LoadOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp;
@@ -75,6 +76,125 @@
         }
     }
 
+    public static class HotSpotLoadConstantOp extends AMD64LIRInstruction implements MoveOp {
+
+        @Def({REG, STACK}) private AllocatableValue result;
+        private final Constant input;
+
+        public HotSpotLoadConstantOp(AllocatableValue result, Constant input) {
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(input)) {
+                if (isRegister(result)) {
+                    masm.movl(asRegister(result), 0);
+                } else {
+                    assert isStackSlot(result);
+                    masm.movl((AMD64Address) crb.asAddress(result), 0);
+                }
+            } else if (input instanceof HotSpotObjectConstant) {
+                boolean compressed = HotSpotObjectConstant.isCompressed(input);
+                OopData data = new OopData(compressed ? 4 : 8, HotSpotObjectConstant.asObject(input), compressed);
+                if (crb.target.inlineObjects) {
+                    crb.recordInlineDataInCode(data);
+                    if (isRegister(result)) {
+                        if (compressed) {
+                            masm.movl(asRegister(result), 0xDEADDEAD);
+                        } else {
+                            masm.movq(asRegister(result), 0xDEADDEADDEADDEADL);
+                        }
+                    } else {
+                        assert isStackSlot(result);
+                        if (compressed) {
+                            masm.movl((AMD64Address) crb.asAddress(result), 0xDEADDEAD);
+                        } else {
+                            throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                        }
+                    }
+                } else {
+                    if (isRegister(result)) {
+                        AMD64Address address = (AMD64Address) crb.recordDataReferenceInCode(data);
+                        if (compressed) {
+                            masm.movl(asRegister(result), address);
+                        } else {
+                            masm.movq(asRegister(result), address);
+                        }
+                    } else {
+                        throw GraalInternalError.shouldNotReachHere("Cannot directly store data patch to memory");
+                    }
+                }
+            } else if (input instanceof HotSpotMetaspaceConstant) {
+                assert input.getKind() == Kind.Int || input.getKind() == Kind.Long;
+                boolean compressed = input.getKind() == Kind.Int;
+                MetaspaceData data = new MetaspaceData(compressed ? 4 : 8, input.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(input), compressed);
+                crb.recordInlineDataInCode(data);
+                if (isRegister(result)) {
+                    if (compressed) {
+                        masm.movl(asRegister(result), input.asInt());
+                    } else {
+                        masm.movq(asRegister(result), input.asLong());
+                    }
+                } else {
+                    assert isStackSlot(result);
+                    if (compressed) {
+                        masm.movl((AMD64Address) crb.asAddress(result), input.asInt());
+                    } else {
+                        throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                    }
+                }
+            } else {
+                AMD64Move.move(crb, masm, result, input);
+            }
+        }
+
+        public Value getInput() {
+            return input;
+        }
+
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    public static class HotSpotStoreConstantOp extends StoreConstantOp {
+
+        public HotSpotStoreConstantOp(Kind kind, AMD64AddressValue address, Constant input, LIRFrameState state) {
+            super(kind, address, input, state);
+        }
+
+        @Override
+        public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (input.isNull() && kind == Kind.Int) {
+                // compressed null
+                masm.movl(address.toAddress(), 0);
+            } else if (input instanceof HotSpotObjectConstant) {
+                if (HotSpotObjectConstant.isCompressed(input) && crb.target.inlineObjects) {
+                    // compressed oop
+                    crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(input), true));
+                    masm.movl(address.toAddress(), 0xDEADDEAD);
+                } else {
+                    // uncompressed oop
+                    throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                }
+            } else if (input instanceof HotSpotMetaspaceConstant) {
+                if (input.getKind() == Kind.Int) {
+                    // compressed metaspace pointer
+                    crb.recordInlineDataInCode(new MetaspaceData(0, input.asInt(), HotSpotMetaspaceConstant.getMetaspaceObject(input), true));
+                    masm.movl(address.toAddress(), input.asInt());
+                } else {
+                    // uncompressed metaspace pointer
+                    throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                }
+            } else {
+                // primitive value
+                super.emitMemAccess(crb, masm);
+            }
+        }
+    }
+
     public static class CompressPointer extends AMD64LIRInstruction {
 
         private final CompressEncoding encoding;
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Tue May 27 21:20:01 2014 -0700
@@ -94,7 +94,16 @@
 
     @Override
     public boolean canStoreConstant(Constant c, boolean isCompressed) {
-        return true;
+        return !(c instanceof HotSpotObjectConstant);
+    }
+
+    @Override
+    public boolean canInlineConstant(Constant c) {
+        if (c instanceof HotSpotObjectConstant) {
+            return c.isNull();
+        } else {
+            return super.canInlineConstant(c);
+        }
     }
 
     private static Kind getMemoryKind(PlatformKind kind) {
@@ -122,6 +131,9 @@
         HSAILAddressValue storeAddress = asAddressValue(address);
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+                c = Constant.INT_0;
+            }
             if (canStoreConstant(c, false)) {
                 append(new StoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
                 return;
@@ -224,7 +236,18 @@
     @Override
     protected HSAILLIRInstruction createMove(AllocatableValue dst, Value src) {
         if (dst.getPlatformKind() == NarrowOopStamp.NarrowOop) {
-            if (isRegister(src) || isStackSlot(dst)) {
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(src)) {
+                return new MoveToRegOp(Kind.Int, dst, Constant.INT_0);
+            } else if (src instanceof HotSpotObjectConstant) {
+                if (HotSpotObjectConstant.isCompressed((Constant) src)) {
+                    Variable uncompressed = newVariable(Kind.Object);
+                    append(new MoveToRegOp(Kind.Object, uncompressed, src));
+                    CompressEncoding oopEncoding = config.getOopEncoding();
+                    return new HSAILMove.CompressPointer(dst, newVariable(Kind.Object), uncompressed, oopEncoding.base, oopEncoding.shift, oopEncoding.alignment, true);
+                } else {
+                    return new MoveToRegOp(Kind.Object, dst, src);
+                }
+            } else if (isRegister(src) || isStackSlot(dst)) {
                 return new MoveFromRegOp(Kind.Int, dst, src);
             } else {
                 return new MoveToRegOp(Kind.Int, dst, src);
@@ -291,5 +314,4 @@
         emitMove(obj, address);
         append(new HSAILMove.NullCheckOp(obj, state));
     }
-
 }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Tue May 27 21:20:01 2014 -0700
@@ -59,16 +59,16 @@
 
     public void completeInitialization() {
         // Register the substitutions for java.lang.Math routines.
-        registerSubstitutions(HSAILMathSubstitutions.class);
+        registerSubstitutions(Math.class, HSAILMathSubstitutions.class);
 
         // Register the ignored substitutions
         addIgnoredResolvedMethod(String.class, "equals", Object.class);
     }
 
     @Override
-    protected ResolvedJavaMethod registerMethodSubstitution(Member originalMethod, Method substituteMethod) {
+    protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Member originalMethod, Method substituteMethod) {
         // TODO: decide if we want to override this in any way
-        return super.registerMethodSubstitution(originalMethod, substituteMethod);
+        return super.registerMethodSubstitution(cr, originalMethod, substituteMethod);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java	Tue May 27 21:20:01 2014 -0700
@@ -22,10 +22,13 @@
  */
 package com.oracle.graal.hotspot.ptx;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -37,19 +40,50 @@
 
     public HotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotBackend hostBackend) {
         HotSpotProviders host = hostBackend.getProviders();
-
-        HotSpotMetaAccessProvider metaAccess = host.getMetaAccess();
-        PTXHotSpotCodeCacheProvider codeCache = new PTXHotSpotCodeCacheProvider(runtime, createTarget());
-        ConstantReflectionProvider constantReflection = host.getConstantReflection();
-        HotSpotForeignCallsProvider foreignCalls = new PTXHotSpotForeignCallsProvider();
-        LoweringProvider lowerer = new PTXHotSpotLoweringProvider(host.getLowerer());
-        Replacements replacements = host.getReplacements();
-        HotSpotDisassemblerProvider disassembler = host.getDisassembler();
-        SuitesProvider suites = new DefaultSuitesProvider();
-        HotSpotRegistersProvider registers = new HotSpotRegisters(PTX.tid, Register.None, Register.None);
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection(),
-                        host.getMethodHandleAccess());
-        return new PTXHotSpotBackend(runtime, providers);
+        HotSpotMetaAccessProvider metaAccess;
+        PTXHotSpotCodeCacheProvider codeCache;
+        ConstantReflectionProvider constantReflection;
+        HotSpotForeignCallsProvider foreignCalls;
+        LoweringProvider lowerer;
+        Replacements replacements;
+        HotSpotDisassemblerProvider disassembler;
+        SuitesProvider suites;
+        HotSpotRegistersProvider registers;
+        HotSpotProviders providers;
+        try (InitTimer t = timer("create providers")) {
+            try (InitTimer rt = timer("create MetaAccess provider")) {
+                metaAccess = host.getMetaAccess();
+            }
+            try (InitTimer rt = timer("create CodeCache provider")) {
+                codeCache = new PTXHotSpotCodeCacheProvider(runtime, createTarget());
+            }
+            try (InitTimer rt = timer("create ConstantReflection provider")) {
+                constantReflection = host.getConstantReflection();
+            }
+            try (InitTimer rt = timer("create ForeignCalls provider")) {
+                foreignCalls = new PTXHotSpotForeignCallsProvider();
+            }
+            try (InitTimer rt = timer("create Lowerer provider")) {
+                lowerer = new PTXHotSpotLoweringProvider(host.getLowerer());
+            }
+            try (InitTimer rt = timer("create Replacements provider")) {
+                replacements = host.getReplacements();
+            }
+            try (InitTimer rt = timer("create Disassembler provider")) {
+                disassembler = host.getDisassembler();
+            }
+            try (InitTimer rt = timer("create Suites provider")) {
+                suites = new DefaultSuitesProvider();
+            }
+            try (InitTimer rt = timer("create HotSpotRegisters provider")) {
+                registers = new HotSpotRegisters(PTX.tid, Register.None, Register.None);
+            }
+            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection(),
+                            host.getMethodHandleAccess());
+        }
+        try (InitTimer rt = timer("instantiate backend")) {
+            return new PTXHotSpotBackend(runtime, providers);
+        }
     }
 
     protected Architecture createArchitecture() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sourcegen/src/com/oracle/graal/hotspot/sourcegen/GenGraalRuntimeInlineHpp.java	Tue May 27 21:20:01 2014 -0700
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sourcegen;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.zip.*;
+
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.options.*;
+
+/**
+ * Command line utility for generating the source code of {@code GraalRuntime.inline.hpp}.
+ */
+public class GenGraalRuntimeInlineHpp {
+
+    public static void main(String[] args) {
+        PrintStream out = System.out;
+        try {
+            genGetServiceImpls(out);
+            genSetOption(out);
+        } catch (Throwable t) {
+            t.printStackTrace(out);
+        }
+        out.flush();
+    }
+
+    /**
+     * Generates code for {@code GraalRuntime::get_service_impls()}.
+     */
+    private static void genGetServiceImpls(PrintStream out) throws Exception {
+        String graalJar = null;
+        String classPath = System.getProperty("java.class.path");
+        for (String e : classPath.split(File.pathSeparator)) {
+            if (e.endsWith("graal.jar")) {
+                graalJar = e;
+                break;
+            }
+        }
+        final List<Class<? extends Service>> services = new ArrayList<>();
+        final ZipFile zipFile = new ZipFile(new File(Objects.requireNonNull(graalJar, "Could not find graal.jar on class path: " + classPath)));
+        for (final Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements();) {
+            final ZipEntry zipEntry = e.nextElement();
+            String name = zipEntry.getName();
+            if (name.startsWith("META-INF/services/")) {
+                String serviceName = name.substring("META-INF/services/".length());
+                Class<?> c = Class.forName(serviceName);
+                if (Service.class.isAssignableFrom(c)) {
+                    @SuppressWarnings("unchecked")
+                    Class<? extends Service> sc = (Class<? extends Service>) c;
+
+                    services.add(sc);
+                }
+            }
+        }
+
+        out.println("Handle GraalRuntime::get_service_impls(KlassHandle serviceKlass, TRAPS) {");
+        for (Class<?> service : services) {
+            out.printf("  if (serviceKlass->name()->equals(\"%s\")) {%n", toInternalName(service));
+            List<Class<?>> impls = new ArrayList<>();
+            for (Object impl : ServiceLoader.load(service)) {
+                impls.add(impl.getClass());
+            }
+
+            out.printf("    objArrayOop servicesOop = oopFactory::new_objArray(serviceKlass(), %d, CHECK_NH);%n", impls.size());
+            out.println("    objArrayHandle services(THREAD, servicesOop);");
+            for (int i = 0; i < impls.size(); i++) {
+                String name = toInternalName(impls.get(i));
+                out.printf("    %sservice = create_Service(\"%s\", CHECK_NH);%n", (i == 0 ? "Handle " : ""), name);
+                out.printf("    services->obj_at_put(%d, service());%n", i);
+            }
+            out.println("    return services;");
+            out.println("  }");
+        }
+        out.println("  return Handle();");
+        out.println("}");
+    }
+
+    /**
+     * Generates code for {@code GraalRuntime::set_option()}.
+     */
+    private static void genSetOption(PrintStream out) throws Exception {
+        SortedMap<String, OptionDescriptor> options = getOptions();
+
+        Set<Integer> lengths = new TreeSet<>();
+        for (String s : options.keySet()) {
+            lengths.add(s.length());
+        }
+        lengths.add("PrintFlags".length());
+
+        out.println("bool GraalRuntime::set_option(KlassHandle hotSpotOptionsClass, const char* name, int name_len, Handle name_handle, const char* value, TRAPS) {");
+        out.println("  if (value[0] == '+' || value[0] == '-') {");
+        out.println("    // boolean options");
+        genMatchers(out, lengths, options, true);
+        out.println("  } else {");
+        out.println("    // non-boolean options");
+        genMatchers(out, lengths, options, false);
+        out.println("  }");
+        out.println("  return false;");
+        out.println("}");
+    }
+
+    protected static void genMatchers(PrintStream out, Set<Integer> lengths, SortedMap<String, OptionDescriptor> options, boolean isBoolean) throws Exception {
+        out.println("    switch (name_len) {");
+        for (int len : lengths) {
+            boolean printedCase = false;
+
+            // The use of strncmp is required (instead of strcmp) as the option name will not be
+            // null terminated for <name>=<value> style options.
+            if (len == "PrintFlags".length() && isBoolean) {
+                printedCase = true;
+                out.println("    case " + len + ":");
+                out.printf("      if (strncmp(name, \"PrintFlags\", %d) == 0) {%n", len);
+                out.println("        if (value[0] == '+') {");
+                out.println("          VMToCompiler::setOption(hotSpotOptionsClass, name_handle, Handle(), '?', Handle(), 0L);");
+                out.println("        }");
+                out.println("        return true;");
+                out.println("      }");
+            }
+            for (Map.Entry<String, OptionDescriptor> e : options.entrySet()) {
+                OptionDescriptor desc = e.getValue();
+                if (e.getKey().length() == len && ((desc.getType() == Boolean.class) == isBoolean)) {
+                    if (!printedCase) {
+                        printedCase = true;
+                        out.println("    case " + len + ":");
+                    }
+                    out.printf("      if (strncmp(name, \"%s\", %d) == 0) {%n", e.getKey(), len);
+                    Class<?> declaringClass = desc.getDeclaringClass();
+                    out.printf("        Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));%n", toInternalName(declaringClass), desc.getFieldName(),
+                                    toInternalName(getFieldType(desc)));
+                    if (isBoolean) {
+                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, value[0], Handle(), 0L);");
+                    } else if (desc.getType() == String.class) {
+                        out.println("        Handle stringValue = java_lang_String::create_from_str(value, CHECK_(true));");
+                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, 's', stringValue, 0L);");
+                    } else {
+                        char spec = getPrimitiveSpecChar(desc);
+                        out.println("        jlong primitiveValue = parse_primitive_option_value('" + spec + "', name_handle, value, CHECK_(true));");
+                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, '" + spec + "', Handle(), primitiveValue);");
+                    }
+                    out.println("        return true;");
+                    out.println("      }");
+                }
+            }
+        }
+        out.println("    }");
+    }
+
+    @SuppressWarnings("unchecked")
+    static SortedMap<String, OptionDescriptor> getOptions() throws Exception {
+        Field field = Class.forName("com.oracle.graal.hotspot.HotSpotOptionsLoader").getDeclaredField("options");
+        field.setAccessible(true);
+        return (SortedMap<String, OptionDescriptor>) field.get(null);
+    }
+
+    private static Class<?> getFieldType(OptionDescriptor desc) throws Exception {
+        return desc.getDeclaringClass().getDeclaredField(desc.getFieldName()).getType();
+    }
+
+    private static String toInternalName(Class<?> c) {
+        return c.getName().replace('.', '/');
+    }
+
+    /**
+     * @see HotSpotOptions#setOption(String, OptionValue, char, String, long)
+     */
+    @SuppressWarnings("javadoc")
+    private static char getPrimitiveSpecChar(OptionDescriptor desc) {
+        if (desc.getType() == Integer.class) {
+            return 'i';
+        }
+        if (desc.getType() == Float.class) {
+            return 'f';
+        }
+        if (desc.getType() == Double.class) {
+            return 'd';
+        }
+        throw GraalInternalError.shouldNotReachHere("Unexpected primitive option type: " + desc.getType().getName());
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Tue May 27 21:20:01 2014 -0700
@@ -23,8 +23,8 @@
 package com.oracle.graal.hotspot.sparc;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Tue May 27 21:20:01 2014 -0700
@@ -30,6 +30,8 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
@@ -69,6 +71,51 @@
 
     private final HotSpotGraalRuntime runtime;
 
+    /**
+     * @see AESCryptSubstitutions#encryptBlockStub(ForeignCallDescriptor, Word, Word, Word)
+     */
+    public static final ForeignCallDescriptor ENCRYPT_BLOCK = new ForeignCallDescriptor("encrypt_block", void.class, Word.class, Word.class, Word.class);
+
+    /**
+     * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Word)
+     */
+    public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Word.class);
+
+    /**
+     * @see CipherBlockChainingSubstitutions#crypt
+     */
+    public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class);
+
+    /**
+     * @see CipherBlockChainingSubstitutions#crypt
+     */
+    public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class);
+
+    /**
+     * @see VMErrorNode
+     */
+    public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
+
+    /**
+     * @see NewMultiArrayStubCall
+     */
+    public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, Word.class, int.class, Word.class);
+
+    /**
+     * @see NewArrayStubCall
+     */
+    public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, Word.class, int.class);
+
+    /**
+     * @see NewInstanceStubCall
+     */
+    public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, Word.class);
+
+    /**
+     * @see UncommonTrapCallNode
+     */
+    public static final ForeignCallDescriptor UNCOMMON_TRAP = new ForeignCallDescriptor("uncommonTrap", Word.class, Word.class, int.class);
+
     public HotSpotBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) {
         super(providers);
         this.runtime = runtime;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackendFactory.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackendFactory.java	Tue May 27 21:20:01 2014 -0700
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.hotspot;
 
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.hotspot.HotSpotGraalRuntime.Options;
 
-public interface HotSpotBackendFactory {
+public interface HotSpotBackendFactory extends Service {
 
     HotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotBackend host);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue May 27 21:20:01 2014 -0700
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.compiler.common.UnsafeAccess.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.Options.*;
 import static sun.reflect.Reflection.*;
 
@@ -41,6 +42,7 @@
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.events.*;
@@ -56,6 +58,47 @@
  */
 public final class HotSpotGraalRuntime implements GraalRuntime, RuntimeProvider, StackIntrospection {
 
+    /**
+     * A facility for timing a step in the initialization sequence for the runtime. This exists
+     * separate from {@link DebugTimer} as it must be independent from all other Graal code so as to
+     * not perturb the initialization sequence.
+     */
+    public static class InitTimer implements AutoCloseable {
+        final String name;
+        final long start;
+
+        private InitTimer(String name) {
+            this.name = name;
+            this.start = System.currentTimeMillis();
+            System.out.println("START: " + SPACES.substring(0, timerDepth * 2) + name);
+            assert Thread.currentThread() == initializingThread;
+            timerDepth++;
+        }
+
+        public void close() {
+            final long end = System.currentTimeMillis();
+            timerDepth--;
+            System.out.println(" DONE: " + SPACES.substring(0, timerDepth * 2) + name + " [" + (end - start) + " ms]");
+        }
+
+        public static InitTimer timer(String name) {
+            return ENABLED ? new InitTimer(name) : null;
+        }
+
+        public static InitTimer timer(String name, Object suffix) {
+            return ENABLED ? new InitTimer(name + suffix) : null;
+        }
+
+        /**
+         * Specified initialization timing is enabled. This must only be set via a system property
+         * as the timing facility is used to time initialization of {@link HotSpotOptions}.
+         */
+        private static final boolean ENABLED = Boolean.getBoolean("graal.runtime.TimeInit");
+        public static int timerDepth = 0;
+        public static final String SPACES = "                                            ";
+        public static final Thread initializingThread = Thread.currentThread();
+    }
+
     private static final HotSpotGraalRuntime instance;
 
     /**
@@ -64,16 +107,24 @@
     private static native void init(Class<?> compilerToVMClass);
 
     static {
-        init(CompilerToVMImpl.class);
+        try (InitTimer t = timer("initialize natives")) {
+            init(CompilerToVMImpl.class);
+        }
 
-        // The options must be processed before any code using them...
-        HotSpotOptions.initialize();
+        try (InitTimer t = timer("initialize HotSpotOptions")) {
+            // The options must be processed before any code using them...
+            HotSpotOptions.initialize();
+        }
 
-        // ... including code in the constructor
-        instance = new HotSpotGraalRuntime();
+        try (InitTimer t = timer("HotSpotGraalRuntime.<init>")) {
+            // ... including code in the constructor
+            instance = new HotSpotGraalRuntime();
+        }
 
-        // Why deferred initialization? See comment in completeInitialization().
-        instance.completeInitialization();
+        try (InitTimer t = timer("HotSpotGraalRuntime.completeInitialization")) {
+            // Why deferred initialization? See comment in completeInitialization().
+            instance.completeInitialization();
+        }
 
         registerFieldsToFilter(HotSpotGraalRuntime.class, "instance");
     }
@@ -138,7 +189,7 @@
         HotSpotBackendFactory nonBasic = null;
         int nonBasicCount = 0;
 
-        for (HotSpotBackendFactory factory : ServiceLoader.loadInstalled(HotSpotBackendFactory.class)) {
+        for (HotSpotBackendFactory factory : Services.load(HotSpotBackendFactory.class)) {
             if (factory.getArchitecture().equalsIgnoreCase(architecture)) {
                 if (factory.getGraalRuntimeName().equals(GraalRuntime.getValue())) {
                     assert selected == null || checkFactoryOverriding(selected, factory);
@@ -244,7 +295,9 @@
 
         compilerToVm = toVM;
         vmToCompiler = toCompiler;
-        config = new HotSpotVMConfig(compilerToVm);
+        try (InitTimer t = timer("HotSpotVMConfig<init>")) {
+            config = new HotSpotVMConfig(compilerToVm);
+        }
 
         CompileTheWorld.Options.overrideWithNativeOptions(config);
 
@@ -265,18 +318,31 @@
         }
 
         String hostArchitecture = config.getHostArchitectureName();
-        hostBackend = registerBackend(findFactory(hostArchitecture).createBackend(this, null));
+
+        HotSpotBackendFactory factory;
+        try (InitTimer t = timer("find factory:", hostArchitecture)) {
+            factory = findFactory(hostArchitecture);
+        }
+        try (InitTimer t = timer("create backend:", hostArchitecture)) {
+            hostBackend = registerBackend(factory.createBackend(this, null));
+        }
 
         String[] gpuArchitectures = getGPUArchitectureNames(compilerToVm);
         for (String arch : gpuArchitectures) {
-            HotSpotBackendFactory factory = findFactory(arch);
+            try (InitTimer t = timer("find factory:", arch)) {
+                factory = findFactory(arch);
+            }
             if (factory == null) {
                 throw new GraalInternalError("No backend available for specified GPU architecture \"%s\"", arch);
             }
-            registerBackend(factory.createBackend(this, hostBackend));
+            try (InitTimer t = timer("create backend:", arch)) {
+                registerBackend(factory.createBackend(this, hostBackend));
+            }
         }
 
-        eventProvider = createEventProvider();
+        try (InitTimer t = timer("createEventProvider")) {
+            eventProvider = createEventProvider();
+        }
     }
 
     private HotSpotBackend registerBackend(HotSpotBackend backend) {
@@ -386,7 +452,7 @@
 
     private EventProvider createEventProvider() {
         if (config.flightRecorder) {
-            ServiceLoader<EventProvider> sl = ServiceLoader.loadInstalled(EventProvider.class);
+            Iterable<EventProvider> sl = Services.load(EventProvider.class);
             EventProvider singleProvider = null;
             for (EventProvider ep : sl) {
                 assert singleProvider == null : String.format("multiple %s service implementations found: %s and %s", EventProvider.class.getName(), singleProvider.getClass().getName(),
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Tue May 27 21:20:01 2014 -0700
@@ -23,13 +23,14 @@
 package com.oracle.graal.hotspot;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-
-import java.util.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.nodes.spi.*;
@@ -65,16 +66,23 @@
         HotSpotVMConfig config = getRuntime().getConfig();
         HotSpotHostForeignCallsProvider foreignCalls = (HotSpotHostForeignCallsProvider) providers.getForeignCalls();
         final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
-        foreignCalls.initialize(providers, config);
-        lowerer.initialize(providers, config);
+
+        try (InitTimer st = timer("foreignCalls.initialize")) {
+            foreignCalls.initialize(providers, config);
+        }
+        try (InitTimer st = timer("lowerer.initialize")) {
+            lowerer.initialize(providers, config);
+        }
         HotSpotReplacementsImpl replacements = (HotSpotReplacementsImpl) providers.getReplacements();
 
         // Install intrinsics.
         if (Intrinsify.getValue()) {
             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, providers.getSnippetReflection(), replacements, providers.getCodeCache().getTarget());
+                try (InitTimer st = timer("replacementsProviders.registerReplacements")) {
+                    Iterable<ReplacementsProvider> sl = Services.load(ReplacementsProvider.class);
+                    for (ReplacementsProvider replacementsProvider : sl) {
+                        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/HotSpotOptionsLoader.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptionsLoader.java	Tue May 27 21:20:01 2014 -0700
@@ -22,10 +22,8 @@
  */
 package com.oracle.graal.hotspot;
 
-import java.io.*;
 import java.util.*;
 
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.options.*;
 
 /**
@@ -56,103 +54,4 @@
     private static boolean isHotSpotOption(OptionDescriptor desc) {
         return desc.getClass().getName().startsWith("com.oracle.graal");
     }
-
-    /**
-     * Command line utility for generating the source code of GraalRuntime::set_option() which is
-     * written {@link System#out}.
-     */
-    public static void main(String[] args) {
-        PrintStream out = System.out;
-        try {
-            Set<Integer> lengths = new TreeSet<>();
-            for (String s : options.keySet()) {
-                lengths.add(s.length());
-            }
-            lengths.add("PrintFlags".length());
-
-            out.println("bool GraalRuntime::set_option(KlassHandle hotSpotOptionsClass, const char* name, int name_len, Handle name_handle, const char* value, TRAPS) {");
-            out.println("  if (value[0] == '+' || value[0] == '-') {");
-            out.println("    // boolean options");
-            genMatchers(out, lengths, true);
-            out.println("  } else {");
-            out.println("    // non-boolean options");
-            genMatchers(out, lengths, false);
-            out.println("  }");
-            out.println("  return false;");
-            out.println("}");
-        } catch (Throwable t) {
-            t.printStackTrace(out);
-        }
-        out.flush();
-    }
-
-    protected static void genMatchers(PrintStream out, Set<Integer> lengths, boolean isBoolean) throws Exception {
-        out.println("    switch (name_len) {");
-        for (int len : lengths) {
-            boolean printedCase = false;
-
-            // The use of strncmp is required (instead of strcmp) as the option name will not be
-            // null terminated for <name>=<value> style options.
-            if (len == "PrintFlags".length() && isBoolean) {
-                printedCase = true;
-                out.println("    case " + len + ":");
-                out.printf("      if (strncmp(name, \"PrintFlags\", %d) == 0) {\n", len);
-                out.println("        if (value[0] == '+') {");
-                out.println("          VMToCompiler::setOption(hotSpotOptionsClass, name_handle, Handle(), '?', Handle(), 0L);");
-                out.println("        }");
-                out.println("        return true;");
-                out.println("      }");
-            }
-            for (Map.Entry<String, OptionDescriptor> e : options.entrySet()) {
-                OptionDescriptor desc = e.getValue();
-                if (e.getKey().length() == len && ((desc.getType() == Boolean.class) == isBoolean)) {
-                    if (!printedCase) {
-                        printedCase = true;
-                        out.println("    case " + len + ":");
-                    }
-                    out.printf("      if (strncmp(name, \"%s\", %d) == 0) {\n", e.getKey(), len);
-                    Class<?> declaringClass = desc.getDeclaringClass();
-                    out.printf("        Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));\n", toInternalName(declaringClass), desc.getFieldName(),
-                                    toInternalName(getFieldType(desc)));
-                    if (isBoolean) {
-                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, value[0], Handle(), 0L);");
-                    } else if (desc.getType() == String.class) {
-                        out.println("        Handle stringValue = java_lang_String::create_from_str(value, CHECK_(true));");
-                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, 's', stringValue, 0L);");
-                    } else {
-                        char spec = getPrimitiveSpecChar(desc);
-                        out.println("        jlong primitiveValue = parse_primitive_option_value('" + spec + "', name_handle, value, CHECK_(true));");
-                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, '" + spec + "', Handle(), primitiveValue);");
-                    }
-                    out.println("        return true;");
-                    out.println("      }");
-                }
-            }
-        }
-        out.println("    }");
-    }
-
-    private static Class<?> getFieldType(OptionDescriptor desc) throws Exception {
-        return desc.getDeclaringClass().getDeclaredField(desc.getFieldName()).getType();
-    }
-
-    private static String toInternalName(Class<?> c) {
-        return c.getName().replace('.', '/');
-    }
-
-    /**
-     * @see HotSpotOptions#setOption(String, OptionValue, char, String, long)
-     */
-    private static char getPrimitiveSpecChar(OptionDescriptor desc) {
-        if (desc.getType() == Integer.class) {
-            return 'i';
-        }
-        if (desc.getType() == Float.class) {
-            return 'f';
-        }
-        if (desc.getType() == Double.class) {
-            return 'd';
-        }
-        throw GraalInternalError.shouldNotReachHere("Unexpected primitive option type: " + desc.getType().getName());
-    }
 }
\ No newline at end of file
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Tue May 27 21:20:01 2014 -0700
@@ -48,7 +48,7 @@
     }
 
     @Override
-    protected ResolvedJavaMethod registerMethodSubstitution(Member originalMethod, Method substituteMethod) {
+    protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Member originalMethod, Method substituteMethod) {
         final Class<?> substituteClass = substituteMethod.getDeclaringClass();
         if (substituteClass.getDeclaringClass() == BoxingSubstitutions.class) {
             if (config.useHeapProfiler) {
@@ -78,7 +78,7 @@
                 return null;
             }
         }
-        return super.registerMethodSubstitution(originalMethod, substituteMethod);
+        return super.registerMethodSubstitution(cr, originalMethod, substituteMethod);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Tue May 27 21:20:01 2014 -0700
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
 import static com.oracle.graal.hotspot.CompileTheWorld.Options.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -40,6 +41,7 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.CompilationTask.Enqueueing;
 import com.oracle.graal.hotspot.CompileTheWorld.Config;
+import com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer;
 import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.java.*;
@@ -191,10 +193,14 @@
         assert VerifyOptionsPhase.checkOptions(hostProviders.getMetaAccess());
 
         // Complete initialization of backends
-        hostBackend.completeInitialization();
+        try (InitTimer st = timer(hostBackend.getTarget().arch.getName(), ".completeInitialization")) {
+            hostBackend.completeInitialization();
+        }
         for (HotSpotBackend backend : runtime.getBackends().values()) {
             if (backend != hostBackend) {
-                backend.completeInitialization();
+                try (InitTimer st = timer(backend.getTarget().arch.getName(), ".completeInitialization")) {
+                    backend.completeInitialization();
+                }
             }
         }
 
@@ -204,6 +210,12 @@
     }
 
     public void startCompiler(boolean bootstrapEnabled) throws Throwable {
+        try (InitTimer timer = timer("startCompiler")) {
+            startCompiler0(bootstrapEnabled);
+        }
+    }
+
+    private void startCompiler0(boolean bootstrapEnabled) throws Throwable {
 
         bootstrapRunning = bootstrapEnabled;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java	Tue May 27 21:20:01 2014 -0700
@@ -0,0 +1,96 @@
+/*
+ * 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.hotspot.meta;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.nodes.type.*;
+
+/**
+ * The compressed representation of the {@link Constant#NULL_OBJECT null constant}.
+ */
+public final class HotSpotCompressedNullConstant extends Constant implements HotSpotConstant {
+
+    private static final long serialVersionUID = 8906209595800783961L;
+
+    public static final Constant COMPRESSED_NULL = new HotSpotCompressedNullConstant();
+
+    private HotSpotCompressedNullConstant() {
+        super(NarrowOopStamp.NarrowOop);
+    }
+
+    @Override
+    public boolean isNull() {
+        return true;
+    }
+
+    @Override
+    public boolean isDefaultForKind() {
+        return true;
+    }
+
+    @Override
+    public Object asBoxedPrimitive() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public int asInt() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public boolean asBoolean() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public long asLong() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public float asFloat() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public double asDouble() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public String toValueString() {
+        return "null";
+    }
+
+    @Override
+    public int hashCode() {
+        return System.identityHashCode(this);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        assert o == this || !(o instanceof HotSpotCompressedNullConstant) : "null constant is a singleton";
+        return o == this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstant.java	Tue May 27 21:20:01 2014 -0700
@@ -0,0 +1,29 @@
+/*
+ * 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.meta;
+
+/**
+ * Marker interface for hotspot specific constants.
+ */
+public interface HotSpotConstant {
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Tue May 27 21:20:01 2014 -0700
@@ -223,7 +223,7 @@
 
     @Override
     public ResolvedJavaType asJavaType(Constant constant) {
-        if (constant.getKind() == Kind.Object) {
+        if (constant instanceof HotSpotObjectConstant) {
             Object obj = HotSpotObjectConstant.asObject(constant);
             if (obj instanceof Class) {
                 return runtime.getHostProviders().getMetaAccess().lookupJavaType((Class<?>) obj);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue May 27 21:20:01 2014 -0700
@@ -27,11 +27,7 @@
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
-import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*;
-import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*;
-import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*;
-import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
-import static com.oracle.graal.hotspot.nodes.VMErrorNode.*;
+import static com.oracle.graal.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.MonitorSnippets.*;
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
@@ -44,8 +40,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.DefaultHotSpotLoweringProvider.RuntimeCalls.*;
-import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
+import static com.oracle.graal.nodes.java.ForeignCallDescriptors.*;
 import static com.oracle.graal.replacements.Log.*;
 import static com.oracle.graal.replacements.MathSubstitutionsX86.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java	Tue May 27 21:20:01 2014 -0700
@@ -51,7 +51,7 @@
     }
 
     public ResolvedJavaType lookupJavaType(Constant constant) {
-        if (constant.getKind() != Kind.Object || constant.isNull()) {
+        if (constant.isNull() || !(constant instanceof HotSpotObjectConstant)) {
             return null;
         }
         Object o = HotSpotObjectConstant.asObject(constant);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant.java	Tue May 27 21:20:01 2014 -0700
@@ -26,7 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 
-public final class HotSpotMetaspaceConstant extends PrimitiveConstant {
+public final class HotSpotMetaspaceConstant extends PrimitiveConstant implements HotSpotConstant {
 
     private static final long serialVersionUID = 1003463314013122983L;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Tue May 27 21:20:01 2014 -0700
@@ -23,12 +23,13 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.nodes.type.*;
 
 /**
  * Represents a constant non-{@code null} object reference, within the compiler and across the
  * compiler/runtime interface.
  */
-public final class HotSpotObjectConstant extends Constant {
+public final class HotSpotObjectConstant extends Constant implements HotSpotConstant {
 
     private static final long serialVersionUID = 3592151693708093496L;
 
@@ -36,7 +37,7 @@
         if (object == null) {
             return Constant.NULL_OBJECT;
         } else {
-            return new HotSpotObjectConstant(object);
+            return new HotSpotObjectConstant(object, false);
         }
     }
 
@@ -59,21 +60,41 @@
     public static Object asBoxedValue(Constant constant) {
         if (constant.isNull()) {
             return null;
-        } else if (constant.getKind() == Kind.Object) {
+        } else if (constant instanceof HotSpotObjectConstant) {
             return ((HotSpotObjectConstant) constant).object;
         } else {
             return constant.asBoxedPrimitive();
         }
     }
 
+    public static boolean isCompressed(Constant constant) {
+        if (constant.isNull()) {
+            return HotSpotCompressedNullConstant.NULL_OBJECT.equals(constant);
+        } else {
+            return ((HotSpotObjectConstant) constant).compressed;
+        }
+    }
+
     private final Object object;
+    private final boolean compressed;
 
-    private HotSpotObjectConstant(Object object) {
-        super(Kind.Object);
+    private HotSpotObjectConstant(Object object, boolean compressed) {
+        super(compressed ? NarrowOopStamp.NarrowOop : Kind.Object);
         this.object = object;
+        this.compressed = compressed;
         assert object != null;
     }
 
+    public Constant compress() {
+        assert !compressed;
+        return new HotSpotObjectConstant(object, true);
+    }
+
+    public Constant uncompress() {
+        assert compressed;
+        return new HotSpotObjectConstant(object, false);
+    }
+
     @Override
     public boolean isNull() {
         return false;
@@ -135,6 +156,6 @@
 
     @Override
     public String toString() {
-        return getKind().getJavaName() + "[" + Kind.Object.format(object) + "]";
+        return (compressed ? "NarrowOop" : getKind().getJavaName()) + "[" + Kind.Object.format(object) + "]";
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Tue May 27 21:20:01 2014 -0700
@@ -58,7 +58,7 @@
 
         if (ImmutableCode.getValue()) {
             // lowering introduces class constants, therefore it must be after lowering
-            ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase(runtime.getConfig().classMirrorOffset));
+            ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase(runtime.getConfig().classMirrorOffset, runtime.getConfig().getOopEncoding()));
             if (VerifyPhases.getValue()) {
                 ret.getHighTier().appendPhase(new AheadOfTimeVerificationPhase());
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue May 27 21:20:01 2014 -0700
@@ -29,6 +29,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
+import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -39,7 +40,7 @@
  * Compress or uncompress an oop or metaspace pointer.
  */
 @NodeInfo(nameTemplate = "{p#op/s}")
-public final class CompressionNode extends FloatingNode implements LIRLowerable, Canonicalizable {
+public final class CompressionNode extends ConvertNode implements LIRLowerable, Canonicalizable {
 
     private enum CompressionOp {
         Compress,
@@ -49,13 +50,10 @@
     private final CompressionOp op;
     private final CompressEncoding encoding;
 
-    @Input private ValueNode input;
-
     private CompressionNode(CompressionOp op, ValueNode input, CompressEncoding encoding) {
-        super(mkStamp(op, input.stamp(), encoding));
+        super(mkStamp(op, input.stamp(), encoding), input);
         this.op = op;
         this.encoding = encoding;
-        this.input = input;
     }
 
     public static CompressionNode compress(ValueNode input, CompressEncoding encoding) {
@@ -66,6 +64,61 @@
         return input.graph().unique(new CompressionNode(CompressionOp.Uncompress, input, encoding));
     }
 
+    private static Constant compress(Constant c, CompressEncoding encoding) {
+        if (Constant.NULL_OBJECT.equals(c)) {
+            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
+        } else if (c instanceof HotSpotObjectConstant) {
+            return ((HotSpotObjectConstant) c).compress();
+        } else if (c instanceof HotSpotMetaspaceConstant) {
+            assert c.getKind() == Kind.Long;
+            return HotSpotMetaspaceConstant.forMetaspaceObject(Kind.Int, encoding.compress(c.asLong()), HotSpotMetaspaceConstant.getMetaspaceObject(c));
+        } else {
+            throw GraalInternalError.shouldNotReachHere("invalid constant input for compress op: " + c);
+        }
+    }
+
+    private static Constant uncompress(Constant c, CompressEncoding encoding) {
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+            return Constant.NULL_OBJECT;
+        } else if (c instanceof HotSpotObjectConstant) {
+            return ((HotSpotObjectConstant) c).uncompress();
+        } else if (c instanceof HotSpotMetaspaceConstant) {
+            assert c.getKind() == Kind.Int;
+            return HotSpotMetaspaceConstant.forMetaspaceObject(Kind.Long, encoding.uncompress(c.asInt()), HotSpotMetaspaceConstant.getMetaspaceObject(c));
+        } else {
+            throw GraalInternalError.shouldNotReachHere("invalid constant input for uncompress op: " + c);
+        }
+    }
+
+    @Override
+    public Constant convert(Constant c) {
+        switch (op) {
+            case Compress:
+                return compress(c, encoding);
+            case Uncompress:
+                return uncompress(c, encoding);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Constant reverse(Constant c) {
+        switch (op) {
+            case Compress:
+                return uncompress(c, encoding);
+            case Uncompress:
+                return compress(c, encoding);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public boolean isLossless() {
+        return true;
+    }
+
     private static Stamp mkStamp(CompressionOp op, Stamp input, CompressEncoding encoding) {
         switch (op) {
             case Compress:
@@ -93,20 +146,18 @@
         throw GraalInternalError.shouldNotReachHere(String.format("Unexpected input stamp %s", input));
     }
 
-    public ValueNode getInput() {
-        return input;
-    }
-
     public CompressEncoding getEncoding() {
         return encoding;
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (input instanceof CompressionNode) {
-            CompressionNode other = (CompressionNode) input;
+        if (getInput().isConstant()) {
+            return ConstantNode.forConstant(stamp(), evalConst(getInput().asConstant()), tool.getMetaAccess(), graph());
+        } else if (getInput() instanceof CompressionNode) {
+            CompressionNode other = (CompressionNode) getInput();
             if (op != other.op && encoding.equals(other.encoding)) {
-                return other.input;
+                return other.getInput();
             }
         }
         return this;
@@ -116,8 +167,8 @@
     public void generate(NodeLIRBuilderTool gen) {
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
         boolean nonNull;
-        if (input.stamp() instanceof ObjectStamp) {
-            nonNull = StampTool.isObjectNonNull(input.stamp());
+        if (getInput().stamp() instanceof ObjectStamp) {
+            nonNull = StampTool.isObjectNonNull(getInput().stamp());
         } else {
             // metaspace pointers are never null
             nonNull = true;
@@ -126,10 +177,10 @@
         Value result;
         switch (op) {
             case Compress:
-                result = hsGen.emitCompress(gen.operand(input), encoding, nonNull);
+                result = hsGen.emitCompress(gen.operand(getInput()), encoding, nonNull);
                 break;
             case Uncompress:
-                result = hsGen.emitUncompress(gen.operand(input), encoding, nonNull);
+                result = hsGen.emitUncompress(gen.operand(getInput()), encoding, nonNull);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Tue May 27 21:20:01 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
@@ -42,8 +43,6 @@
     @Input private ValueNode hub;
     @Input private ValueNode length;
 
-    public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, Word.class, int.class);
-
     public NewArrayStubCall(ValueNode hub, ValueNode length) {
         super(defaultStamp);
         this.hub = hub;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Tue May 27 21:20:01 2014 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -40,8 +42,6 @@
 
     @Input private ValueNode hub;
 
-    public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, Word.class);
-
     public NewInstanceStubCall(ValueNode hub) {
         super(defaultStamp);
         this.hub = hub;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Tue May 27 21:20:01 2014 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -42,8 +44,6 @@
     @Input private ValueNode dims;
     private final int rank;
 
-    public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, Word.class, int.class, Word.class);
-
     public NewMultiArrayStubCall(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode hub, int rank, ValueNode dims) {
         super(foreignCalls, NEW_MULTI_ARRAY, defaultStamp);
         this.hub = hub;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Tue May 27 21:20:01 2014 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -42,7 +44,6 @@
     @Input private ValueNode trapRequest;
     @Input private SaveAllRegistersNode registerSaver;
     private final ForeignCallsProvider foreignCalls;
-    public static final ForeignCallDescriptor UNCOMMON_TRAP = new ForeignCallDescriptor("uncommonTrap", Word.class, Word.class, int.class);
 
     public UncommonTrapCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver, ValueNode trapRequest) {
         super(StampFactory.forKind(Kind.fromJavaClass(UNCOMMON_TRAP.getResultType())));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Tue May 27 21:20:01 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.nodes.CStringNode.*;
 
 import com.oracle.graal.api.code.*;
@@ -40,7 +41,6 @@
 
     private final String format;
     @Input private ValueNode value;
-    public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
 
     public VMErrorNode(String format, ValueNode value) {
         super(StampFactory.forVoid());
@@ -67,7 +67,7 @@
         Value whereArg = emitCString(gen, whereString);
         Value formatArg = emitCString(gen, format);
 
-        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(VMErrorNode.VM_ERROR);
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(VM_ERROR);
         gen.getLIRGeneratorTool().emitForeignCall(linkage, null, whereArg, formatArg, gen.operand(value));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Tue May 27 21:20:01 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
@@ -27,7 +27,9 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.hotspot.HotSpotVMConfig.*;
 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.phases.*;
@@ -39,22 +41,24 @@
  * directly. Instead the {@link Class} reference should be obtained from the {@code Klass} object.
  * The reason for this is, that in Class Data Sharing (CDS) a {@code Klass} object is mapped to a
  * fixed address in memory, but the {@code javaMirror} is not (which lives in the Java heap).
- * 
+ *
  * Lowering can introduce new {@link ConstantNode}s containing a {@link Class} reference, thus this
  * phase must be applied after {@link LoweringPhase}.
- * 
+ *
  * @see AheadOfTimeVerificationPhase
  */
 public class LoadJavaMirrorWithKlassPhase extends BasePhase<PhaseContext> {
 
     private final int classMirrorOffset;
+    private final CompressEncoding oopEncoding;
 
-    public LoadJavaMirrorWithKlassPhase(int classMirrorOffset) {
+    public LoadJavaMirrorWithKlassPhase(int classMirrorOffset, CompressEncoding oopEncoding) {
         this.classMirrorOffset = classMirrorOffset;
+        this.oopEncoding = oopEncoding;
     }
 
-    private FloatingReadNode getClassConstantReplacement(StructuredGraph graph, PhaseContext context, Constant constant) {
-        if (constant.getKind() == Kind.Object && HotSpotObjectConstant.asObject(constant) instanceof Class<?>) {
+    private ValueNode getClassConstantReplacement(StructuredGraph graph, PhaseContext context, Constant constant) {
+        if (constant instanceof HotSpotObjectConstant && HotSpotObjectConstant.asObject(constant) instanceof Class<?>) {
             MetaAccessProvider metaAccess = context.getMetaAccess();
             ResolvedJavaType type = metaAccess.lookupJavaType((Class<?>) HotSpotObjectConstant.asObject(constant));
             assert type instanceof HotSpotResolvedObjectType;
@@ -65,7 +69,12 @@
             Stamp stamp = StampFactory.exactNonNull(metaAccess.lookupJavaType(Class.class));
             LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, Kind.Object, classMirrorOffset, graph);
             FloatingReadNode freadNode = graph.unique(new FloatingReadNode(klassNode, location, null, stamp));
-            return freadNode;
+
+            if (HotSpotObjectConstant.isCompressed(constant)) {
+                return CompressionNode.compress(freadNode, oopEncoding);
+            } else {
+                return freadNode;
+            }
         }
         return null;
     }
@@ -74,7 +83,7 @@
     protected void run(StructuredGraph graph, PhaseContext context) {
         for (ConstantNode node : getConstantNodes(graph)) {
             Constant constant = node.asConstant();
-            FloatingReadNode freadNode = getClassConstantReplacement(graph, context, constant);
+            ValueNode freadNode = getClassConstantReplacement(graph, context, constant);
             if (freadNode != null) {
                 node.replace(graph, freadNode);
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Tue May 27 21:20:01 2014 -0700
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import sun.misc.*;
 
@@ -93,9 +94,6 @@
         }
     }
 
-    public static final ForeignCallDescriptor ENCRYPT_BLOCK = new ForeignCallDescriptor("encrypt_block", void.class, Word.class, Word.class, Word.class);
-    public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Word.class);
-
     @NodeIntrinsic(ForeignCallNode.class)
     public static native void encryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Word key);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java	Tue May 27 21:20:01 2014 -0700
@@ -35,9 +35,9 @@
 
     @Override
     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);
+        replacements.registerSubstitutions(ConstantCallSite.class, ConstantCallSiteSubstitutions.class);
+        replacements.registerSubstitutions(MutableCallSite.class, MutableCallSiteSubstitutions.class);
+        replacements.registerSubstitutions(VolatileCallSite.class, VolatileCallSiteSubstitutions.class);
     }
 
     @ClassSubstitution(ConstantCallSite.class)
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Tue May 27 21:20:01 2014 -0700
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import sun.misc.*;
 
@@ -108,9 +109,6 @@
         }
     }
 
-    public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class);
-    public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class);
-
     @NodeIntrinsic(ForeignCallNode.class)
     public static native void encryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Word key, Word r, int inLength);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue May 27 21:20:01 2014 -0700
@@ -22,29 +22,50 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import java.lang.reflect.*;
+import java.util.zip.*;
+
+import sun.misc.*;
+import sun.reflect.*;
+
 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.graph.*;
+import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 
 @ServiceProvider(ReplacementsProvider.class)
 public class HotSpotSubstitutions implements ReplacementsProvider {
 
+    static class NamedType implements Type {
+        private final String name;
+
+        public NamedType(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
     @Override
     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);
-        replacements.registerSubstitutions(UnsafeSubstitutions.class);
-        replacements.registerSubstitutions(ClassSubstitutions.class);
-        replacements.registerSubstitutions(AESCryptSubstitutions.class);
-        replacements.registerSubstitutions(CipherBlockChainingSubstitutions.class);
-        replacements.registerSubstitutions(CRC32Substitutions.class);
-        replacements.registerSubstitutions(ReflectionSubstitutions.class);
-        replacements.registerSubstitutions(HotSpotNodeClassSubstitutions.class);
-        replacements.registerSubstitutions(HotSpotNodeSubstitutions.class);
-        replacements.registerSubstitutions(CompositeValueClassSubstitutions.class);
+        replacements.registerSubstitutions(Object.class, ObjectSubstitutions.class);
+        replacements.registerSubstitutions(System.class, SystemSubstitutions.class);
+        replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class);
+        replacements.registerSubstitutions(Unsafe.class, UnsafeSubstitutions.class);
+        replacements.registerSubstitutions(Class.class, ClassSubstitutions.class);
+        replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class);
+        replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class);
+        replacements.registerSubstitutions(NodeClass.class, HotSpotNodeClassSubstitutions.class);
+        replacements.registerSubstitutions(Node.class, HotSpotNodeSubstitutions.class);
+        replacements.registerSubstitutions(CompositeValueClass.class, CompositeValueClassSubstitutions.class);
+        replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class);
+        replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Tue May 27 21:20:01 2014 -0700
@@ -180,7 +180,7 @@
                         // owns the bias and we need to revoke that bias. The revocation will occur
                         // in the interpreter runtime.
                         traceObject(trace, "+lock{stub:revoke}", object, true);
-                        monitorenterStub(MONITORENTER, object, lock);
+                        monitorenterStubC(MONITORENTER, object, lock);
                         return;
                     } else {
                         // At this point we know the epoch has expired, meaning that the
@@ -200,7 +200,7 @@
                         // succeeded in biasing it toward itself and we need to revoke that
                         // bias. The revocation will occur in the runtime in the slow case.
                         traceObject(trace, "+lock{stub:epoch-expired}", object, true);
-                        monitorenterStub(MONITORENTER, object, lock);
+                        monitorenterStubC(MONITORENTER, object, lock);
                         return;
                     }
                 } else {
@@ -257,7 +257,7 @@
             if (probability(VERY_SLOW_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0))) {
                 // Most likely not a recursive lock, go into a slow runtime call
                 traceObject(trace, "+lock{stub:failed-cas}", object, true);
-                monitorenterStub(MONITORENTER, object, lock);
+                monitorenterStubC(MONITORENTER, object, lock);
                 return;
             } else {
                 // Recursively locked => write 0 to the lock slot
@@ -283,7 +283,7 @@
         // cannot float about the null check above
         final Word lock = beginLockScope(lockDepth);
         traceObject(trace, "+lock{stub}", object, true);
-        monitorenterStub(MONITORENTER, object, lock);
+        monitorenterStubC(MONITORENTER, object, lock);
     }
 
     @Snippet
@@ -324,7 +324,7 @@
                 // The object's mark word was not pointing to the displaced header,
                 // we do unlocking via runtime call.
                 traceObject(trace, "-lock{stub}", object, false);
-                monitorexitStub(MONITOREXIT, object, lock);
+                monitorexitStubC(MONITOREXIT, object, lock);
             } else {
                 traceObject(trace, "-lock{cas}", object, false);
             }
@@ -341,7 +341,7 @@
         verifyOop(object);
         traceObject(trace, "-lock{stub}", object, false);
         final Word lock = CurrentLockNode.currentLock(lockDepth);
-        monitorexitStub(MONITOREXIT, object, lock);
+        monitorexitStubC(MONITOREXIT, object, lock);
         endLockScope();
         decCounter();
     }
@@ -531,9 +531,9 @@
     public static final ForeignCallDescriptor MONITOREXIT = new ForeignCallDescriptor("monitorexit", void.class, Object.class, Word.class);
 
     @NodeIntrinsic(ForeignCallNode.class)
-    private static native void monitorenterStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
+    private static native void monitorenterStubC(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
 
     @NodeIntrinsic(ForeignCallNode.class)
-    private static native void monitorexitStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
+    private static native void monitorexitStubC(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
 
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Tue May 27 21:20:01 2014 -0700
@@ -35,7 +35,8 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.Snippet.*;
+import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.Snippet.Fold;
 import com.oracle.graal.word.*;
 
 /**
@@ -80,7 +81,7 @@
     private final TargetDescription target;
 
     public DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super(DeoptimizationStub.class, "deoptimizationHandler", providers, target, linkage);
         this.target = target;
     }
 
@@ -270,8 +271,8 @@
         return config().deoptimizationUnpackUncommonTrap;
     }
 
-    public static final ForeignCallDescriptor FETCH_UNROLL_INFO = descriptorFor(DeoptimizationStub.class, "fetchUnrollInfo");
-    public static final ForeignCallDescriptor UNPACK_FRAMES = descriptorFor(DeoptimizationStub.class, "unpackFrames");
+    public static final ForeignCallDescriptor FETCH_UNROLL_INFO = newDescriptor(DeoptimizationStub.class, "fetchUnrollInfo", Word.class, Word.class);
+    public static final ForeignCallDescriptor UNPACK_FRAMES = newDescriptor(DeoptimizationStub.class, "unpackFrames", int.class, Word.class, int.class);
 
     @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
     public static native Word fetchUnrollInfo(@ConstantNodeParameter ForeignCallDescriptor fetchUnrollInfo, Word thread);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Tue May 27 21:20:01 2014 -0700
@@ -50,7 +50,7 @@
 public class ExceptionHandlerStub extends SnippetStub {
 
     public ExceptionHandlerStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super("exceptionHandler", providers, target, linkage);
     }
 
     /**
@@ -142,7 +142,7 @@
         return enabled || cAssertionsEnabled();
     }
 
-    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = descriptorFor(ExceptionHandlerStub.class, "exceptionHandlerForPc");
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = newDescriptor(ExceptionHandlerStub.class, "exceptionHandlerForPc", Word.class, Word.class);
 
     @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
     public static native Word exceptionHandlerForPc(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForPc, Word thread);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue May 27 21:20:01 2014 -0700
@@ -53,7 +53,7 @@
 public class NewArrayStub extends SnippetStub {
 
     public NewArrayStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super("newArray", providers, target, linkage);
     }
 
     @Override
@@ -115,7 +115,7 @@
         return verifyObject(getAndClearObjectResult(thread));
     }
 
-    public static final ForeignCallDescriptor NEW_ARRAY_C = descriptorFor(NewArrayStub.class, "newArrayC");
+    public static final ForeignCallDescriptor NEW_ARRAY_C = newDescriptor(NewArrayStub.class, "newArrayC", void.class, Word.class, Word.class, int.class);
 
     @NodeIntrinsic(StubForeignCallNode.class)
     public static native void newArrayC(@ConstantNodeParameter ForeignCallDescriptor newArrayC, Word thread, Word hub, int length);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue May 27 21:20:01 2014 -0700
@@ -53,7 +53,7 @@
 public class NewInstanceStub extends SnippetStub {
 
     public NewInstanceStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super("newInstance", providers, target, linkage);
     }
 
     @Override
@@ -251,7 +251,7 @@
         return Boolean.getBoolean("graal.newInstanceStub.forceSlowPath");
     }
 
-    public static final ForeignCallDescriptor NEW_INSTANCE_C = descriptorFor(NewInstanceStub.class, "newInstanceC");
+    public static final ForeignCallDescriptor NEW_INSTANCE_C = newDescriptor(NewInstanceStub.class, "newInstanceC", void.class, Word.class, Word.class);
 
     @NodeIntrinsic(StubForeignCallNode.class)
     public static native void newInstanceC(@ConstantNodeParameter ForeignCallDescriptor newInstanceC, Word thread, Word hub);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Tue May 27 21:20:01 2014 -0700
@@ -44,9 +44,9 @@
 
     static class Template extends AbstractTemplates {
 
-        Template(HotSpotProviders providers, TargetDescription target, Class<? extends Snippets> declaringClass) {
+        Template(HotSpotProviders providers, TargetDescription target, Class<? extends Snippets> declaringClass, String snippetMethodName) {
             super(providers, providers.getSnippetReflection(), target);
-            this.info = snippet(declaringClass, null);
+            this.info = snippet(declaringClass, snippetMethodName);
         }
 
         /**
@@ -65,11 +65,26 @@
     /**
      * Creates a new snippet stub.
      *
+     * @param snippetMethodName name of the single {@link Snippet} annotated method in the class of
+     *            this object
      * @param linkage linkage details for a call to the stub
      */
-    public SnippetStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+    public SnippetStub(String snippetMethodName, HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        this(null, snippetMethodName, providers, target, linkage);
+    }
+
+    /**
+     * Creates a new snippet stub.
+     *
+     * @param snippetDeclaringClass this class in which the {@link Snippet} annotated method is
+     *            declared. If {@code null}, this the class of this object is used.
+     * @param snippetMethodName name of the single {@link Snippet} annotated method in
+     *            {@code snippetDeclaringClass}
+     * @param linkage linkage details for a call to the stub
+     */
+    public SnippetStub(Class<? extends Snippets> snippetDeclaringClass, String snippetMethodName, HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(providers, linkage);
-        this.snippet = new Template(providers, target, getClass());
+        this.snippet = new Template(providers, target, snippetDeclaringClass == null ? getClass() : snippetDeclaringClass, snippetMethodName);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Tue May 27 21:20:01 2014 -0700
@@ -47,14 +47,20 @@
  */
 public class StubUtil {
 
-    public static final ForeignCallDescriptor VM_MESSAGE_C = descriptorFor(StubUtil.class, "vmMessageC");
+    public static final ForeignCallDescriptor VM_MESSAGE_C = newDescriptor(StubUtil.class, "vmMessageC", void.class, boolean.class, Word.class, long.class, long.class, long.class);
+
+    public static ForeignCallDescriptor newDescriptor(Class<?> stubClass, String name, Class<?> resultType, Class<?>... argumentTypes) {
+        ForeignCallDescriptor d = new ForeignCallDescriptor(name, resultType, argumentTypes);
+        assert descriptorFor(stubClass, name).equals(d) : descriptorFor(stubClass, name) + " != " + d;
+        return d;
+    }
 
     /**
      * Looks for a {@link StubForeignCallNode} node intrinsic named {@code name} in
      * {@code stubClass} and returns a {@link ForeignCallDescriptor} based on its signature and the
      * value of {@code hasSideEffect}.
      */
-    public static ForeignCallDescriptor descriptorFor(Class<?> stubClass, String name) {
+    private static ForeignCallDescriptor descriptorFor(Class<?> stubClass, String name) {
         Method found = null;
         for (Method method : stubClass.getDeclaredMethods()) {
             if (Modifier.isStatic(method.getModifiers()) && method.getAnnotation(NodeIntrinsic.class) != null && method.getName().equals(name)) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Tue May 27 21:20:01 2014 -0700
@@ -80,7 +80,7 @@
     private final TargetDescription target;
 
     public UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super(UncommonTrapStub.class, "uncommonTrapHandler", providers, target, linkage);
         this.target = target;
     }
 
@@ -281,7 +281,7 @@
         return config().deoptimizationUnpackUncommonTrap;
     }
 
-    public static final ForeignCallDescriptor UNPACK_FRAMES = descriptorFor(UncommonTrapStub.class, "unpackFrames");
+    public static final ForeignCallDescriptor UNPACK_FRAMES = newDescriptor(UncommonTrapStub.class, "unpackFrames", int.class, Word.class, int.class);
 
     @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
     public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Tue May 27 21:20:01 2014 -0700
@@ -47,7 +47,7 @@
 public class UnwindExceptionToCallerStub extends SnippetStub {
 
     public UnwindExceptionToCallerStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super("unwindExceptionToCaller", providers, target, linkage);
     }
 
     /**
@@ -110,7 +110,8 @@
         return enabled || cAssertionsEnabled();
     }
 
-    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = descriptorFor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress");
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = newDescriptor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", Word.class, Word.class,
+                    Word.class);
 
     @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
     public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java	Tue May 27 21:20:01 2014 -0700
@@ -35,7 +35,7 @@
 public class VerifyOopStub extends SnippetStub {
 
     public VerifyOopStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super("verifyOop", providers, target, linkage);
     }
 
     @Snippet
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Tue May 27 21:20:01 2014 -0700
@@ -280,9 +280,10 @@
         this.method = method;
         exceptionHandlers = method.getExceptionHandlers();
         stream = new BytecodeStream(method.getCode());
-        this.blockMap = new BciBlock[method.getCodeSize()];
+        int codeSize = method.getCodeSize();
+        this.blockMap = new BciBlock[codeSize];
         this.blocks = new ArrayList<>();
-        this.loopHeaders = new BciBlock[64];
+        this.loopHeaders = new BciBlock[codeSize < 64 ? codeSize : 64];
     }
 
     /**
@@ -780,7 +781,7 @@
         for (BciBlock successor : block.getSuccessors()) {
             // Recursively process successors.
             loops |= computeBlockOrder(successor);
-            if (block.visited && successor.active) {
+            if (successor.active) {
                 // Reached block via backward branch.
                 block.isLoopEnd = true;
             }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Tue May 27 21:20:01 2014 -0700
@@ -84,7 +84,7 @@
         }
 
         @Override
-        public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        protected void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
             if (isRegister(y)) {
                 switch (opcode) {
                     case BCMP:
@@ -129,6 +129,13 @@
                             throw GraalInternalError.shouldNotReachHere();
                         }
                         break;
+                    case ACMP:
+                        if (asConstant(y).isNull()) {
+                            masm.cmpq(address.toAddress(), 0);
+                        } else {
+                            throw GraalInternalError.shouldNotReachHere();
+                        }
+                        break;
                     default:
                         throw GraalInternalError.shouldNotReachHere();
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Tue May 27 21:20:01 2014 -0700
@@ -153,13 +153,7 @@
     }
 
     public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph) {
-        if (stamp instanceof PrimitiveStamp) {
-            return forPrimitive(stamp, constant, graph);
-        } else {
-            ConstantNode ret = forConstant(constant, metaAccess, graph);
-            assert ret.stamp().isCompatible(stamp);
-            return ret;
-        }
+        return graph.unique(new ConstantNode(constant, stamp.constant(constant, metaAccess)));
     }
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue May 27 21:20:01 2014 -0700
@@ -126,14 +126,14 @@
             }
         } else if (x() instanceof ConvertNode && y().isConstant()) {
             ConvertNode convertX = (ConvertNode) x();
-            ConstantNode newY = canonicalConvertConstant(convertX, y().asConstant());
+            ConstantNode newY = canonicalConvertConstant(tool, convertX, y().asConstant());
             if (newY != null) {
                 setX(convertX.getInput());
                 setY(newY);
             }
         } else if (y() instanceof ConvertNode && x().isConstant()) {
             ConvertNode convertY = (ConvertNode) y();
-            ConstantNode newX = canonicalConvertConstant(convertY, x().asConstant());
+            ConstantNode newX = canonicalConvertConstant(tool, convertY, x().asConstant());
             if (newX != null) {
                 setX(newX);
                 setY(convertY.getInput());
@@ -142,11 +142,11 @@
         return this;
     }
 
-    private ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) {
+    private ConstantNode canonicalConvertConstant(CanonicalizerTool tool, 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());
+                return ConstantNode.forConstant(convert.getInput().stamp(), reverseConverted, tool.getMetaAccess(), convert.graph());
             }
         }
         return null;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Tue May 27 21:20:01 2014 -0700
@@ -41,7 +41,8 @@
     }
 
     public static long narrow(long value, int resultBits) {
-        return value & IntegerStamp.defaultMask(resultBits);
+        long ret = value & IntegerStamp.defaultMask(resultBits);
+        return SignExtendNode.signExtend(ret, resultBits);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ForeignCallDescriptors.java	Tue May 27 21:20:01 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.nodes.java;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * The foreign call descriptors used by nodes in this package.
+ * <p>
+ * Using a separate class for such descriptors prevents an access from triggering unwanted class
+ * initialization during runtime initialization.
+ */
+public class ForeignCallDescriptors {
+
+    /**
+     * @see RegisterFinalizerNode
+     */
+    public static final ForeignCallDescriptor REGISTER_FINALIZER = new ForeignCallDescriptor("registerFinalizer", void.class, Object.class);
+
+}
\ No newline at end of file
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Tue May 27 21:20:01 2014 -0700
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.nodes.java;
 
+import static com.oracle.graal.nodes.java.ForeignCallDescriptors.*;
+
 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.*;
@@ -36,8 +37,6 @@
  */
 public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode.DeoptAfter {
 
-    public static final ForeignCallDescriptor REGISTER_FINALIZER = new ForeignCallDescriptor("registerFinalizer", void.class, Object.class);
-
     @Input(InputType.State) private FrameState deoptState;
     @Input private ValueNode object;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Tue May 27 21:20:01 2014 -0700
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.spi;
 
+import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -36,14 +37,14 @@
 
     /**
      * Gets the snippet graph derived from a given method.
-     * 
+     *
      * @return the snippet graph, if any, that is derived from {@code method}
      */
     StructuredGraph getSnippet(ResolvedJavaMethod method);
 
     /**
      * Gets the snippet graph derived from a given method.
-     * 
+     *
      * @param recursiveEntry if the snippet contains a call to this method, it's considered as
      *            recursive call and won't be processed for {@linkplain MethodSubstitution
      *            substitutions} or {@linkplain MacroSubstitution macro nodes}.
@@ -59,7 +60,7 @@
     /**
      * Notifies this object during snippet specialization once the specialized snippet's constant
      * parameters have been replaced with constant values.
-     * 
+     *
      * @param specializedSnippet the snippet in the process of being specialized. This is a copy of
      *            the unspecialized snippet graph created during snippet preparation.
      */
@@ -67,14 +68,14 @@
 
     /**
      * Gets the graph that is a substitution for a given method.
-     * 
+     *
      * @return the graph, if any, that is a substitution for {@code method}
      */
     StructuredGraph getMethodSubstitution(ResolvedJavaMethod method);
 
     /**
      * Gets the node class with which a method invocation should be replaced.
-     * 
+     *
      * @param method target of an invocation
      * @return the {@linkplain MacroSubstitution#macro() macro node class} associated with
      *         {@code method} or null if there is no such association
@@ -89,8 +90,15 @@
     /**
      * Registers all the {@linkplain MethodSubstitution method} and {@linkplain MacroSubstitution
      * macro} substitutions defined by a given class.
+     *
+     * @param original the original class for which substitutions are being registered. This must be
+     *            the same type denoted by the {@link ClassSubstitution} annotation on
+     *            {@code substitutions}. It is required here so that an implementation is not forced
+     *            to read annotations during registration.
+     * @param substitutions the class defining substitutions for {@code original}. This class must
+     *            be annotated with {@link ClassSubstitution}.
      */
-    void registerSubstitutions(Class<?> substitutions);
+    void registerSubstitutions(Type original, Class<?> substitutions);
 
     /**
      * Returns all methods that are currently registered as method/macro substitution or as a
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Tue May 27 21:20:01 2014 -0700
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.phases.tiers;
 
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.phases.*;
 
-public interface CompilerConfiguration {
+public interface CompilerConfiguration extends Service {
 
     PhaseSuite<HighTierContext> createHighTier();
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java	Tue May 27 21:20:01 2014 -0700
@@ -26,6 +26,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
@@ -65,7 +66,7 @@
         CompilerConfiguration nonBasic = null;
         int nonBasicCount = 0;
 
-        for (CompilerConfiguration config : ServiceLoader.loadInstalled(CompilerConfiguration.class)) {
+        for (CompilerConfiguration config : Services.load(CompilerConfiguration.class)) {
             String name = config.getClass().getSimpleName();
             if (name.endsWith("CompilerConfiguration")) {
                 name = name.substring(0, name.length() - "CompilerConfiguration".length());
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java	Tue May 27 21:20:01 2014 -0700
@@ -25,6 +25,8 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
@@ -40,8 +42,8 @@
 
     public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         if (Intrinsify.getValue()) {
-            replacements.registerSubstitutions(ArraysSubstitutions.class);
-            replacements.registerSubstitutions(StringSubstitutions.class);
+            replacements.registerSubstitutions(Arrays.class, ArraysSubstitutions.class);
+            replacements.registerSubstitutions(String.class, StringSubstitutions.class);
         }
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSubstitutions.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSubstitutions.java	Tue May 27 21:20:01 2014 -0700
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
 
 public class BoxingSubstitutions {
 
@@ -140,8 +141,14 @@
         }
     }
 
-    public static Class<?>[] getClasses() {
-        return new Class<?>[]{BooleanSubstitutions.class, ByteSubstitutions.class, CharacterSubstitutions.class, DoubleSubstitutions.class, FloatSubstitutions.class, IntegerSubstitutions.class,
-                        LongSubstitutions.class, ShortSubstitutions.class};
+    public static void registerReplacements(Replacements replacements) {
+        replacements.registerSubstitutions(Boolean.class, BooleanSubstitutions.class);
+        replacements.registerSubstitutions(Character.class, CharacterSubstitutions.class);
+        replacements.registerSubstitutions(Double.class, DoubleSubstitutions.class);
+        replacements.registerSubstitutions(Byte.class, ByteSubstitutions.class);
+        replacements.registerSubstitutions(Float.class, FloatSubstitutions.class);
+        replacements.registerSubstitutions(Integer.class, IntegerSubstitutions.class);
+        replacements.registerSubstitutions(Short.class, ShortSubstitutions.class);
+        replacements.registerSubstitutions(Long.class, LongSubstitutions.class);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Tue May 27 21:20:01 2014 -0700
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
+import java.lang.reflect.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
@@ -37,20 +39,17 @@
 public class GraalMethodSubstitutions implements ReplacementsProvider {
 
     public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
-        for (Class<?> clazz : BoxingSubstitutions.getClasses()) {
-            replacements.registerSubstitutions(clazz);
-        }
-
+        BoxingSubstitutions.registerReplacements(replacements);
         if (Intrinsify.getValue()) {
-            replacements.registerSubstitutions(ArraySubstitutions.class);
-            replacements.registerSubstitutions(MathSubstitutionsX86.class);
-            replacements.registerSubstitutions(DoubleSubstitutions.class);
-            replacements.registerSubstitutions(FloatSubstitutions.class);
-            replacements.registerSubstitutions(LongSubstitutions.class);
-            replacements.registerSubstitutions(IntegerSubstitutions.class);
-            replacements.registerSubstitutions(CharacterSubstitutions.class);
-            replacements.registerSubstitutions(ShortSubstitutions.class);
-            replacements.registerSubstitutions(UnsignedMathSubstitutions.class);
+            replacements.registerSubstitutions(Array.class, ArraySubstitutions.class);
+            replacements.registerSubstitutions(Math.class, MathSubstitutionsX86.class);
+            replacements.registerSubstitutions(Double.class, DoubleSubstitutions.class);
+            replacements.registerSubstitutions(Float.class, FloatSubstitutions.class);
+            replacements.registerSubstitutions(Long.class, LongSubstitutions.class);
+            replacements.registerSubstitutions(Integer.class, IntegerSubstitutions.class);
+            replacements.registerSubstitutions(Character.class, CharacterSubstitutions.class);
+            replacements.registerSubstitutions(Short.class, ShortSubstitutions.class);
+            replacements.registerSubstitutions(UnsignedMath.class, UnsignedMathSubstitutions.class);
         }
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue May 27 21:20:01 2014 -0700
@@ -29,6 +29,7 @@
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
 
 import sun.misc.*;
 
@@ -68,28 +69,165 @@
      */
     protected final ConcurrentMap<ResolvedJavaMethod, StructuredGraph> graphs;
 
-    // These data structures are all fully initialized during single-threaded
-    // compiler startup and so do not need to be concurrent.
-    protected final Map<ResolvedJavaMethod, ResolvedJavaMethod> registeredMethodSubstitutions;
-    private final Map<ResolvedJavaMethod, Class<? extends FixedWithNextNode>> registeredMacroSubstitutions;
-    private final Set<ResolvedJavaMethod> forcedSubstitutions;
+    /**
+     * Encapsulates method and macro substitutions for a single class.
+     */
+    protected class ClassReplacements {
+        protected final Map<ResolvedJavaMethod, ResolvedJavaMethod> methodSubstitutions = new HashMap<>();
+        private final Map<ResolvedJavaMethod, Class<? extends FixedWithNextNode>> macroSubstitutions = new HashMap<>();
+        private final Set<ResolvedJavaMethod> forcedSubstitutions = new HashSet<>();
+
+        public ClassReplacements(Class<?>[] substitutionClasses, AtomicReference<ClassReplacements> ref) {
+            for (Class<?> substitutionClass : substitutionClasses) {
+                ClassSubstitution classSubstitution = substitutionClass.getAnnotation(ClassSubstitution.class);
+                assert !Snippets.class.isAssignableFrom(substitutionClass);
+                SubstitutionGuard defaultGuard = getGuard(classSubstitution.defaultGuard());
+                for (Method substituteMethod : substitutionClass.getDeclaredMethods()) {
+                    if (ref.get() != null) {
+                        // Bail if another thread beat us creating the substitutions
+                        return;
+                    }
+                    MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class);
+                    MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class);
+                    if (methodSubstitution == null && macroSubstitution == null) {
+                        continue;
+                    }
+
+                    int modifiers = substituteMethod.getModifiers();
+                    if (!Modifier.isStatic(modifiers)) {
+                        throw new GraalInternalError("Substitution methods must be static: " + substituteMethod);
+                    }
+
+                    if (methodSubstitution != null) {
+                        SubstitutionGuard guard = getGuard(methodSubstitution.guard());
+                        if (guard == null) {
+                            guard = defaultGuard;
+                        }
+
+                        if (macroSubstitution != null && macroSubstitution.isStatic() != methodSubstitution.isStatic()) {
+                            throw new GraalInternalError("Macro and method substitution must agree on isStatic attribute: " + substituteMethod);
+                        }
+                        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+                            throw new GraalInternalError("Substitution method must not be abstract or native: " + substituteMethod);
+                        }
+                        String originalName = originalName(substituteMethod, methodSubstitution.value());
+                        JavaSignature originalSignature = originalSignature(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic());
+                        Member originalMethod = originalMethod(classSubstitution, methodSubstitution.optional(), originalName, originalSignature);
+                        if (originalMethod != null && (guard == null || guard.execute())) {
+                            ResolvedJavaMethod original = registerMethodSubstitution(this, originalMethod, substituteMethod);
+                            if (original != null && methodSubstitution.forced() && shouldIntrinsify(original)) {
+                                forcedSubstitutions.add(original);
+                            }
+                        }
+                    }
+                    // We don't have per method guards for macro substitutions but at
+                    // least respect the defaultGuard if there is one.
+                    if (macroSubstitution != null && (defaultGuard == null || defaultGuard.execute())) {
+                        String originalName = originalName(substituteMethod, macroSubstitution.value());
+                        JavaSignature originalSignature = originalSignature(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic());
+                        Member originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalSignature);
+                        if (originalMethod != null) {
+                            ResolvedJavaMethod original = registerMacroSubstitution(this, originalMethod, macroSubstitution.macro());
+                            if (original != null && macroSubstitution.forced() && shouldIntrinsify(original)) {
+                                forcedSubstitutions.add(original);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private JavaSignature originalSignature(Method substituteMethod, String methodSubstitution, boolean isStatic) {
+            Class<?>[] parameters;
+            Class<?> returnType;
+            if (methodSubstitution.isEmpty()) {
+                parameters = substituteMethod.getParameterTypes();
+                if (!isStatic) {
+                    assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter";
+                    parameters = Arrays.copyOfRange(parameters, 1, parameters.length);
+                }
+                returnType = substituteMethod.getReturnType();
+            } else {
+                Signature signature = providers.getMetaAccess().parseMethodDescriptor(methodSubstitution);
+                parameters = new Class[signature.getParameterCount(false)];
+                for (int i = 0; i < parameters.length; i++) {
+                    parameters[i] = resolveClass(signature.getParameterType(i, null));
+                }
+                returnType = resolveClass(signature.getReturnType(null));
+            }
+            return new JavaSignature(returnType, parameters);
+        }
+
+        private Member originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, JavaSignature signature) {
+            Class<?> originalClass = classSubstitution.value();
+            if (originalClass == ClassSubstitution.class) {
+                originalClass = resolveClass(classSubstitution.className(), classSubstitution.optional());
+                if (originalClass == null) {
+                    // optional class was not found
+                    return null;
+                }
+            }
+            try {
+                if (name.equals("<init>")) {
+                    assert signature.returnType.equals(void.class) : signature;
+                    Constructor<?> original = originalClass.getDeclaredConstructor(signature.parameters);
+                    return original;
+                } else {
+                    Method original = originalClass.getDeclaredMethod(name, signature.parameters);
+                    if (!original.getReturnType().equals(signature.returnType)) {
+                        throw new NoSuchMethodException(originalClass.getName() + "." + name + signature);
+                    }
+                    return original;
+                }
+            } catch (NoSuchMethodException | SecurityException e) {
+                if (optional) {
+                    return null;
+                }
+                throw new GraalInternalError(e);
+            }
+        }
+    }
+
+    /**
+     * Per-class replacements. The entries in these maps are all fully initialized during
+     * single-threaded compiler startup and so do not need to be concurrent.
+     */
+    private final Map<String, AtomicReference<ClassReplacements>> classReplacements;
+    private final Map<String, Class<?>[]> internalNameToSubstitutionClasses;
+
     private final Map<Class<? extends SnippetTemplateCache>, SnippetTemplateCache> snippetTemplateCache;
 
     public ReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, Assumptions assumptions, TargetDescription target) {
         this.providers = providers.copyWith(this);
+        this.classReplacements = new HashMap<>();
+        this.internalNameToSubstitutionClasses = new HashMap<>();
         this.snippetReflection = snippetReflection;
         this.target = target;
         this.assumptions = assumptions;
         this.graphs = new ConcurrentHashMap<>();
-        this.registeredMethodSubstitutions = new HashMap<>();
-        this.registeredMacroSubstitutions = new HashMap<>();
-        this.forcedSubstitutions = new HashSet<>();
         this.snippetTemplateCache = new HashMap<>();
     }
 
     private static final boolean UseSnippetGraphCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetGraphCache", "true"));
     private static final DebugTimer SnippetPreparationTime = Debug.timer("SnippetPreparationTime");
 
+    /**
+     * Gets the method and macro replacements for a given class. This method will parse the
+     * replacements in the substitution classes associated with {@code internalName} the first time
+     * this method is called for {@code internalName}.
+     */
+    protected ClassReplacements getClassReplacements(String internalName) {
+        Class<?>[] substitutionClasses = internalNameToSubstitutionClasses.get(internalName);
+        if (substitutionClasses != null) {
+            AtomicReference<ClassReplacements> crRef = classReplacements.get(internalName);
+            if (crRef.get() == null) {
+                crRef.compareAndSet(null, new ClassReplacements(substitutionClasses, crRef));
+            }
+            return crRef.get();
+        }
+        return null;
+    }
+
     public StructuredGraph getSnippet(ResolvedJavaMethod method) {
         return getSnippet(method, null);
     }
@@ -133,7 +271,8 @@
 
     @Override
     public StructuredGraph getMethodSubstitution(ResolvedJavaMethod original) {
-        ResolvedJavaMethod substitute = registeredMethodSubstitutions.get(original);
+        ClassReplacements cr = getClassReplacements(original.getDeclaringClass().getName());
+        ResolvedJavaMethod substitute = cr == null ? null : cr.methodSubstitutions.get(original);
         if (substitute == null) {
             return null;
         }
@@ -150,7 +289,8 @@
     }
 
     public Class<? extends FixedWithNextNode> getMacroSubstitution(ResolvedJavaMethod method) {
-        return registeredMacroSubstitutions.get(method);
+        ClassReplacements cr = getClassReplacements(method.getDeclaringClass().getName());
+        return cr == null ? null : cr.macroSubstitutions.get(method);
     }
 
     public Assumptions getAssumptions() {
@@ -168,59 +308,29 @@
         return null;
     }
 
-    public void registerSubstitutions(Class<?> substitutions) {
-        ClassSubstitution classSubstitution = substitutions.getAnnotation(ClassSubstitution.class);
-        assert classSubstitution != null;
-        assert !Snippets.class.isAssignableFrom(substitutions);
-        SubstitutionGuard defaultGuard = getGuard(classSubstitution.defaultGuard());
-        for (Method substituteMethod : substitutions.getDeclaredMethods()) {
-            MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class);
-            MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class);
-            if (methodSubstitution == null && macroSubstitution == null) {
-                continue;
-            }
-
-            int modifiers = substituteMethod.getModifiers();
-            if (!Modifier.isStatic(modifiers)) {
-                throw new GraalInternalError("Substitution methods must be static: " + substituteMethod);
-            }
-
-            if (methodSubstitution != null) {
-                SubstitutionGuard guard = getGuard(methodSubstitution.guard());
-                if (guard == null) {
-                    guard = defaultGuard;
-                }
+    private static String getOriginalInternalName(Class<?> substitutions) {
+        ClassSubstitution cs = substitutions.getAnnotation(ClassSubstitution.class);
+        assert cs != null : substitutions + " must be annotated by " + ClassSubstitution.class.getSimpleName();
+        if (cs.value() == ClassSubstitution.class) {
+            return toInternalName(cs.className());
+        }
+        return toInternalName(cs.value().getName());
+    }
 
-                if (macroSubstitution != null && macroSubstitution.isStatic() != methodSubstitution.isStatic()) {
-                    throw new GraalInternalError("Macro and method substitution must agree on isStatic attribute: " + substituteMethod);
-                }
-                if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
-                    throw new GraalInternalError("Substitution method must not be abstract or native: " + substituteMethod);
-                }
-                String originalName = originalName(substituteMethod, methodSubstitution.value());
-                JavaSignature originalSignature = originalSignature(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic());
-                Member originalMethod = originalMethod(classSubstitution, methodSubstitution.optional(), originalName, originalSignature);
-                if (originalMethod != null && (guard == null || guard.execute())) {
-                    ResolvedJavaMethod original = registerMethodSubstitution(originalMethod, substituteMethod);
-                    if (original != null && methodSubstitution.forced() && shouldIntrinsify(original)) {
-                        forcedSubstitutions.add(original);
-                    }
-                }
-            }
-            // We don't have per method guards for macro substitutions but at
-            // least respect the defaultGuard if there is one.
-            if (macroSubstitution != null && (defaultGuard == null || defaultGuard.execute())) {
-                String originalName = originalName(substituteMethod, macroSubstitution.value());
-                JavaSignature originalSignature = originalSignature(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic());
-                Member originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalSignature);
-                if (originalMethod != null) {
-                    ResolvedJavaMethod original = registerMacroSubstitution(originalMethod, macroSubstitution.macro());
-                    if (original != null && macroSubstitution.forced() && shouldIntrinsify(original)) {
-                        forcedSubstitutions.add(original);
-                    }
-                }
-            }
+    public void registerSubstitutions(Type original, Class<?> substitutionClass) {
+        String internalName = toInternalName(original.getTypeName());
+        assert getOriginalInternalName(substitutionClass).equals(internalName) : getOriginalInternalName(substitutionClass) + " != " + (internalName);
+        Class<?>[] classes = internalNameToSubstitutionClasses.get(internalName);
+        if (classes == null) {
+            classes = new Class<?>[]{substitutionClass};
+        } else {
+            assert !Arrays.asList(classes).contains(substitutionClass);
+            classes = Arrays.copyOf(classes, classes.length + 1);
+            classes[classes.length - 1] = substitutionClass;
         }
+        internalNameToSubstitutionClasses.put(internalName, classes);
+        AtomicReference<ClassReplacements> existing = classReplacements.put(internalName, new AtomicReference<>());
+        assert existing == null || existing.get() == null;
     }
 
     /**
@@ -230,7 +340,7 @@
      * @param substituteMethod the substitute method
      * @return the original method
      */
-    protected ResolvedJavaMethod registerMethodSubstitution(Member originalMember, Method substituteMethod) {
+    protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Member originalMember, Method substituteMethod) {
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         ResolvedJavaMethod substitute = metaAccess.lookupJavaMethod(substituteMethod);
         ResolvedJavaMethod original;
@@ -243,7 +353,7 @@
             Debug.log("substitution: %s --> %s", MetaUtil.format("%H.%n(%p) %r", original), MetaUtil.format("%H.%n(%p) %r", substitute));
         }
 
-        registeredMethodSubstitutions.put(original, substitute);
+        cr.methodSubstitutions.put(original, substitute);
         return original;
     }
 
@@ -254,7 +364,7 @@
      * @param macro the substitute macro node class
      * @return the original method
      */
-    protected ResolvedJavaMethod registerMacroSubstitution(Member originalMethod, Class<? extends FixedWithNextNode> macro) {
+    protected ResolvedJavaMethod registerMacroSubstitution(ClassReplacements cr, Member originalMethod, Class<? extends FixedWithNextNode> macro) {
         ResolvedJavaMethod originalJavaMethod;
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         if (originalMethod instanceof Method) {
@@ -262,7 +372,7 @@
         } else {
             originalJavaMethod = metaAccess.lookupJavaConstructor((Constructor<?>) originalMethod);
         }
-        registeredMacroSubstitutions.put(originalJavaMethod, macro);
+        cr.macroSubstitutions.put(originalJavaMethod, macro);
         return originalJavaMethod;
     }
 
@@ -551,7 +661,7 @@
      * @param optional if true, resolution failure returns null
      * @return the resolved class or null if resolution fails and {@code optional} is true
      */
-    static Class<?> resolveType(String className, boolean optional) {
+    static Class<?> resolveClass(String className, boolean optional) {
         try {
             // Need to use launcher class path to handle classes
             // that are not on the boot class path
@@ -565,7 +675,7 @@
         }
     }
 
-    private static Class<?> resolveType(JavaType type) {
+    private static Class<?> resolveClass(JavaType type) {
         JavaType base = type;
         int dimensions = 0;
         while (base.getComponentType() != null) {
@@ -573,7 +683,7 @@
             dimensions++;
         }
 
-        Class<?> baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base), false);
+        Class<?> baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveClass(toJavaName(base), false);
         return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass();
     }
 
@@ -599,67 +709,21 @@
         }
     }
 
-    private JavaSignature originalSignature(Method substituteMethod, String methodSubstitution, boolean isStatic) {
-        Class<?>[] parameters;
-        Class<?> returnType;
-        if (methodSubstitution.isEmpty()) {
-            parameters = substituteMethod.getParameterTypes();
-            if (!isStatic) {
-                assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter";
-                parameters = Arrays.copyOfRange(parameters, 1, parameters.length);
-            }
-            returnType = substituteMethod.getReturnType();
-        } else {
-            Signature signature = providers.getMetaAccess().parseMethodDescriptor(methodSubstitution);
-            parameters = new Class[signature.getParameterCount(false)];
-            for (int i = 0; i < parameters.length; i++) {
-                parameters[i] = resolveType(signature.getParameterType(i, null));
-            }
-            returnType = resolveType(signature.getReturnType(null));
-        }
-        return new JavaSignature(returnType, parameters);
-    }
-
-    private static Member originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, JavaSignature signature) {
-        Class<?> originalClass = classSubstitution.value();
-        if (originalClass == ClassSubstitution.class) {
-            originalClass = resolveType(classSubstitution.className(), classSubstitution.optional());
-            if (originalClass == null) {
-                // optional class was not found
-                return null;
-            }
-        }
-        try {
-            if (name.equals("<init>")) {
-                assert signature.returnType.equals(void.class) : signature;
-                Constructor<?> original = originalClass.getDeclaredConstructor(signature.parameters);
-                return original;
-            } else {
-                Method original = originalClass.getDeclaredMethod(name, signature.parameters);
-                if (!original.getReturnType().equals(signature.returnType)) {
-                    throw new NoSuchMethodException(originalClass.getName() + "." + name + signature);
-                }
-                return original;
-            }
-        } catch (NoSuchMethodException | SecurityException e) {
-            if (optional) {
-                return null;
-            }
-            throw new GraalInternalError(e);
-        }
-    }
-
     @Override
     public Collection<ResolvedJavaMethod> getAllReplacements() {
         HashSet<ResolvedJavaMethod> result = new HashSet<>();
-        result.addAll(registeredMethodSubstitutions.keySet());
-        result.addAll(registeredMacroSubstitutions.keySet());
+        for (String internalName : classReplacements.keySet()) {
+            ClassReplacements cr = getClassReplacements(internalName);
+            result.addAll(cr.methodSubstitutions.keySet());
+            result.addAll(cr.macroSubstitutions.keySet());
+        }
         return result;
     }
 
     @Override
     public boolean isForcedSubstitution(ResolvedJavaMethod method) {
-        return forcedSubstitutions.contains(method);
+        ClassReplacements cr = getClassReplacements(method.getDeclaringClass().getName());
+        return cr != null && cr.forcedSubstitutions.contains(method);
     }
 
     @Override
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue May 27 21:20:01 2014 -0700
@@ -33,6 +33,7 @@
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -78,8 +79,51 @@
     public static class SnippetInfo {
 
         protected final ResolvedJavaMethod method;
-        protected final boolean[] constantParameters;
-        protected final boolean[] varargsParameters;
+
+        /**
+         * Lazily constructed parts of {@link SnippetInfo}.
+         */
+        static class Lazy {
+            public Lazy(ResolvedJavaMethod method) {
+                int count = method.getSignature().getParameterCount(false);
+                constantParameters = new boolean[count];
+                varargsParameters = new boolean[count];
+                for (int i = 0; i < count; i++) {
+                    constantParameters[i] = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method) != null;
+                    varargsParameters[i] = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method) != null;
+
+                    assert !constantParameters[i] || !varargsParameters[i] : "Parameter cannot be annotated with both @" + ConstantParameter.class.getSimpleName() + " and @" +
+                                    VarargsParameter.class.getSimpleName();
+                }
+
+                // Retrieve the names only when assertions are turned on.
+                assert initNames(method, count);
+            }
+
+            final boolean[] constantParameters;
+            final boolean[] varargsParameters;
+
+            /**
+             * The parameter names, taken from the local variables table. Only used for assertion
+             * checking, so use only within an assert statement.
+             */
+            String[] names;
+
+            private boolean initNames(ResolvedJavaMethod method, int parameterCount) {
+                names = new String[parameterCount];
+                int slotIdx = 0;
+                for (int i = 0; i < names.length; i++) {
+                    names[i] = method.getLocalVariableTable().getLocal(slotIdx, 0).getName();
+
+                    Kind kind = method.getSignature().getParameterKind(i);
+                    slotIdx += kind == Kind.Long || kind == Kind.Double ? 2 : 1;
+                }
+                return true;
+            }
+
+        }
+
+        protected final AtomicReference<Lazy> lazy = new AtomicReference<>(null);
 
         /**
          * Times instantiations of all templates derived form this snippet.
@@ -95,31 +139,18 @@
          */
         private final DebugMetric instantiationCounter;
 
-        /**
-         * The parameter names, taken from the local variables table. Only used for assertion
-         * checking, so use only within an assert statement.
-         */
-        protected final String[] names;
+        private Lazy lazy() {
+            if (lazy.get() == null) {
+                lazy.compareAndSet(null, new Lazy(method));
+            }
+            return lazy.get();
+        }
 
         protected SnippetInfo(ResolvedJavaMethod method) {
             this.method = method;
             instantiationCounter = Debug.metric("SnippetInstantiationCount[%s]", method);
             instantiationTimer = Debug.timer("SnippetInstantiationTime[%s]", 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];
-            for (int i = 0; i < count; i++) {
-                constantParameters[i] = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method) != null;
-                varargsParameters[i] = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method) != null;
-
-                assert !isConstantParameter(i) || !isVarargsParameter(i) : "Parameter cannot be annotated with both @" + ConstantParameter.class.getSimpleName() + " and @" +
-                                VarargsParameter.class.getSimpleName();
-            }
-
-            names = new String[count];
-            // Retrieve the names only when assertions are turned on.
-            assert initNames();
         }
 
         private int templateCount;
@@ -133,35 +164,28 @@
             }
         }
 
-        private boolean initNames() {
-            int slotIdx = 0;
-            for (int i = 0; i < names.length; i++) {
-                names[i] = method.getLocalVariableTable().getLocal(slotIdx, 0).getName();
-
-                Kind kind = method.getSignature().getParameterKind(i);
-                slotIdx += kind == Kind.Long || kind == Kind.Double ? 2 : 1;
-            }
-            return true;
-        }
-
         public ResolvedJavaMethod getMethod() {
             return method;
         }
 
         public int getParameterCount() {
-            return constantParameters.length;
+            return lazy().constantParameters.length;
         }
 
         public boolean isConstantParameter(int paramIdx) {
-            return constantParameters[paramIdx];
+            return lazy().constantParameters[paramIdx];
         }
 
         public boolean isVarargsParameter(int paramIdx) {
-            return varargsParameters[paramIdx];
+            return lazy().varargsParameters[paramIdx];
         }
 
         public String getParameterName(int paramIdx) {
-            return names[paramIdx];
+            String[] names = lazy().names;
+            if (names != null) {
+                return names[paramIdx];
+            }
+            return null;
         }
     }
 
@@ -223,7 +247,7 @@
 
         private boolean check(String name, boolean constParam, boolean varargsParam) {
             assert nextParamIdx < info.getParameterCount() : "too many parameters: " + name + "  " + this;
-            assert info.names[nextParamIdx] == null || info.names[nextParamIdx].equals(name) : "wrong parameter name: " + name + "  " + this;
+            assert info.getParameterName(nextParamIdx) == null || info.getParameterName(nextParamIdx).equals(name) : "wrong parameter name: " + name + "  " + this;
             assert constParam == info.isConstantParameter(nextParamIdx) : "Parameter " + (constParam ? "not " : "") + "annotated with @" + ConstantParameter.class.getSimpleName() + ": " + name +
                             "  " + this;
             assert varargsParam == info.isVarargsParameter(nextParamIdx) : "Parameter " + (varargsParam ? "not " : "") + "annotated with @" + VarargsParameter.class.getSimpleName() + ": " + name +
@@ -243,7 +267,7 @@
                 } else if (info.isVarargsParameter(i)) {
                     result.append("varargs ");
                 }
-                result.append(info.names[i]).append(" = ").append(values[i]);
+                result.append(info.getParameterName(i)).append(" = ").append(values[i]);
                 sep = ", ";
             }
             result.append(">");
@@ -260,8 +284,8 @@
                 for (int i = 0; i < info.getParameterCount(); i++) {
                     if (info.isConstantParameter(i)) {
                         sb.append(sep);
-                        if (info.names[i] != null) {
-                            sb.append(info.names[i]);
+                        if (info.getParameterName(i) != null) {
+                            sb.append(info.getParameterName(i));
                         } else {
                             sb.append(i);
                         }
@@ -418,25 +442,27 @@
             }
         }
 
+        private static Method findMethod(Class<? extends Snippets> declaringClass, String methodName, Method except) {
+            for (Method m : declaringClass.getDeclaredMethods()) {
+                if (m.getName().equals(methodName) && !m.equals(except)) {
+                    return m;
+                }
+            }
+            return null;
+        }
+
         /**
-         * Finds the method in {@code declaringClass} annotated with {@link Snippet} named
-         * {@code methodName}. If {@code methodName} is null, then there must be exactly one snippet
-         * method in {@code declaringClass}.
+         * Finds the unique method in {@code declaringClass} named {@code methodName} annotated by
+         * {@link Snippet} and returns a {@link SnippetInfo} value describing it. There must be
+         * exactly one snippet method in {@code declaringClass}.
          */
         protected SnippetInfo snippet(Class<? extends Snippets> declaringClass, String methodName) {
-            Method found = null;
-            Class<?> clazz = declaringClass;
-            while (clazz != Object.class) {
-                for (Method method : clazz.getDeclaredMethods()) {
-                    if (method.getAnnotation(Snippet.class) != null && (methodName == null || method.getName().equals(methodName))) {
-                        assert found == null : "found more than one @" + Snippet.class.getSimpleName() + " method in " + declaringClass + (methodName == null ? "" : " named " + methodName);
-                        found = method;
-                    }
-                }
-                clazz = clazz.getSuperclass();
-            }
-            assert found != null : "did not find @" + Snippet.class.getSimpleName() + " method in " + declaringClass + (methodName == null ? "" : " named " + methodName);
-            ResolvedJavaMethod javaMethod = providers.getMetaAccess().lookupJavaMethod(found);
+            assert methodName != null;
+            Method method = findMethod(declaringClass, methodName, null);
+            assert method != null : "did not find @" + Snippet.class.getSimpleName() + " method in " + declaringClass + " named " + methodName;
+            assert method.getAnnotation(Snippet.class) != null : method + " must be annotated with @" + Snippet.class.getSimpleName();
+            assert findMethod(declaringClass, methodName, method) == null : "found more than one method named " + methodName + " in " + declaringClass;
+            ResolvedJavaMethod javaMethod = providers.getMetaAccess().lookupJavaMethod(method);
             providers.getReplacements().registerSnippet(javaMethod);
             return new SnippetInfo(javaMethod);
         }
@@ -797,14 +823,14 @@
         assert args.info.getParameterCount() == parameters.length : "number of args (" + args.info.getParameterCount() + ") != number of parameters (" + parameters.length + ")";
         for (int i = 0; i < parameters.length; i++) {
             Object parameter = parameters[i];
-            assert parameter != null : this + " has no parameter named " + args.info.names[i];
+            assert parameter != null : this + " has no parameter named " + args.info.getParameterName(i);
             Object argument = args.values[i];
             if (parameter instanceof ParameterNode) {
                 if (argument instanceof ValueNode) {
                     replacements.put((ParameterNode) parameter, (ValueNode) argument);
                 } else {
                     Kind kind = ((ParameterNode) parameter).getKind();
-                    assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + args.info.names[i];
+                    assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + args.info.getParameterName(i);
                     Constant constant = forBoxed(argument, kind);
                     replacements.put((ParameterNode) parameter, ConstantNode.forConstant(constant, metaAccess, replaceeGraph));
                 }
@@ -836,7 +862,7 @@
                     }
                 }
             } else {
-                assert parameter == CONSTANT_PARAMETER || parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + args.info.names[i] + " -> " + parameter;
+                assert parameter == CONSTANT_PARAMETER || parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + args.info.getParameterName(i) + " -> " + parameter;
             }
         }
         return replacements;
@@ -1253,12 +1279,12 @@
         for (int i = 0; i < args.info.getParameterCount(); i++) {
             if (args.info.isConstantParameter(i)) {
                 Kind kind = signature.getParameterKind(i);
-                assert checkConstantArgument(metaAccess, method, signature, i, args.info.names[i], args.values[i], kind);
+                assert checkConstantArgument(metaAccess, method, signature, i, args.info.getParameterName(i), args.values[i], kind);
 
             } else if (args.info.isVarargsParameter(i)) {
                 assert args.values[i] instanceof Varargs;
                 Varargs varargs = (Varargs) args.values[i];
-                assert checkVarargs(metaAccess, method, signature, i, args.info.names[i], varargs);
+                assert checkVarargs(metaAccess, method, signature, i, args.info.getParameterName(i), varargs);
             }
         }
         return true;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GCAfterTestDecorator.java	Tue May 27 21:20:01 2014 -0700
@@ -0,0 +1,38 @@
+/*
+ * 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.test;
+
+import org.junit.runner.*;
+
+public class GCAfterTestDecorator extends GraalJUnitRunListenerDecorator {
+
+    public GCAfterTestDecorator(GraalJUnitRunListener l) {
+        super(l);
+    }
+
+    @Override
+    public void testFinished(Description description) {
+        System.gc();
+        super.testFinished(description);
+    }
+}
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitCore.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitCore.java	Tue May 27 21:20:01 2014 -0700
@@ -51,6 +51,7 @@
         boolean enableTiming = false;
         boolean color = false;
         boolean eagerStackTrace = false;
+        boolean gcAfterTest = false;
         for (String each : args) {
             if (each.charAt(0) == '-') {
                 // command line arguments
@@ -62,6 +63,8 @@
                     color = true;
                 } else if (each.contentEquals("-JUnitEagerStackTrace")) {
                     eagerStackTrace = true;
+                } else if (each.contentEquals("-JUnitGCAfterTest")) {
+                    gcAfterTest = true;
                 } else {
                     system.out().println("Unknown command line argument: " + each);
                 }
@@ -92,6 +95,9 @@
         if (eagerStackTrace) {
             graalListener = new EagerStackTraceDecorator(graalListener);
         }
+        if (gcAfterTest) {
+            graalListener = new GCAfterTestDecorator(graalListener);
+        }
         junitCore.addListener(GraalTextListener.createRunListener(graalListener));
         Result result = junitCore.run(classes.toArray(new Class[0]));
         for (Failure each : missingClasses) {
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Tue May 27 21:20:01 2014 -0700
@@ -38,7 +38,7 @@
     public ExactMathTest() {
         if (!substitutionsInstalled) {
             Replacements replacements = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders().getReplacements();
-            replacements.registerSubstitutions(ExactMathSubstitutions.class);
+            replacements.registerSubstitutions(ExactMath.class, ExactMathSubstitutions.class);
             substitutionsInstalled = true;
         }
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Tue May 27 21:18:45 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Tue May 27 21:20:01 2014 -0700
@@ -32,6 +32,7 @@
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.truffle.substitutions.*;
+import com.oracle.truffle.api.*;
 
 /**
  * Custom {@link Replacements} for Truffle compilation.
@@ -48,11 +49,11 @@
     }
 
     protected void registerTruffleSubstitutions() {
-        registerSubstitutions(CompilerAssertsSubstitutions.class);
-        registerSubstitutions(CompilerDirectivesSubstitutions.class);
-        registerSubstitutions(ExactMathSubstitutions.class);
-        registerSubstitutions(OptimizedAssumptionSubstitutions.class);
-        registerSubstitutions(OptimizedCallTargetSubstitutions.class);
+        registerSubstitutions(CompilerAsserts.class, CompilerAssertsSubstitutions.class);
+        registerSubstitutions(CompilerDirectives.class, CompilerDirectivesSubstitutions.class);
+        registerSubstitutions(ExactMath.class, ExactMathSubstitutions.class);
+        registerSubstitutions(OptimizedAssumption.class, OptimizedAssumptionSubstitutions.class);
+        registerSubstitutions(OptimizedCallTarget.class, OptimizedCallTargetSubstitutions.class);
     }
 
     @Override
--- a/hotspot/.cproject	Tue May 27 21:18:45 2014 -0700
+++ b/hotspot/.cproject	Tue May 27 21:20:01 2014 -0700
@@ -1,7 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<?fileVersion 4.0.0?>
-
-<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
 	<storageModule moduleId="org.eclipse.cdt.core.settings">
 		<cconfiguration id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881">
 			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881" moduleId="org.eclipse.cdt.core.settings" name="Default">
@@ -27,7 +25,9 @@
 							</builder>
 							<tool id="cdt.managedbuild.tool.gnu.archiver.base.1094883386" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
 							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1342888057" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
-								<option id="gnu.cpp.compiler.option.include.paths.801956928" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths"/>
+								<option id="gnu.cpp.compiler.option.include.paths.801956928" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/com.oracle.graal.hotspot/src_gen/hotspot}&quot;"/>
+								</option>
 								<option id="gnu.cpp.compiler.option.preprocessor.def.634868600" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
 									<listOptionValue builtIn="false" value="_LP64=1"/>
 									<listOptionValue builtIn="false" value="COMPILER1=1"/>
@@ -74,11 +74,6 @@
 							</tool>
 						</toolChain>
 					</folderInfo>
-					<fileInfo id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.426128354" name="addnode.cpp" rcbsApplicability="disable" resourcePath="vm/opto/addnode.cpp" toolsToInvoke="cdt.managedbuild.tool.gnu.cpp.compiler.base.1342888057.211119144">
-						<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1342888057.211119144" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base.1342888057">
-							<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.202578082" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
-						</tool>
-					</fileInfo>
 					<sourceEntries>
 						<entry excluding="cpu/vm/templateTable_x86_32.cpp|cpu/vm/templateInterpreter_x86_32.cpp|cpu/vm/stubRoutines_x86_32.cpp|cpu/vm/stubGenerator_x86_32.cpp|cpu/vm/sharedRuntime_x86_32.cpp|cpu/vm/jniFastGetField_x86_32.cpp|cpu/vm/interpreterRT_x86_32.cpp|cpu/vm/interpreter_x86_32.cpp|cpu/vm/interp_masm_x86_32.cpp|cpu/vm/vtableStubs_x86_32.cpp" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
 					</sourceEntries>
--- a/hotspot/.project	Tue May 27 21:18:45 2014 -0700
+++ b/hotspot/.project	Tue May 27 21:20:01 2014 -0700
@@ -96,7 +96,17 @@
 			<locationURI>PARENT-1-PROJECT_LOC/src/os_cpu/bsd_x86/vm</locationURI>
 		</link>
 		<link>
-			<name>generated</name>
+			<name>generated_compiler1</name>
+			<type>2</type>
+			<locationURI>PARENT-1-PROJECT_LOC/build/linux/linux_amd64_compiler1/generated</locationURI>
+		</link>
+		<link>
+			<name>generated_compiler2</name>
+			<type>2</type>
+			<locationURI>PARENT-1-PROJECT_LOC/build/linux/linux_amd64_compiler2/generated</locationURI>
+		</link>
+		<link>
+			<name>generated_graal</name>
 			<type>2</type>
 			<locationURI>PARENT-1-PROJECT_LOC/build/linux/linux_amd64_graal/generated</locationURI>
 		</link>
--- a/mx/mx_graal.py	Tue May 27 21:18:45 2014 -0700
+++ b/mx/mx_graal.py	Tue May 27 21:20:01 2014 -0700
@@ -484,27 +484,21 @@
         if exists(toDelete):
             os.unlink(toDelete)
 
-def _update_HotSpotOptions_inline_hpp(graalJar):
-    p = mx.project('com.oracle.graal.hotspot')
-    mainClass = 'com.oracle.graal.hotspot.HotSpotOptionsLoader'
-    assert exists(join(p.source_dirs()[0], mainClass.replace('.', os.sep) + '.java'))
-    hsSrcGenDir = join(p.source_gen_dir(), 'hotspot')
-    if not exists(hsSrcGenDir):
-        os.makedirs(hsSrcGenDir)
-    tmp = StringIO.StringIO()
-    retcode = mx.run_java(['-cp', graalJar, mainClass], out=tmp.write, nonZeroIsFatal=False)
-    if retcode != 0:
-        # Suppress the error if it's because the utility class isn't compiled yet
-        with zipfile.ZipFile(graalJar, 'r') as zf:
-            mainClassFile = mainClass.replace('.', '/') + '.class'
-            if mainClassFile not in zf.namelist():
-                return
-        mx.abort(retcode)
-    mx.update_file(join(hsSrcGenDir, 'HotSpotOptions.inline.hpp'), tmp.getvalue())
+def _update_graalRuntime_inline_hpp(graalJar):
+    p = mx.project('com.oracle.graal.hotspot.sourcegen')
+    mainClass = 'com.oracle.graal.hotspot.sourcegen.GenGraalRuntimeInlineHpp'
+    if exists(join(p.output_dir(), mainClass.replace('.', os.sep) + '.class')):
+        hsSrcGenDir = join(mx.project('com.oracle.graal.hotspot').source_gen_dir(), 'hotspot')
+        if not exists(hsSrcGenDir):
+            os.makedirs(hsSrcGenDir)
+
+        tmp = StringIO.StringIO()
+        mx.run_java(['-cp', '{}{}{}'.format(graalJar, os.pathsep, p.output_dir()), mainClass], out=tmp.write)
+        mx.update_file(join(hsSrcGenDir, 'graalRuntime.inline.hpp'), tmp.getvalue())
 
 def _installGraalJarInJdks(graalDist):
     graalJar = graalDist.path
-    _update_HotSpotOptions_inline_hpp(graalJar)
+    _update_graalRuntime_inline_hpp(graalJar)
     jdks = _jdksDir()
 
     if exists(jdks):
@@ -976,7 +970,7 @@
         f_testfile.close()
         harness(projectscp, vmArgs)
 
-def _unittest(args, annotations, prefixcp="", whitelist=None, verbose=False, enable_timing=False, regex=None, color=False, eager_stacktrace=False):
+def _unittest(args, annotations, prefixcp="", whitelist=None, verbose=False, enable_timing=False, regex=None, color=False, eager_stacktrace=False, gc_after_test=False):
     mxdir = dirname(__file__)
     name = 'JUnitWrapper'
     javaSource = join(mxdir, name + '.java')
@@ -999,6 +993,8 @@
         coreArgs.append('-JUnitColor')
     if eager_stacktrace:
         coreArgs.append('-JUnitEagerStackTrace')
+    if gc_after_test:
+        coreArgs.append('-JUnitGCAfterTest')
 
 
     def harness(projectscp, vmArgs):
@@ -1031,6 +1027,7 @@
       --regex <regex>        run only testcases matching a regular expression
       --color                enable colors output
       --eager-stacktrace     print stacktrace eagerly
+      --gc-after-test        force a GC after each test
 
     To avoid conflicts with VM options '--' can be used as delimiter.
 
@@ -1073,6 +1070,7 @@
     parser.add_argument('--regex', help='run only testcases matching a regular expression', metavar='<regex>')
     parser.add_argument('--color', help='enable color output', action='store_true')
     parser.add_argument('--eager-stacktrace', help='print stacktrace eagerly', action='store_true')
+    parser.add_argument('--gc-after-test', help='force a GC after each test', action='store_true')
 
     ut_args = []
     delimiter = False
@@ -1830,7 +1828,7 @@
         out = args[0]
     elif len(args) > 1:
         mx.abort('jacocoreport takes only one argument : an output directory')
-    mx.run_java(['-jar', jacocoreport.get_path(True), '-in', 'jacoco.exec', '-g', join(_graal_home, 'graal'), out])
+    mx.run_java(['-jar', jacocoreport.get_path(True), '--in', 'jacoco.exec', '--out', out] + [p.dir for p in mx.projects()])
 
 def sl(args):
     """run an SL program"""
--- a/mx/projects	Tue May 27 21:18:45 2014 -0700
+++ b/mx/projects	Tue May 27 21:20:01 2014 -0700
@@ -36,8 +36,8 @@
 library@JACOCOAGENT@sha1=2f73a645b02e39290e577ce555f00b02004650b0
 
 library@JACOCOREPORT@path=lib/jacocoreport.jar
-library@JACOCOREPORT@urls=http://lafo.ssw.uni-linz.ac.at/jacoco/jacocoreport-0.7.1-1.jar
-library@JACOCOREPORT@sha1=0c5db714804416dd1df4d8110762136ce3d5c7dc
+library@JACOCOREPORT@urls=http://lafo.ssw.uni-linz.ac.at/jacoco/jacocoreport-0.7.1-2.jar
+library@JACOCOREPORT@sha1=a630436391832d697a12c8f7daef8655d7a1efd2
 
 library@DACAPO_SCALA@path=lib/dacapo-scala-0.1.0-20120216.jar
 library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar
@@ -66,6 +66,7 @@
 library@VECMATH@sha1=a0ae4f51da409fa0c20fa0ca59e6bbc9413ae71d
 
 distribution@GRAAL@path=graal.jar
+distribution@GRAAL@subDir=graal
 distribution@GRAAL@sourcesPath=graal.src.zip
 distribution@GRAAL@dependencies=\
 com.oracle.graal.hotspot.amd64,\
@@ -79,11 +80,13 @@
 distribution@GRAAL@exclude=FINDBUGS
 
 distribution@TRUFFLE@path=truffle.jar
+distribution@TRUFFLE@subDir=graal
 distribution@TRUFFLE@sourcesPath=truffle-sources.jar
 distribution@TRUFFLE@dependencies=\
 com.oracle.truffle.api.dsl
 
 distribution@TRUFFLE-DSL-PROCESSOR@path=truffle-dsl-processor.jar
+distribution@TRUFFLE-DSL-PROCESSOR@subDir=graal
 distribution@TRUFFLE-DSL-PROCESSOR@sourcesPath=truffle-dsl-processor-sources.jar
 distribution@TRUFFLE-DSL-PROCESSOR@dependencies=\
 com.oracle.truffle.dsl.processor
@@ -201,6 +204,14 @@
 project@com.oracle.graal.hotspot@javaCompliance=1.8
 project@com.oracle.graal.hotspot@workingSets=Graal,HotSpot
 
+# graal.hotspot.sourcegen
+project@com.oracle.graal.hotspot.sourcegen@subDir=graal
+project@com.oracle.graal.hotspot.sourcegen@sourceDirs=src
+project@com.oracle.graal.hotspot.sourcegen@dependencies=com.oracle.graal.hotspot
+project@com.oracle.graal.hotspot.sourcegen@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.hotspot.sourcegen@javaCompliance=1.8
+project@com.oracle.graal.hotspot.sourcegen@workingSets=Graal,HotSpot
+
 # graal.hotspot.jfr
 project@com.oracle.graal.hotspot.jfr@subDir=graal
 project@com.oracle.graal.hotspot.jfr@sourceDirs=src
--- a/mxtool/URLConnectionDownload.java	Tue May 27 21:18:45 2014 -0700
+++ b/mxtool/URLConnectionDownload.java	Tue May 27 21:20:01 2014 -0700
@@ -42,9 +42,11 @@
 	 *            successful one
 	 */
     public static void main(String[] args) {
-    	File path = new File(args[0]);
-    	String[] urls = new String[args.length - 1];
-    	System.arraycopy(args, 1, urls, 0, urls.length);
+        File path = new File(args[0]);
+        boolean verbose = args[1].equals("-v");
+        int offset = verbose ? 2 : 1;
+        String[] urls = new String[args.length - offset];
+        System.arraycopy(args, offset, urls, 0, urls.length);
 
         File parent = path.getParentFile();
         makeDirectory(parent);
@@ -92,8 +94,10 @@
                 int n = 0;
                 while ((read = in.read(buf)) != -1) {
                     n += read;
-                    long percent = ((long) n * 100 / size);
-                    System.err.print("\r " + n + " bytes " + (size == -1 ? "" : " (" + percent + "%)"));
+                    if (verbose) {
+                        long percent = ((long) n * 100 / size);
+                        System.err.print("\r " + n + " bytes " + (size == -1 ? "" : " (" + percent + "%)"));
+                    }
                     out.write(buf, 0, read);
                 }
                 System.err.println();
--- a/mxtool/mx.py	Tue May 27 21:18:45 2014 -0700
+++ b/mxtool/mx.py	Tue May 27 21:20:01 2014 -0700
@@ -33,7 +33,7 @@
 Full documentation can be found at https://wiki.openjdk.java.net/display/Graal/The+mx+Tool
 """
 
-import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils, tempfile, fnmatch
+import sys, os, errno, time, subprocess, shlex, types, StringIO, zipfile, signal, xml.sax.saxutils, tempfile, fnmatch
 import multiprocessing
 import textwrap
 import socket
@@ -1525,8 +1525,11 @@
             # Don't make the reader thread a daemon otherwise output can be droppped
             t.start()
             joiners.append(t)
-        for t in joiners:
-            t.join()
+        while any([t.is_alive() for t in joiners]):
+            # Need to use timeout otherwise all signals (including CTRL-C) are blocked
+            # see: http://bugs.python.org/issue1167930
+            for t in joiners:
+                t.join(10)
         if timeout is None or timeout == 0:
             retcode = waitOn(p)
         else:
@@ -1883,60 +1886,18 @@
     if d != '' and not exists(d):
         os.makedirs(d)
 
-
-    if not path.endswith(os.sep):
-        # Try it with the Java tool first since it can show a progress counter
-        myDir = dirname(__file__)
-        javaSource = join(myDir, 'URLConnectionDownload.java')
-        javaClass = join(myDir, 'URLConnectionDownload.class')
-        if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
-            subprocess.check_call([java().javac, '-d', myDir, javaSource])
-        if run([java().java, '-cp', myDir, 'URLConnectionDownload', path] + urls, nonZeroIsFatal=False) == 0:
-            return
-
-    def url_open(url):
-        userAgent = 'Mozilla/5.0 (compatible)'
-        headers = {'User-Agent' : userAgent}
-        req = urllib2.Request(url, headers=headers)
-        return urllib2.urlopen(req)
-
-    for url in urls:
-        try:
-            if verbose:
-                log('Downloading ' + url + ' to ' + path)
-            if url.startswith('zip:') or url.startswith('jar:'):
-                i = url.find('!/')
-                if i == -1:
-                    abort('Zip or jar URL does not contain "!/": ' + url)
-                url, _, entry = url[len('zip:'):].partition('!/')
-                with contextlib.closing(url_open(url)) as f:
-                    data = f.read()
-                    zipdata = StringIO.StringIO(f.read())
-
-                zf = zipfile.ZipFile(zipdata, 'r')
-                data = zf.read(entry)
-                with open(path, 'wb') as f:
-                    f.write(data)
-            else:
-                with contextlib.closing(url_open(url)) as f:
-                    data = f.read()
-                if path.endswith(os.sep):
-                    # Scrape directory listing for relative URLs
-                    hrefs = re.findall(r' href="([^"]*)"', data)
-                    if len(hrefs) != 0:
-                        for href in hrefs:
-                            if not '/' in href:
-                                download(join(path, href), [url + href], verbose)
-                    else:
-                        log('no locals hrefs scraped from ' + url)
-                else:
-                    with open(path, 'wb') as f:
-                        f.write(data)
-            return
-        except IOError as e:
-            log('Error reading from ' + url + ': ' + str(e))
-        except zipfile.BadZipfile as e:
-            log('Error in zip file downloaded from ' + url + ': ' + str(e))
+    assert not path.endswith(os.sep)
+
+    myDir = dirname(__file__)
+    javaSource = join(myDir, 'URLConnectionDownload.java')
+    javaClass = join(myDir, 'URLConnectionDownload.class')
+    if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
+        subprocess.check_call([java().javac, '-d', myDir, javaSource])
+    verbose = []
+    if sys.stderr.isatty():
+        verbose.append("-v")
+    if run([java().java, '-cp', myDir, 'URLConnectionDownload', path] + verbose + urls, nonZeroIsFatal=False) == 0:
+        return
 
     abort('Could not download to ' + path + ' from any of the following URLs:\n\n    ' +
               '\n    '.join(urls) + '\n\nPlease use a web browser to do the download manually')
@@ -3340,10 +3301,6 @@
             refreshFile = os.path.relpath(join(p.dir, p.name + '.jar'), logicalWorkspaceRoot)
             _genEclipseBuilder(out, p, 'Jar', 'archive ' + p.name, refresh=True, refreshFile=refreshFile, relevantResources=[binFolder], async=True, xmlIndent='', xmlStandalone='no')
 
-        if projToDist.has_key(p.name):
-            dist, distDeps = projToDist[p.name]
-            _genEclipseBuilder(out, p, 'Create' + dist.name + 'Dist', 'archive @' + dist.name, relevantResources=[binFolder], logToFile=True, refresh=False, async=True)
-
         out.close('buildSpec')
         out.open('natures')
         out.element('nature', data='org.eclipse.jdt.core.javanature')
@@ -3422,6 +3379,43 @@
     _zip_files(files, suite.dir, configZip.path)
     _zip_files(libFiles, suite.dir, configLibsZip)
 
+    # Create an Eclipse project for each distribution that will create/update the archive
+    # for the distribution whenever any project of the distribution is updated.
+    for dist in suite.dists:
+        name = dist.name
+        if hasattr(dist, 'subDir'):
+            projectDir = join(suite.dir, dist.subDir, dist.name + '.dist')
+        else:
+            projectDir = join(suite.dir, dist.name + '.dist')
+        if not exists(projectDir):
+            os.makedirs(projectDir)
+        distProjects = [d for d in dist.sorted_deps() if d.isProject()]
+        relevantResources = []
+        for p in distProjects:
+            for srcDir in p.source_dirs():
+                relevantResources.append(join(p.name, os.path.relpath(srcDir, p.dir)))
+            relevantResources.append(join(p.name, os.path.relpath(p.output_dir(), p.dir)))
+        out = XMLDoc()
+        out.open('projectDescription')
+        out.element('name', data=dist.name)
+        out.element('comment', data='Updates ' + dist.path + ' if a project dependency of ' + dist.name + ' is updated')
+        out.open('projects')
+        for p in distProjects:
+            out.element('project', data=p.name)
+        out.close('projects')
+        out.open('buildSpec')
+        dist.dir = projectDir
+        dist.javaCompliance = max([p.javaCompliance for p in distProjects])
+        _genEclipseBuilder(out, dist, 'Create' + dist.name + 'Dist', 'archive @' + dist.name, relevantResources=relevantResources, logToFile=True, refresh=False, async=True)
+        out.close('buildSpec')
+        out.open('natures')
+        out.element('nature', data='org.eclipse.jdt.core.javanature')
+        out.close('natures')
+        out.close('projectDescription')
+        projectFile = join(projectDir, '.project')
+        update_file(projectFile, out.xml(indent='\t', newl='\n'))
+        files.append(projectFile)
+
 def _zip_files(files, baseDir, zipPath):
     fd, tmp = tempfile.mkstemp(suffix='', prefix=basename(zipPath), dir=baseDir)
     try:
--- a/src/share/vm/graal/graalRuntime.cpp	Tue May 27 21:18:45 2014 -0700
+++ b/src/share/vm/graal/graalRuntime.cpp	Tue May 27 21:20:01 2014 -0700
@@ -641,6 +641,13 @@
   return VMToCompiler::get_HotSpotGraalRuntime_jobject();
 JVM_END
 
+// private static String[] Graal.getServiceImpls(Class service)
+JVM_ENTRY(jobject, JVM_GetGraalServiceImpls(JNIEnv *env, jclass c, jclass serviceClass))
+  HandleMark hm;
+  KlassHandle serviceKlass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(serviceClass)));
+  return JNIHandles::make_local(THREAD, GraalRuntime::get_service_impls(serviceKlass, THREAD)());
+JVM_END
+
 // private static TruffleRuntime Truffle.createRuntime()
 JVM_ENTRY(jobject, JVM_CreateTruffleRuntime(JNIEnv *env, jclass c))
   return JNIHandles::make_local(VMToCompiler::create_HotSpotTruffleRuntime()());
@@ -683,7 +690,7 @@
     name = arg + 1;
     name_len = strlen(name);
     name_handle = java_lang_String::create_from_str(name, CHECK);
-    valid = set_option(hotSpotOptionsClass, name, name_len, name_handle, arg, CHECK);
+    valid = set_option(hotSpotOptionsClass, name, (int)name_len, name_handle, arg, CHECK);
   } else {
     char* sep = strchr(arg, '=');
     if (sep != NULL) {
@@ -696,7 +703,7 @@
       if (HAS_PENDING_EXCEPTION) {
         return;
       }
-      valid = set_option(hotSpotOptionsClass, name, name_len, name_handle, sep + 1, CHECK);
+      valid = set_option(hotSpotOptionsClass, name, (int)name_len, name_handle, sep + 1, CHECK);
     } else {
       char buf[200];
       jio_snprintf(buf, sizeof(buf), "Value for option %s must use '-G:%s=<value>' format", arg, arg);
@@ -714,7 +721,7 @@
 
 void GraalRuntime::parse_graal_options_file(KlassHandle hotSpotOptionsClass, TRAPS) {
   const char* home = Arguments::get_java_home();
-  int path_len = strlen(home) + strlen("/lib/graal.options") + 1;
+  int path_len = (int)strlen(home) + (int)strlen("/lib/graal.options") + 1;
   char* path = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, path_len);
   char sep = os::file_separator()[0];
   sprintf(path, "%s%clib%cgraal.options", home, sep, sep);
@@ -813,4 +820,16 @@
   return ret;
 }
 
-#include "HotSpotOptions.inline.hpp"
+Handle GraalRuntime::create_Service(const char* name, TRAPS) {
+  TempNewSymbol kname = SymbolTable::new_symbol(name, THREAD);
+  Klass* k = SystemDictionary::resolve_or_fail(kname, true, CHECK_NH);
+  instanceKlassHandle klass(THREAD, k);
+  klass->initialize(CHECK_NH);
+  klass->check_valid_for_instantiation(true, CHECK_NH);
+  JavaValue result(T_VOID);
+  instanceHandle service = klass->allocate_instance_handle(CHECK_NH);
+  JavaCalls::call_special(&result, service, klass, vmSymbols::object_initializer_name(), vmSymbols::void_method_signature(), THREAD);
+  return service;
+}
+
+#include "graalRuntime.inline.hpp"
--- a/src/share/vm/graal/graalRuntime.hpp	Tue May 27 21:18:45 2014 -0700
+++ b/src/share/vm/graal/graalRuntime.hpp	Tue May 27 21:20:01 2014 -0700
@@ -68,14 +68,35 @@
   /**
    * Searches for a Graal option denoted by a given name and sets it value.
    *
+   * The definition of this method is in graalRuntime.inline.hpp
+   * which is generated by com.oracle.graal.hotspot.sourcegen.GenGraalRuntimeInlineHpp.
+   *
    * @returns true if the option was found
    * @throws InternalError if there was a problem setting the option's value
    */
   static bool set_option(KlassHandle hotSpotOptionsClass, const char* name, int name_len, Handle name_handle, const char* value, TRAPS);
 
+  /**
+   * Instantiates a service object, calls its default constructor and returns it.
+   *
+   * @param name the name of a class implementing com.oracle.graal.api.runtime.Service
+   */
+  static Handle create_Service(const char* name, TRAPS);
+
  public:
 
   static void initialize_natives(JNIEnv *env, jclass c2vmClass);
+
+  /**
+   * Given an interface representing a Graal service (i.e. sub-interface of
+   * com.oracle.graal.api.runtime.Service), gets an array of objects, one per
+   * known implementation of the service.
+   *
+   * The definition of this method is in graalRuntime.inline.hpp
+   * which is generated by com.oracle.graal.hotspot.sourcegen.GenGraalRuntimeInlineHpp.
+   */
+  static Handle get_service_impls(KlassHandle serviceKlass, TRAPS);
+
   static BufferBlob* initialize_buffer_blob();
 
   static bool parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS);
--- a/src/share/vm/graal/graalVMToCompiler.hpp	Tue May 27 21:18:45 2014 -0700
+++ b/src/share/vm/graal/graalVMToCompiler.hpp	Tue May 27 21:20:01 2014 -0700
@@ -44,6 +44,9 @@
   static Handle VMToCompiler_instance();
 
 public:
+
+  static bool is_HotSpotGraalRuntime_initialized() { return _HotSpotGraalRuntime_instance != NULL; }
+
   // Gets the singleton HotSpotGraalRuntime instance, initializing it if necessary
   static Handle get_HotSpotGraalRuntime();
 
--- a/src/share/vm/oops/instanceKlass.cpp	Tue May 27 21:18:45 2014 -0700
+++ b/src/share/vm/oops/instanceKlass.cpp	Tue May 27 21:20:01 2014 -0700
@@ -59,6 +59,10 @@
 #include "services/threadService.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/macros.hpp"
+#ifdef GRAAL
+#include "classfile/javaAssertions.hpp"
+#include "graal/graalVMToCompiler.hpp"
+#endif
 #if INCLUDE_ALL_GCS
 #include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp"
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
@@ -1205,6 +1209,15 @@
 #ifdef GRAAL
   if (this_oop->is_subtype_of(SystemDictionary::Node_klass())) {
     if (this_oop() != SystemDictionary::Node_klass()) {
+      if (!VMToCompiler::is_HotSpotGraalRuntime_initialized() && JavaAssertions::systemClassDefault() == false) {
+        // We want to ensure that the process of initializing HotSpotGraalRuntime
+        // is fast since it executes at VM startup. We must avoid triggering
+        // class initialization of any Node classes during this process.
+        ResourceMark rm;
+        char buf[200];
+        jio_snprintf(buf, sizeof(buf), "Node subclass %s must not be initialized before HotSpotGraalRuntime is initialized", this_oop->name()->as_C_string());
+        THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
+      }
       // Create the NodeClass for a Node subclass.
       TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/Class;)Lcom/oracle/graal/graph/NodeClass;", CHECK);
       JavaValue result(T_OBJECT);
--- a/src/share/vm/prims/nativeLookup.cpp	Tue May 27 21:18:45 2014 -0700
+++ b/src/share/vm/prims/nativeLookup.cpp	Tue May 27 21:20:01 2014 -0700
@@ -126,6 +126,7 @@
 #ifdef GRAAL
   void     JNICALL JVM_InitializeGraalNatives(JNIEnv *env, jclass c, jclass compilerToVMClass);
   jobject  JNICALL JVM_GetGraalRuntime(JNIEnv *env, jclass c);
+  jobject  JNICALL JVM_GetGraalServiceImpls(JNIEnv *env, jclass c);
   jobject  JNICALL JVM_CreateTruffleRuntime(JNIEnv *env, jclass c);
   jboolean JNICALL JVM_ParseGraalOptions(JNIEnv *env, jclass hotspotOptionsClass);
 #endif
@@ -141,6 +142,7 @@
   { CC"Java_sun_hotspot_WhiteBox_registerNatives",                 NULL, FN_PTR(JVM_RegisterWhiteBoxMethods)     },
 #ifdef GRAAL
   { CC"Java_com_oracle_graal_api_runtime_Graal_initializeRuntime",   NULL, FN_PTR(JVM_GetGraalRuntime)             },
+  { CC"Java_com_oracle_graal_api_runtime_Services_getServiceImpls",  NULL, FN_PTR(JVM_GetGraalServiceImpls)        },
   { CC"Java_com_oracle_truffle_api_Truffle_createRuntime",           NULL, FN_PTR(JVM_CreateTruffleRuntime)        },
   { CC"Java_com_oracle_graal_hotspot_HotSpotGraalRuntime_init",      NULL, FN_PTR(JVM_InitializeGraalNatives)      },
   { CC"Java_com_oracle_graal_hotspot_HotSpotOptions_parseVMOptions", NULL, FN_PTR(JVM_ParseGraalOptions)           },
--- a/src/share/vm/runtime/vmStructs.hpp	Tue May 27 21:18:45 2014 -0700
+++ b/src/share/vm/runtime/vmStructs.hpp	Tue May 27 21:20:01 2014 -0700
@@ -127,7 +127,9 @@
 #endif
 
 #ifdef GRAAL
-  static void initHotSpotVMConfig(oop config);
+  // The definition of this method is generated by
+  // com.oracle.graal.hotspotvmconfig.HotSpotVMConfigProcessor.
+static void initHotSpotVMConfig(oop config);
 #endif
 
 private: