changeset 21522:28cbfacd0518

Merge
author Gilles Duboscq <gilles.m.duboscq@oracle.com>
date Thu, 28 May 2015 17:44:05 +0200
parents 107300758a4e (current diff) 47c5e0903d06 (diff)
children 4b3b38415adf
files graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LineNumberTableImpl.java graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalImpl.java graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalVariableTableImpl.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/IntrinsicContext.java graal/com.oracle.graal.hotspot.server/overview.html graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/CompilationServer.java graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/InvocationSocket.java graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/Remote.java graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/ReplacingStreams.java graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/package-info.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerObject.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LineNumberTableImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalVariableTableImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ResolvedMethodHandleCallTargetNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyStateNode.java graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java graal/com.oracle.graal.java/src/com/oracle/graal/java/IntrinsicContext.java graal/com.oracle.graal.java/src/com/oracle/graal/java/ReplacementContext.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMemoryCheckpoint.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/HeapAccess.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMap.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAnchorNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/AbstractMemoryCheckpoint.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/AbstractWriteNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/Access.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FixedAccessNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatableAccessNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatingAccessNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatingReadNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/HeapAccess.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryAccess.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryAnchorNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryCheckpoint.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryMap.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryMapNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryPhiNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/ReadNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/WriteNode.java graal/com.oracle.graal.options.processor/src/com/oracle/graal/options/processor/GraalJars.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MethodHandleNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ResolvedMethodHandleCallTargetNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ExpectError.java graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/ToolEvalInstrumentTest.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentResultListener.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRoot.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRootFactory.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNodeFactory.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalResultListener.java graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/TruffleGlobalScope.java graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/TruffleLanguage.java make/defs.make mx/mx_graal.py mx/suite.py mxtool/mx.py src/share/vm/runtime/arguments.cpp
diffstat 487 files changed, 15990 insertions(+), 10784 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java	Thu May 28 17:44:05 2015 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.api.code;
 
-import java.io.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -32,9 +31,7 @@
  * where to find the local variables, operand stack values and locked objects of the bytecode
  * frame(s).
  */
-public class BytecodeFrame extends BytecodePosition implements Serializable {
-
-    private static final long serialVersionUID = -345025397165977565L;
+public class BytecodeFrame extends BytecodePosition {
 
     /**
      * An array of values representing how to reconstruct the state of the Java frame. This is array
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodePosition.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodePosition.java	Thu May 28 17:44:05 2015 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.api.code;
 
-import java.io.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -33,9 +32,7 @@
  * system to reconstruct a source-level stack trace for exceptions and to create
  * {@linkplain BytecodeFrame frames} for deoptimization.
  */
-public class BytecodePosition implements Serializable {
-
-    private static final long serialVersionUID = 8633885274526033515L;
+public class BytecodePosition {
 
     private final BytecodePosition caller;
     private final ResolvedJavaMethod method;
@@ -109,4 +106,15 @@
     public BytecodePosition getCaller() {
         return caller;
     }
+
+    /**
+     * Adds a caller to the current position returning the new position.
+     */
+    public BytecodePosition addCaller(BytecodePosition link) {
+        if (getCaller() == null) {
+            return new BytecodePosition(link, getMethod(), getBCI());
+        } else {
+            return new BytecodePosition(getCaller().addCaller(link), getMethod(), getBCI());
+        }
+    }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Thu May 28 17:44:05 2015 +0200
@@ -294,6 +294,9 @@
      */
     public static StringBuilder append(StringBuilder sb, BytecodeFrame frame) {
         MetaUtil.appendLocation(sb.append("at "), frame.getMethod(), frame.getBCI());
+        assert sb.charAt(sb.length() - 1) == ']';
+        sb.deleteCharAt(sb.length() - 1);
+        sb.append(", duringCall: ").append(frame.duringCall).append(", rethrow: ").append(frame.rethrowException).append(']');
         if (frame.values != null && frame.values.length > 0) {
             sb.append(NEW_LINE);
             String table = tabulateValues(frame);
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Thu May 28 17:44:05 2015 +0200
@@ -25,27 +25,23 @@
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static java.util.Collections.*;
 
-import java.io.*;
 import java.util.*;
 
+import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
 import com.oracle.graal.api.meta.Assumptions.Assumption;
-import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
 import com.oracle.graal.api.meta.*;
 
 /**
  * Represents the output from compiling a method, including the compiled machine code, associated
  * data and references, relocation information, deoptimization information, etc.
  */
-public class CompilationResult implements Serializable {
-
-    private static final long serialVersionUID = -1319947729753702434L;
+public class CompilationResult {
 
     /**
      * Represents a code position with associated additional information.
      */
-    public abstract static class Site implements Serializable {
+    public abstract static class Site {
 
-        private static final long serialVersionUID = -8214214947651979102L;
         /**
          * The position (or offset) of this site with respect to the start of the target method.
          */
@@ -74,7 +70,6 @@
      */
     public static class Infopoint extends Site implements Comparable<Infopoint> {
 
-        private static final long serialVersionUID = 2479806696381720162L;
         public final DebugInfo debugInfo;
 
         public final InfopointReason reason;
@@ -124,8 +119,6 @@
      */
     public static final class Call extends Infopoint {
 
-        private static final long serialVersionUID = 1440741241631046954L;
-
         /**
          * The target of the call.
          */
@@ -183,9 +176,7 @@
     /**
      * Represents some external data that is referenced by the code.
      */
-    public abstract static class Reference implements Serializable {
-
-        private static final long serialVersionUID = 4841246083028477946L;
+    public abstract static class Reference {
 
         @Override
         public abstract int hashCode();
@@ -196,8 +187,6 @@
 
     public static final class ConstantReference extends Reference {
 
-        private static final long serialVersionUID = 5841121930949053612L;
-
         private final VMConstant constant;
 
         public ConstantReference(VMConstant constant) {
@@ -233,8 +222,6 @@
 
     public static final class DataSectionReference extends Reference {
 
-        private static final long serialVersionUID = 9011681879878139182L;
-
         private boolean initialized;
         private int offset;
 
@@ -281,7 +268,6 @@
      */
     public static final class DataPatch extends Site {
 
-        private static final long serialVersionUID = 5771730331604867476L;
         public Reference reference;
 
         public DataPatch(int pcOffset, Reference reference) {
@@ -314,9 +300,8 @@
      * {@link CompilationResult#getTargetCode()}. This is optional information that can be used to
      * enhance a disassembly of the code.
      */
-    public abstract static class CodeAnnotation implements Serializable {
+    public abstract static class CodeAnnotation {
 
-        private static final long serialVersionUID = -7903959680749520748L;
         public final int position;
 
         public CodeAnnotation(int position) {
@@ -342,10 +327,6 @@
      */
     public static final class CodeComment extends CodeAnnotation {
 
-        /**
-         *
-         */
-        private static final long serialVersionUID = 6802287188701961401L;
         public final String value;
 
         public CodeComment(int position, String comment) {
@@ -384,8 +365,6 @@
      */
     public static final class JumpTable extends CodeAnnotation {
 
-        private static final long serialVersionUID = 2222194398353801831L;
-
         /**
          * The low value in the key range (inclusive).
          */
@@ -434,7 +413,6 @@
      */
     public static final class ExceptionHandler extends Site {
 
-        private static final long serialVersionUID = 4897339464722665281L;
         public final int handlerPos;
 
         ExceptionHandler(int pcOffset, int handlerPos) {
@@ -468,7 +446,6 @@
      */
     public static final class Mark extends Site {
 
-        private static final long serialVersionUID = 3612943150662354844L;
         public final Object id;
 
         public Mark(int pcOffset, Object id) {
@@ -625,11 +602,10 @@
     }
 
     /**
-     * Gets a fixed-size {@linkplain Arrays#asList(Object...) view} of the assumptions made during
-     * compilation.
+     * Gets the assumptions made during compilation.
      */
-    public Collection<Assumption> getAssumptions() {
-        return assumptions == null ? Collections.emptyList() : Arrays.asList(assumptions);
+    public Assumption[] getAssumptions() {
+        return assumptions;
     }
 
     /**
@@ -664,15 +640,14 @@
     }
 
     /**
-     * Gets a fixed-size {@linkplain Arrays#asList(Object...) view} of the methods whose bytecodes
-     * were used as input to the compilation.
+     * Gets the methods whose bytecodes were used as input to the compilation.
      *
      * @return {@code null} if the compilation did not record method dependencies otherwise the
      *         methods whose bytecodes were used as input to the compilation with the first element
      *         being the root method of the compilation
      */
-    public Collection<ResolvedJavaMethod> getMethods() {
-        return methods == null ? null : Arrays.asList(methods);
+    public ResolvedJavaMethod[] getMethods() {
+        return methods;
     }
 
     public DataSection getDataSection() {
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DataSection.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DataSection.java	Thu May 28 17:44:05 2015 +0200
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
 
-import java.io.*;
 import java.nio.*;
 import java.util.*;
 import java.util.function.*;
@@ -34,9 +33,7 @@
 import com.oracle.graal.api.code.DataSection.Data;
 import com.oracle.graal.api.meta.*;
 
-public final class DataSection implements Serializable, Iterable<Data> {
-
-    private static final long serialVersionUID = -1375715553825731716L;
+public final class DataSection implements Iterable<Data> {
 
     @FunctionalInterface
     public interface DataBuilder {
@@ -77,9 +74,7 @@
         }
     }
 
-    public static final class Data implements Serializable {
-
-        private static final long serialVersionUID = -719932751800916080L;
+    public static final class Data {
 
         private int alignment;
         private final int size;
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java	Thu May 28 17:44:05 2015 +0200
@@ -64,6 +64,13 @@
     }
 
     /**
+     * Returns the name of this code blob.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
      * Returns the start address of this installed code if it is {@linkplain #isValid() valid}, 0
      * otherwise.
      */
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java	Thu May 28 17:44:05 2015 +0200
@@ -32,8 +32,6 @@
  */
 public final class RegisterValue extends AllocatableValue {
 
-    private static final long serialVersionUID = 7999341472196897163L;
-
     private final Register reg;
 
     /**
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackLockValue.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackLockValue.java	Thu May 28 17:44:05 2015 +0200
@@ -31,8 +31,6 @@
  */
 public final class StackLockValue extends AbstractValue implements JavaValue {
 
-    private static final long serialVersionUID = 8241681800464483691L;
-
     private Value owner;
     private StackSlotValue slot;
     private final boolean eliminated;
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java	Thu May 28 17:44:05 2015 +0200
@@ -30,8 +30,6 @@
  */
 public final class StackSlot extends StackSlotValue {
 
-    private static final long serialVersionUID = -7725071921307318433L;
-
     private final int offset;
     private final boolean addFrameSize;
 
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlotValue.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlotValue.java	Thu May 28 17:44:05 2015 +0200
@@ -30,8 +30,6 @@
  */
 public abstract class StackSlotValue extends AllocatableValue {
 
-    private static final long serialVersionUID = 5106407801795483337L;
-
     public StackSlotValue(LIRKind lirKind) {
         super(lirKind);
     }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java	Thu May 28 17:44:05 2015 +0200
@@ -33,8 +33,6 @@
  */
 public final class VirtualObject extends AbstractValue implements JavaValue {
 
-    private static final long serialVersionUID = -2907197776426346021L;
-
     private final ResolvedJavaType type;
     private Value[] values;
     private final int id;
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualStackSlot.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualStackSlot.java	Thu May 28 17:44:05 2015 +0200
@@ -30,7 +30,6 @@
  */
 public abstract class VirtualStackSlot extends StackSlotValue {
 
-    private static final long serialVersionUID = 2823688688873398219L;
     private final int id;
 
     public VirtualStackSlot(int id, LIRKind lirKind) {
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Thu May 28 17:44:05 2015 +0200
@@ -312,6 +312,25 @@
         }
     }
 
+    @Test
+    public void isJavaLangObjectInitTest() throws NoSuchMethodException {
+        ResolvedJavaMethod method = metaAccess.lookupJavaMethod(Object.class.getConstructor());
+        assertTrue(method.isJavaLangObjectInit());
+        for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
+            ResolvedJavaMethod m = e.getValue();
+            assertFalse(m.isJavaLangObjectInit());
+        }
+        for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) {
+            ResolvedJavaMethod m = e.getValue();
+            Constructor<?> key = e.getKey();
+            if (key.getDeclaringClass() == Object.class && key.getParameters().length == 0) {
+                assertTrue(m.isJavaLangObjectInit());
+            } else {
+                assertFalse(m.isJavaLangObjectInit());
+            }
+        }
+    }
+
     private Method findTestMethod(Method apiMethod) {
         String testName = apiMethod.getName() + "Test";
         for (Method m : getClass().getDeclaredMethods()) {
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java	Thu May 28 17:44:05 2015 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.api.meta;
 
-import java.io.*;
-
 /**
  * This object holds probability information for a set of items that were profiled at a specific
  * BCI. The precision of the supplied values may vary, but a runtime that provides this information
@@ -34,9 +32,7 @@
  * @param <U> the class of the items that are profiled at the specific BCI and for which
  *            probabilities are stored. E.g., a ResolvedJavaType or a ResolvedJavaMethod.
  */
-public abstract class AbstractJavaProfile<T extends AbstractProfiledItem<U>, U> implements Serializable {
-
-    private static final long serialVersionUID = 5493379044459116749L;
+public abstract class AbstractJavaProfile<T extends AbstractProfiledItem<U>, U> {
 
     private final double notRecordedProbability;
     private final T[] pitems;
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractProfiledItem.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractProfiledItem.java	Thu May 28 17:44:05 2015 +0200
@@ -22,15 +22,11 @@
  */
 package com.oracle.graal.api.meta;
 
-import java.io.*;
-
 /**
  * A profiled type that has a probability. Profiled types are naturally sorted in descending order
  * of their probabilities.
  */
-public abstract class AbstractProfiledItem<T> implements Comparable<AbstractProfiledItem<?>>, Serializable {
-
-    private static final long serialVersionUID = 7838575753661305744L;
+public abstract class AbstractProfiledItem<T> implements Comparable<AbstractProfiledItem<?>> {
 
     protected final T item;
     protected final double probability;
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractValue.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractValue.java	Thu May 28 17:44:05 2015 +0200
@@ -22,14 +22,10 @@
  */
 package com.oracle.graal.api.meta;
 
-import java.io.*;
-
 /**
  * Abstract base class for values.
  */
-public abstract class AbstractValue implements Serializable, Value, KindProvider {
-
-    private static final long serialVersionUID = -6909397188697766469L;
+public abstract class AbstractValue implements Value, KindProvider {
 
     public static final AllocatableValue ILLEGAL = Value.ILLEGAL;
 
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java	Thu May 28 17:44:05 2015 +0200
@@ -28,8 +28,6 @@
  */
 public abstract class AllocatableValue extends AbstractValue implements JavaValue, KindProvider {
 
-    private static final long serialVersionUID = 153019506717492133L;
-
     public static final AllocatableValue[] NONE = {};
 
     public AllocatableValue(LIRKind lirKind) {
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java	Thu May 28 17:44:05 2015 +0200
@@ -22,25 +22,20 @@
  */
 package com.oracle.graal.api.meta;
 
-import java.io.*;
 import java.lang.invoke.*;
 import java.util.*;
 
 /**
  * Class for recording assumptions made during compilation.
  */
-public final class Assumptions implements Serializable, Iterable<Assumptions.Assumption> {
-
-    private static final long serialVersionUID = 5152062717588239131L;
+public final class Assumptions implements Iterable<Assumptions.Assumption> {
 
     /**
      * Abstract base class for assumptions. An assumption assumes a property of the runtime that may
      * be invalidated by subsequent execution (e.g., that a class has no subclasses implementing
      * {@link NoFinalizableSubclass Object.finalize()}).
      */
-    public abstract static class Assumption implements Serializable {
-
-        private static final long serialVersionUID = -1936652569665112915L;
+    public abstract static class Assumption {
     }
 
     /**
@@ -68,6 +63,10 @@
             return result;
         }
 
+        public boolean isAssumptionFree() {
+            return assumptions.length == 0;
+        }
+
         public void add(AssumptionResult<T> other) {
             Assumption[] newAssumptions = Arrays.copyOf(this.assumptions, this.assumptions.length + other.assumptions.length);
             System.arraycopy(other.assumptions, 0, newAssumptions, this.assumptions.length, other.assumptions.length);
@@ -80,8 +79,6 @@
      */
     public static final class NoFinalizableSubclass extends Assumption {
 
-        private static final long serialVersionUID = 6451169735564055081L;
-
         private ResolvedJavaType receiverType;
 
         public NoFinalizableSubclass(ResolvedJavaType receiverType) {
@@ -115,8 +112,6 @@
      */
     public static final class ConcreteSubtype extends Assumption {
 
-        private static final long serialVersionUID = -1457173265437676252L;
-
         /**
          * Type the assumption is made about.
          */
@@ -164,8 +159,6 @@
      */
     public static final class LeafType extends Assumption {
 
-        private static final long serialVersionUID = -1457173265437676252L;
-
         /**
          * Type the assumption is made about.
          */
@@ -203,8 +196,6 @@
      */
     public static final class ConcreteMethod extends Assumption {
 
-        private static final long serialVersionUID = -7636746737947390059L;
-
         /**
          * A virtual (or interface) method whose unique implementation for the receiver type in
          * {@link #context} is {@link #impl}.
@@ -257,8 +248,6 @@
      */
     public static final class CallSiteTargetValue extends Assumption {
 
-        private static final long serialVersionUID = 1732459941784550371L;
-
         public final CallSite callSite;
         public final MethodHandle methodHandle;
 
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java	Thu May 28 17:44:05 2015 +0200
@@ -63,6 +63,14 @@
     JavaConstant readConstantArrayElement(JavaConstant array, int index);
 
     /**
+     * Reads a value from the given array at the given offset if it is a stable array. The offset
+     * will decoded relative to the platform addressing into an index into the array. Returns
+     * {@code null} if the constant is not a stable array, if it is a default value, if the offset
+     * is out of bounds, or if the value is not available at this point.
+     */
+    JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset);
+
+    /**
      * Gets the constant value of this field. Note that a {@code static final} field may not be
      * considered constant if its declaring class is not yet initialized or if it is a well known
      * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}).
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaConstant.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaConstant.java	Thu May 28 17:44:05 2015 +0200
@@ -256,16 +256,18 @@
      */
     static PrimitiveConstant forIntegerKind(Kind kind, long i) {
         switch (kind) {
+            case Boolean:
+                return forBoolean(i != 0);
             case Byte:
-                return new PrimitiveConstant(kind, (byte) i);
+                return forByte((byte) i);
             case Short:
-                return new PrimitiveConstant(kind, (short) i);
+                return forShort((short) i);
             case Char:
-                return new PrimitiveConstant(kind, (char) i);
+                return forChar((char) i);
             case Int:
-                return new PrimitiveConstant(kind, (int) i);
+                return forInt((int) i);
             case Long:
-                return new PrimitiveConstant(kind, i);
+                return forLong(i);
             default:
                 throw new IllegalArgumentException("not an integer kind: " + kind);
         }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaMethodProfile.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaMethodProfile.java	Thu May 28 17:44:05 2015 +0200
@@ -31,8 +31,6 @@
  */
 public final class JavaMethodProfile extends AbstractJavaProfile<ProfiledMethod, ResolvedJavaMethod> {
 
-    private static final long serialVersionUID = -1440572119913692689L;
-
     public JavaMethodProfile(double notRecordedProbability, ProfiledMethod[] pitems) {
         super(notRecordedProbability, pitems);
     }
@@ -43,8 +41,6 @@
 
     public static class ProfiledMethod extends AbstractProfiledItem<ResolvedJavaMethod> {
 
-        private static final long serialVersionUID = 5418813647187024693L;
-
         public ProfiledMethod(ResolvedJavaMethod method, double probability) {
             super(method, probability);
         }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Thu May 28 17:44:05 2015 +0200
@@ -33,7 +33,6 @@
  */
 public final class JavaTypeProfile extends AbstractJavaProfile<ProfiledType, ResolvedJavaType> {
 
-    private static final long serialVersionUID = -6877016333706838441L;
     private static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0];
 
     private final TriState nullSeen;
@@ -145,8 +144,6 @@
 
     public static class ProfiledType extends AbstractProfiledItem<ResolvedJavaType> {
 
-        private static final long serialVersionUID = 1481773321889860837L;
-
         public ProfiledType(ResolvedJavaType type, double probability) {
             super(type, probability);
             assert type.isArray() || type.isConcrete() : type;
@@ -177,4 +174,22 @@
         }
         return buf.append(String.format("], notRecorded:%.6f>", getNotRecordedProbability())).toString();
     }
+
+    /**
+     * Returns {@code true} if all types seen at this location have been recorded in the profile.
+     */
+    public boolean allTypesRecorded() {
+        return this.getNotRecordedProbability() == 0.0;
+    }
+
+    /**
+     * Returns the single monormorphic type representing this profile or {@code null} if no such
+     * type exists.
+     */
+    public ResolvedJavaType asSingleType() {
+        if (allTypesRecorded() && this.getTypes().length == 1) {
+            return getTypes()[0].getType();
+        }
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LIRKind.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LIRKind.java	Thu May 28 17:44:05 2015 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.api.meta;
 
+import java.util.*;
+
 /**
  * Represents the type of values in the LIR. It is composed of a {@link PlatformKind} that gives the
  * low level representation of the value, and a {@link #referenceMask} that describes the location
@@ -133,15 +135,60 @@
      */
     public static LIRKind merge(Value... inputs) {
         assert inputs.length > 0;
-        for (Value input : inputs) {
-            LIRKind kind = input.getLIRKind();
+        ArrayList<LIRKind> kinds = new ArrayList<>(inputs.length);
+        for (int i = 0; i < inputs.length; i++) {
+            kinds.add(inputs[i].getLIRKind());
+        }
+        return merge(kinds);
+    }
+
+    /**
+     * @see #merge(Value...)
+     */
+    public static LIRKind merge(Iterable<LIRKind> kinds) {
+        LIRKind mergeKind = null;
+
+        for (LIRKind kind : kinds) {
+
+            assert mergeKind == null || verifyMoveKinds(mergeKind, kind) : String.format("Input kinds do not match %s vs. %s", mergeKind, kind);
+
             if (kind.isDerivedReference()) {
+                /**
+                 * Kind is a derived reference therefore the result can only be also a derived
+                 * reference.
+                 */
                 return kind;
             }
+            if (mergeKind == null) {
+                mergeKind = kind;
+                continue;
+            }
+
+            if (kind.isValue()) {
+                /* Kind is a value. */
+                if (mergeKind.referenceMask != 0) {
+                    /*
+                     * Inputs consists of values and references. Make the result a derived
+                     * reference.
+                     */
+                    return mergeKind.makeDerivedReference();
+                }
+                /* Check that other inputs are also values. */
+            } else {
+                /* Kind is a reference. */
+                if (mergeKind.referenceMask != kind.referenceMask) {
+                    /*
+                     * Reference maps do not match so the result can only be a derived reference.
+                     */
+                    return mergeKind.makeDerivedReference();
+                }
+            }
+
         }
+        assert mergeKind != null;
 
         // all inputs are values or references, just return one of them
-        return inputs[0].getLIRKind();
+        return mergeKind;
     }
 
     /**
@@ -277,4 +324,26 @@
         LIRKind other = (LIRKind) obj;
         return platformKind == other.platformKind && referenceMask == other.referenceMask;
     }
+
+    public static boolean verifyMoveKinds(LIRKind dst, LIRKind src) {
+        if (src.equals(dst)) {
+            return true;
+        }
+        /*
+         * TODO(je,rs) What we actually want is toStackKind(src.getPlatformKind()).equals(
+         * dst.getPlatformKind()) but due to the handling of sub-integer at the current point
+         * (phi-)moves from e.g. integer to short can happen. Therefore we compare stack kinds.
+         */
+        if (toStackKind(src.getPlatformKind()).equals(toStackKind(dst.getPlatformKind()))) {
+            return !src.isDerivedReference() || dst.isDerivedReference();
+        }
+        return false;
+    }
+
+    private static PlatformKind toStackKind(PlatformKind platformKind) {
+        if (platformKind instanceof Kind) {
+            return ((Kind) platformKind).getStackKind();
+        }
+        return platformKind;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LineNumberTableImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+public class LineNumberTableImpl implements LineNumberTable {
+
+    private final int[] lineNumbers;
+    private final int[] bci;
+
+    public LineNumberTableImpl(int[] lineNumbers, int[] bci) {
+        this.lineNumbers = lineNumbers;
+        this.bci = bci;
+    }
+
+    @Override
+    public int[] getLineNumberEntries() {
+        return lineNumbers;
+    }
+
+    @Override
+    public int[] getBciEntries() {
+        return bci;
+    }
+
+    @Override
+    public int getLineNumber(@SuppressWarnings("hiding") int bci) {
+        for (int i = 0; i < this.bci.length - 1; i++) {
+            if (this.bci[i] <= bci && bci < this.bci[i + 1]) {
+                return lineNumbers[i];
+            }
+        }
+        return lineNumbers[lineNumbers.length - 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+public class LocalImpl implements Local {
+
+    private final String name;
+    private final int startBci;
+    private final int endBci;
+    private final int slot;
+    private final JavaType type;
+
+    public LocalImpl(String name, JavaType type, int startBci, int endBci, int slot) {
+        this.name = name;
+        this.startBci = startBci;
+        this.endBci = endBci;
+        this.slot = slot;
+        this.type = type;
+    }
+
+    @Override
+    public int getStartBCI() {
+        return startBci;
+    }
+
+    @Override
+    public int getEndBCI() {
+        return endBci;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public JavaType getType() {
+        return type;
+    }
+
+    @Override
+    public int getSlot() {
+        return slot;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof LocalImpl)) {
+            return false;
+        }
+        LocalImpl that = (LocalImpl) obj;
+        return this.name.equals(that.name) && this.startBci == that.startBci && this.endBci == that.endBci && this.slot == that.slot && this.type.equals(that.type);
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "LocalImpl<name=" + name + ", type=" + type + ", startBci=" + startBci + ", endBci=" + endBci + ", slot=" + slot + ">";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalVariableTableImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+import java.util.*;
+
+public class LocalVariableTableImpl implements LocalVariableTable {
+
+    private final Local[] locals;
+
+    public LocalVariableTableImpl(Local[] locals) {
+        this.locals = locals;
+    }
+
+    @Override
+    public Local getLocal(int slot, int bci) {
+        Local result = null;
+        for (Local local : locals) {
+            if (local.getSlot() == slot && local.getStartBCI() <= bci && local.getEndBCI() >= bci) {
+                if (result == null) {
+                    result = local;
+                } else {
+                    throw new IllegalStateException("Locals overlap!");
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public Local[] getLocals() {
+        return locals;
+    }
+
+    @Override
+    public Local[] getLocalsAt(int bci) {
+        List<Local> result = new ArrayList<>();
+        for (Local l : locals) {
+            if (l.getStartBCI() <= bci && bci <= l.getEndBCI()) {
+                result.add(l);
+            }
+        }
+        return result.toArray(new Local[result.size()]);
+    }
+
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java	Thu May 28 17:44:05 2015 +0200
@@ -54,26 +54,18 @@
      */
     public static final LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length");
 
-    protected final boolean immutable;
-
     public static LocationIdentity any() {
         return ANY_LOCATION;
     }
 
-    protected LocationIdentity(boolean immutable) {
-        this.immutable = immutable;
-    }
-
     /**
      * Denotes a location is unchanging in all cases. Not that this is different than the Java
      * notion of final which only requires definite assignment.
      */
-    public final boolean isImmutable() {
-        return immutable;
-    }
+    public abstract boolean isImmutable();
 
     public final boolean isMutable() {
-        return !immutable;
+        return !isImmutable();
     }
 
     public final boolean isAny() {
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java	Thu May 28 17:44:05 2015 +0200
@@ -46,11 +46,12 @@
         }
     }
 
-    protected final String name;
+    private final String name;
+    private final boolean immutable;
 
     private NamedLocationIdentity(String name, boolean immutable) {
-        super(immutable);
         this.name = name;
+        this.immutable = immutable;
     }
 
     /**
@@ -87,6 +88,11 @@
     }
 
     @Override
+    public boolean isImmutable() {
+        return immutable;
+    }
+
+    @Override
     public String toString() {
         return name + (isImmutable() ? ":final" : "");
     }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NullConstant.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NullConstant.java	Thu May 28 17:44:05 2015 +0200
@@ -27,8 +27,6 @@
  */
 final class NullConstant extends AbstractValue implements JavaConstant {
 
-    private static final long serialVersionUID = 8906209595800783961L;
-
     protected NullConstant() {
         super(LIRKind.reference(Kind.Object));
     }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PrimitiveConstant.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PrimitiveConstant.java	Thu May 28 17:44:05 2015 +0200
@@ -30,8 +30,6 @@
  */
 public class PrimitiveConstant extends AbstractValue implements JavaConstant, SerializableConstant {
 
-    private static final long serialVersionUID = 8787949721295655376L;
-
     /**
      * The boxed primitive value as a {@code long}. For {@code float} and {@code double} values,
      * this value is the result of {@link Float#floatToRawIntBits(float)} and
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/RawConstant.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/RawConstant.java	Thu May 28 17:44:05 2015 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.api.meta;
 
 public class RawConstant extends PrimitiveConstant {
-    private static final long serialVersionUID = -242269518888560348L;
 
     public RawConstant(long rawValue) {
         super(Kind.Int, rawValue);
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Thu May 28 17:44:05 2015 +0200
@@ -288,4 +288,11 @@
     default boolean hasReceiver() {
         return !isStatic();
     }
+
+    /**
+     * Determines if this method is {@link java.lang.Object#Object()}.
+     */
+    default boolean isJavaLangObjectInit() {
+        return getDeclaringClass().isJavaLangObject() && getName().equals("<init>");
+    }
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Thu May 28 17:44:05 2015 +0200
@@ -28,7 +28,7 @@
  */
 public interface Value extends KindProvider, TrustedInterface {
 
-    @SuppressWarnings("serial") AllocatableValue ILLEGAL = new AllocatableValue(LIRKind.Illegal) {
+    AllocatableValue ILLEGAL = new AllocatableValue(LIRKind.Illegal) {
 
         @Override
         public String toString() {
--- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java	Thu May 28 17:44:05 2015 +0200
@@ -56,15 +56,6 @@
     String signature() default "";
 
     /**
-     * Determines if this method should be substituted in all cases, even if inlining thinks it is
-     * not important.
-     *
-     * Note that this is still depending on whether inlining sees the correct call target, so it's
-     * only a hard guarantee for static and special invocations.
-     */
-    boolean forced() default false;
-
-    /**
      * Determines if the substitution is for a method that may not be part of the runtime. For
      * example, a method introduced in a later JDK version. Substitutions for such methods are
      * omitted if the original method cannot be found.
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Thu May 28 17:44:05 2015 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
 
 /**
  * This class implements commonly used X86 code patterns.
@@ -256,9 +257,14 @@
      * volatile field!
      */
     public final void movlong(AMD64Address dst, long src) {
-        AMD64Address high = new AMD64Address(dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4);
-        movl(dst, (int) (src & 0xFFFFFFFF));
-        movl(high, (int) (src >> 32));
+        if (NumUtil.isInt(src)) {
+            AMD64MIOp.MOV.emit(this, OperandSize.QWORD, dst, (int) src);
+        } else {
+            AMD64Address high = new AMD64Address(dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4);
+            movl(dst, (int) (src & 0xFFFFFFFF));
+            movl(high, (int) (src >> 32));
+        }
+
     }
 
     public final void flog(Register dest, Register value, boolean base10) {
--- a/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Thu May 28 17:44:05 2015 +0200
@@ -63,6 +63,7 @@
             CompilationResult compResult = new CompilationResult();
             byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);
             compResult.setTargetCode(targetCode, targetCode.length);
+            compResult.setTotalFrameSize(0);
 
             InstalledCode code = codeCache.addMethod(method, compResult, null, null);
 
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/NumUtil.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/NumUtil.java	Thu May 28 17:44:05 2015 +0200
@@ -82,6 +82,13 @@
         return (short) x == x;
     }
 
+    /**
+     * Determines if a given {@code long} value is the range of signed short values.
+     */
+    public static boolean isShort(long x) {
+        return (short) x == x;
+    }
+
     public static boolean isUShort(int s) {
         return s == (s & 0xFFFF);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/ConstantStackMoveTest.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.amd64.test;
+
+import static org.junit.Assume.*;
+
+import org.junit.*;
+
+import com.oracle.graal.amd64.*;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.jtt.*;
+
+public class ConstantStackMoveTest extends LIRTest {
+    @Before
+    public void checkAMD64() {
+        assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
+    }
+
+    private static class LoadConstantStackSpec extends LIRTestSpecification {
+        protected final Object primitive;
+
+        public LoadConstantStackSpec(Object primitive) {
+            this.primitive = primitive;
+        }
+
+        @Override
+        public void generate(LIRGeneratorTool gen) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            // create slots
+            PrimitiveConstant constantValue = JavaConstant.forBoxedPrimitive(primitive);
+            StackSlotValue s1 = frameMapBuilder.allocateSpillSlot(constantValue.getLIRKind());
+            // move stuff around
+            gen.emitMove(s1, constantValue);
+            gen.emitBlackhole(s1);
+            setResult(gen.emitMove(s1));
+        }
+    }
+
+    private static final class LoadConstantStackSpecByte extends LoadConstantStackSpec {
+        public LoadConstantStackSpecByte(byte primitive) {
+            super(primitive);
+        }
+
+        byte get() {
+            return (Byte) primitive;
+        }
+    }
+
+    private static final class LoadConstantStackSpecShort extends LoadConstantStackSpec {
+        public LoadConstantStackSpecShort(short primitive) {
+            super(primitive);
+        }
+
+        short get() {
+            return (Short) primitive;
+        }
+    }
+
+    private static final class LoadConstantStackSpecInteger extends LoadConstantStackSpec {
+        public LoadConstantStackSpecInteger(int primitive) {
+            super(primitive);
+        }
+
+        int get() {
+            return (Integer) primitive;
+        }
+    }
+
+    private static final class LoadConstantStackSpecLong extends LoadConstantStackSpec {
+        public LoadConstantStackSpecLong(long primitive) {
+            super(primitive);
+        }
+
+        long get() {
+            return (Long) primitive;
+        }
+    }
+
+    private static final class LoadConstantStackSpecFloat extends LoadConstantStackSpec {
+        public LoadConstantStackSpecFloat(float primitive) {
+            super(primitive);
+        }
+
+        float get() {
+            return (Float) primitive;
+        }
+    }
+
+    private static final class LoadConstantStackSpecDouble extends LoadConstantStackSpec {
+        public LoadConstantStackSpecDouble(double primitive) {
+            super(primitive);
+        }
+
+        double get() {
+            return (Double) primitive;
+        }
+    }
+
+    private static final LoadConstantStackSpecByte stackCopyByte = new LoadConstantStackSpecByte(Byte.MAX_VALUE);
+    private static final LoadConstantStackSpecShort stackCopyShort = new LoadConstantStackSpecShort(Short.MAX_VALUE);
+    private static final LoadConstantStackSpecInteger stackCopyInt = new LoadConstantStackSpecInteger(Integer.MAX_VALUE);
+    private static final LoadConstantStackSpecLong stackCopyLong = new LoadConstantStackSpecLong(Long.MAX_VALUE);
+    private static final LoadConstantStackSpecFloat stackCopyFloat = new LoadConstantStackSpecFloat(Float.MAX_VALUE);
+    private static final LoadConstantStackSpecDouble stackCopyDouble = new LoadConstantStackSpecDouble(Double.MAX_VALUE);
+
+    @LIRIntrinsic
+    public static byte testCopyByte(LoadConstantStackSpecByte spec) {
+        return spec.get();
+    }
+
+    public byte testByte() {
+        return testCopyByte(stackCopyByte);
+    }
+
+    @Test
+    public void runByte() throws Throwable {
+        runTest("testByte");
+    }
+
+    @LIRIntrinsic
+    public static short testCopyShort(LoadConstantStackSpecShort spec) {
+        return spec.get();
+    }
+
+    public short testShort() {
+        return testCopyShort(stackCopyShort);
+    }
+
+    @Test
+    public void runShort() throws Throwable {
+        runTest("testShort");
+    }
+
+    @LIRIntrinsic
+    public static int testCopyInt(LoadConstantStackSpecInteger spec) {
+        return spec.get();
+    }
+
+    public int testInt() {
+        return testCopyInt(stackCopyInt);
+    }
+
+    @Test
+    public void runInt() throws Throwable {
+        runTest("testInt");
+    }
+
+    @LIRIntrinsic
+    public static long testCopyLong(LoadConstantStackSpecLong spec) {
+        return spec.get();
+    }
+
+    public long testLong() {
+        return testCopyLong(stackCopyLong);
+    }
+
+    @Test
+    public void runLong() throws Throwable {
+        runTest("testLong");
+    }
+
+    @LIRIntrinsic
+    public static float testCopyFloat(LoadConstantStackSpecFloat spec) {
+        return spec.get();
+    }
+
+    public float testFloat() {
+        return testCopyFloat(stackCopyFloat);
+    }
+
+    @Test
+    public void runFloat() throws Throwable {
+        runTest("testFloat");
+    }
+
+    @LIRIntrinsic
+    public static double testCopyDouble(LoadConstantStackSpecDouble spec) {
+        return spec.get();
+    }
+
+    public double testDouble() {
+        return testCopyDouble(stackCopyDouble);
+    }
+
+    @Test
+    public void runDouble() throws Throwable {
+        runTest("testDouble");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/StackStoreTest.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.amd64.test;
+
+import static org.junit.Assume.*;
+
+import org.junit.*;
+
+import com.oracle.graal.amd64.*;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.jtt.*;
+
+public class StackStoreTest extends LIRTest {
+    @Before
+    public void checkAMD64() {
+        assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
+    }
+
+    private static final LIRTestSpecification stackCopy0 = new LIRTestSpecification() {
+        @Override
+        public void generate(LIRGeneratorTool gen, Value a) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            // create slots
+            StackSlotValue s1 = frameMapBuilder.allocateSpillSlot(a.getLIRKind());
+            StackSlotValue s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(Kind.Short));
+            // move stuff around
+            gen.emitMove(s1, a);
+            gen.emitMove(s2, JavaConstant.forShort(Short.MIN_VALUE));
+            setResult(gen.emitMove(s1));
+            gen.emitBlackhole(s1);
+            gen.emitBlackhole(s2);
+        }
+    };
+
+    private static final LIRTestSpecification stackCopy1 = new LIRTestSpecification() {
+        @Override
+        public void generate(LIRGeneratorTool gen, Value a) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            // create slots
+            StackSlotValue s1 = frameMapBuilder.allocateSpillSlot(a.getLIRKind());
+            StackSlotValue s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(Kind.Short));
+            // move stuff around
+            gen.emitMove(s1, a);
+            Value v = gen.emitMove(JavaConstant.forShort(Short.MIN_VALUE));
+            gen.emitMove(s2, v);
+            setResult(gen.emitMove(s1));
+            gen.emitBlackhole(s1);
+            gen.emitBlackhole(s2);
+        }
+    };
+
+    private static final LIRTestSpecification stackCopy2 = new LIRTestSpecification() {
+        @Override
+        public void generate(LIRGeneratorTool gen, Value a) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            // create slots
+            StackSlotValue s1 = frameMapBuilder.allocateSpillSlot(a.getLIRKind());
+            StackSlotValue s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(Kind.Short));
+            // move stuff around
+            gen.emitMove(s2, JavaConstant.forShort(Short.MIN_VALUE));
+            gen.emitMove(s1, a);
+            setResult(gen.emitMove(s2));
+            gen.emitBlackhole(s1);
+            gen.emitBlackhole(s2);
+        }
+    };
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static int testShortStackSlot(LIRTestSpecification spec, int a) {
+        return a;
+    }
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static short testShortStackSlot2(LIRTestSpecification spec, int a) {
+        return Short.MIN_VALUE;
+    }
+
+    public int test0(int a) {
+        return testShortStackSlot(stackCopy0, a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test0", 0xDEADDEAD);
+    }
+
+    public int test1(int a) {
+        return testShortStackSlot(stackCopy1, a);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test1", 0xDEADDEAD);
+    }
+
+    public int test2(int a) {
+        return testShortStackSlot2(stackCopy2, a);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test2", 0xDEADDEAD);
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Thu May 28 17:44:05 2015 +0200
@@ -52,6 +52,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.spi.*;
+import com.oracle.graal.compiler.common.util.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.amd64.*;
@@ -64,6 +65,7 @@
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp;
 import com.oracle.graal.lir.amd64.AMD64Move.AMD64StackMove;
+import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MembarOp;
@@ -81,6 +83,7 @@
 
     private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(Kind.Int));
     private AMD64SpillMoveFactory moveFactory;
+    private Map<PlatformKind.Key, RegisterBackupPair> categorized;
 
     private static class RegisterBackupPair {
         public final Register register;
@@ -93,7 +96,6 @@
     }
 
     private class AMD64SpillMoveFactory implements LIRGeneratorTool.SpillMoveFactory {
-        private Map<PlatformKind.Key, RegisterBackupPair> categorized;
 
         @Override
         public LIRInstruction createMove(AllocatableValue result, Value input) {
@@ -102,34 +104,9 @@
 
         @Override
         public LIRInstruction createStackMove(AllocatableValue result, Value input) {
-            RegisterBackupPair backup = getScratchRegister(input.getPlatformKind());
-            return new AMD64StackMove(result, input, backup.register, backup.backupSlot);
+            return AMD64LIRGenerator.this.createStackMove(result, input);
         }
 
-        private RegisterBackupPair getScratchRegister(PlatformKind kind) {
-            PlatformKind.Key key = kind.getKey();
-            if (categorized == null) {
-                categorized = new HashMap<>();
-            } else if (categorized.containsKey(key)) {
-                return categorized.get(key);
-            }
-
-            FrameMapBuilder frameMapBuilder = getResult().getFrameMapBuilder();
-            RegisterConfig registerConfig = frameMapBuilder.getRegisterConfig();
-
-            Register[] availableRegister = registerConfig.filterAllocatableRegisters(kind, registerConfig.getAllocatableRegisters());
-            assert availableRegister != null && availableRegister.length > 1;
-            Register scratchRegister = availableRegister[0];
-
-            Architecture arch = frameMapBuilder.getCodeCache().getTarget().arch;
-            LIRKind largestKind = LIRKind.value(arch.getLargestStorableKind(scratchRegister.getRegisterCategory()));
-            VirtualStackSlot backupSlot = frameMapBuilder.allocateSpillSlot(largestKind);
-
-            RegisterBackupPair value = new RegisterBackupPair(scratchRegister, backupSlot);
-            categorized.put(key, value);
-
-            return value;
-        }
     }
 
     public AMD64LIRGenerator(LIRKindTool lirKindTool, Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) {
@@ -155,6 +132,28 @@
         }
     }
 
+    /**
+     * Checks whether the supplied constant can be used without loading it into a register for store
+     * operations, i.e., on the right hand side of a memory access.
+     *
+     * @param c The constant to check.
+     * @return True if the constant can be used directly, false if the constant needs to be in a
+     *         register.
+     */
+    protected final boolean canStoreConstant(JavaConstant c) {
+        // there is no immediate move of 64-bit constants on Intel
+        switch (c.getKind()) {
+            case Long:
+                return Util.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c);
+            case Double:
+                return false;
+            case Object:
+                return c.isNull();
+            default:
+                return true;
+        }
+    }
+
     protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) {
         if (src instanceof AMD64AddressValue) {
             return new LeaOp(dst, (AMD64AddressValue) src);
@@ -165,6 +164,42 @@
         }
     }
 
+    protected LIRInstruction createStackMove(AllocatableValue result, Value input) {
+        RegisterBackupPair backup = getScratchRegister(input.getPlatformKind());
+        Register scratchRegister = backup.register;
+        StackSlotValue backupSlot = backup.backupSlot;
+        return createStackMove(result, input, scratchRegister, backupSlot);
+    }
+
+    protected LIRInstruction createStackMove(AllocatableValue result, Value input, Register scratchRegister, StackSlotValue backupSlot) {
+        return new AMD64StackMove(result, input, scratchRegister, backupSlot);
+    }
+
+    protected RegisterBackupPair getScratchRegister(PlatformKind kind) {
+        PlatformKind.Key key = kind.getKey();
+        if (categorized == null) {
+            categorized = new HashMap<>();
+        } else if (categorized.containsKey(key)) {
+            return categorized.get(key);
+        }
+
+        FrameMapBuilder frameMapBuilder = getResult().getFrameMapBuilder();
+        RegisterConfig registerConfig = frameMapBuilder.getRegisterConfig();
+
+        Register[] availableRegister = registerConfig.filterAllocatableRegisters(kind, registerConfig.getAllocatableRegisters());
+        assert availableRegister != null && availableRegister.length > 1;
+        Register scratchRegister = availableRegister[0];
+
+        Architecture arch = frameMapBuilder.getCodeCache().getTarget().arch;
+        LIRKind largestKind = LIRKind.value(arch.getLargestStorableKind(scratchRegister.getRegisterCategory()));
+        VirtualStackSlot backupSlot = frameMapBuilder.allocateSpillSlot(largestKind);
+
+        RegisterBackupPair value = new RegisterBackupPair(scratchRegister, backupSlot);
+        categorized.put(key, value);
+
+        return value;
+    }
+
     @Override
     public void emitMove(AllocatableValue dst, Value src) {
         append(createMove(dst, src));
@@ -252,6 +287,183 @@
         return result;
     }
 
+    private static LIRKind toStackKind(LIRKind kind) {
+        if (kind.getPlatformKind() instanceof Kind) {
+            Kind stackKind = ((Kind) kind.getPlatformKind()).getStackKind();
+            return kind.changeType(stackKind);
+        } else {
+            return kind;
+        }
+    }
+
+    @Override
+    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
+        AMD64AddressValue loadAddress = asAddressValue(address);
+        Variable result = newVariable(toStackKind(kind));
+        switch ((Kind) kind.getPlatformKind()) {
+            case Boolean:
+                append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, loadAddress, state));
+                break;
+            case Byte:
+                append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state));
+                break;
+            case Char:
+                append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, loadAddress, state));
+                break;
+            case Short:
+                append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state));
+                break;
+            case Int:
+                append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state));
+                break;
+            case Long:
+            case Object:
+                append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state));
+                break;
+            case Float:
+                append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state));
+                break;
+            case Double:
+                append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+        return result;
+    }
+
+    protected void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) {
+        if (value.isNull()) {
+            assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object;
+            OperandSize size = kind == Kind.Int ? DWORD : QWORD;
+            append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state));
+        } else {
+            AMD64MIOp op = AMD64MIOp.MOV;
+            OperandSize size;
+            long imm;
+
+            switch (kind) {
+                case Boolean:
+                case Byte:
+                    op = AMD64MIOp.MOVB;
+                    size = BYTE;
+                    imm = value.asInt();
+                    break;
+                case Char:
+                case Short:
+                    size = WORD;
+                    imm = value.asInt();
+                    break;
+                case Int:
+                    size = DWORD;
+                    imm = value.asInt();
+                    break;
+                case Long:
+                    size = QWORD;
+                    imm = value.asLong();
+                    break;
+                case Float:
+                    size = DWORD;
+                    imm = Float.floatToRawIntBits(value.asFloat());
+                    break;
+                case Double:
+                    size = QWORD;
+                    imm = Double.doubleToRawLongBits(value.asDouble());
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere("unexpected kind " + kind);
+            }
+
+            if (NumUtil.isInt(imm)) {
+                append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state));
+            } else {
+                emitStore(kind, address, asAllocatable(value), state);
+            }
+        }
+    }
+
+    protected void emitStore(Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state));
+                break;
+            case Char:
+            case Short:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state));
+                break;
+            case Int:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state));
+                break;
+            case Long:
+            case Object:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state));
+                break;
+            case Float:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state));
+                break;
+            case Double:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public void emitStore(LIRKind lirKind, Value address, Value input, LIRFrameState state) {
+        AMD64AddressValue storeAddress = asAddressValue(address);
+        Kind kind = (Kind) lirKind.getPlatformKind();
+        if (isConstant(input)) {
+            emitStoreConst(kind, storeAddress, asConstant(input), state);
+        } else {
+            emitStore(kind, storeAddress, asAllocatable(input), state);
+        }
+    }
+
+    @Override
+    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+        LIRKind kind = newValue.getLIRKind();
+        assert kind.equals(expectedValue.getLIRKind());
+        Kind memKind = (Kind) kind.getPlatformKind();
+
+        AMD64AddressValue addressValue = asAddressValue(address);
+        RegisterValue raxRes = AMD64.rax.asValue(kind);
+        emitMove(raxRes, expectedValue);
+        append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
+
+        assert trueValue.getLIRKind().equals(falseValue.getLIRKind());
+        Variable result = newVariable(trueValue.getLIRKind());
+        append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
+        return result;
+    }
+
+    @Override
+    public Value emitAtomicReadAndAdd(Value address, Value delta) {
+        LIRKind kind = delta.getLIRKind();
+        Kind memKind = (Kind) kind.getPlatformKind();
+        Variable result = newVariable(kind);
+        AMD64AddressValue addressValue = asAddressValue(address);
+        append(new AMD64Move.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta)));
+        return result;
+    }
+
+    @Override
+    public Value emitAtomicReadAndWrite(Value address, Value newValue) {
+        LIRKind kind = newValue.getLIRKind();
+        Kind memKind = (Kind) kind.getPlatformKind();
+        Variable result = newVariable(kind);
+        AMD64AddressValue addressValue = asAddressValue(address);
+        append(new AMD64Move.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue)));
+        return result;
+    }
+
+    @Override
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        assert address.getKind() == Kind.Object || address.getKind() == Kind.Long : address + " - " + address.getKind() + " not a pointer!";
+        append(new AMD64Move.NullCheckOp(asAddressValue(address), state));
+    }
+
     @Override
     public void emitJump(LabelRef label) {
         assert label != null;
@@ -1055,16 +1267,39 @@
             return result;
         } else {
             assert inputVal.getKind().getStackKind() == Kind.Int;
-            Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int));
-            int mask = (int) CodeUtil.mask(fromBits);
-            append(new AMD64Binary.DataOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), JavaConstant.forInt(mask)));
+
+            LIRKind resultKind = LIRKind.derive(inputVal);
             if (toBits > 32) {
-                Variable longResult = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long));
-                emitMove(longResult, result);
-                return longResult;
+                resultKind = resultKind.changeType(Kind.Long);
             } else {
-                return result;
+                resultKind = resultKind.changeType(Kind.Int);
             }
+
+            /*
+             * Always emit DWORD operations, even if the resultKind is Long. On AMD64, all DWORD
+             * operations implicitly set the upper half of the register to 0, which is what we want
+             * anyway. Compared to the QWORD oparations, the encoding of the DWORD operations is
+             * sometimes one byte shorter.
+             */
+            switch (fromBits) {
+                case 8:
+                    return emitConvertOp(resultKind, MOVZXB, DWORD, inputVal);
+                case 16:
+                    return emitConvertOp(resultKind, MOVZX, DWORD, inputVal);
+                case 32:
+                    return emitConvertOp(resultKind, MOV, DWORD, inputVal);
+            }
+
+            // odd bit count, fall back on manual masking
+            Variable result = newVariable(resultKind);
+            JavaConstant mask;
+            if (toBits > 32) {
+                mask = JavaConstant.forLong(CodeUtil.mask(fromBits));
+            } else {
+                mask = JavaConstant.forInt((int) CodeUtil.mask(fromBits));
+            }
+            append(new AMD64Binary.DataOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), mask));
+            return result;
         }
     }
 
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Thu May 28 17:44:05 2015 +0200
@@ -47,6 +47,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 
 public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder {
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Thu May 28 17:44:05 2015 +0200
@@ -45,4 +45,6 @@
     public Fields getData() {
         return data;
     }
+
+    public abstract Fields[] getAllFields();
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Thu May 28 17:44:05 2015 +0200
@@ -48,6 +48,8 @@
      */
     private final Class<?>[] types;
 
+    private final Class<?>[] declaringClasses;
+
     public static Fields forClass(Class<?> clazz, Class<?> endClazz, boolean includeTransient, FieldsScanner.CalcOffset calcOffset) {
         FieldsScanner scanner = new FieldsScanner(calcOffset == null ? new FieldsScanner.DefaultCalcOffset() : calcOffset);
         scanner.scan(clazz, endClazz, includeTransient);
@@ -59,11 +61,13 @@
         this.offsets = new long[fields.size()];
         this.names = new String[offsets.length];
         this.types = new Class[offsets.length];
+        this.declaringClasses = new Class[offsets.length];
         int index = 0;
         for (FieldsScanner.FieldInfo f : fields) {
             offsets[index] = f.offset;
             names[index] = f.name;
             types[index] = f.type;
+            declaringClasses[index] = f.declaringClass;
             index++;
         }
     }
@@ -77,7 +81,7 @@
 
     public static void translateInto(Fields fields, ArrayList<FieldsScanner.FieldInfo> infos) {
         for (int index = 0; index < fields.getCount(); index++) {
-            infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index]));
+            infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index], fields.declaringClasses[index]));
         }
     }
 
@@ -217,6 +221,10 @@
         return other.offsets[index] == offsets[index];
     }
 
+    public long[] getOffsets() {
+        return offsets;
+    }
+
     /**
      * Gets the name of a field.
      *
@@ -235,6 +243,10 @@
         return types[index];
     }
 
+    public Class<?> getDeclaringClass(int index) {
+        return declaringClasses[index];
+    }
+
     /**
      * Checks that a given field is assignable from a given value.
      *
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java	Thu May 28 17:44:05 2015 +0200
@@ -60,11 +60,13 @@
         public final long offset;
         public final String name;
         public final Class<?> type;
+        public final Class<?> declaringClass;
 
-        public FieldInfo(long offset, String name, Class<?> type) {
+        public FieldInfo(long offset, String name, Class<?> type, Class<?> declaringClass) {
             this.offset = offset;
             this.name = name;
             this.type = type;
+            this.declaringClass = declaringClass;
         }
 
         /**
@@ -117,6 +119,6 @@
     }
 
     protected void scanField(Field field, long offset) {
-        data.add(new FieldsScanner.FieldInfo(offset, field.getName(), field.getType()));
+        data.add(new FieldsScanner.FieldInfo(offset, field.getName(), field.getType(), field.getDeclaringClass()));
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Thu May 28 17:44:05 2015 +0200
@@ -286,7 +286,7 @@
     public static final OptionValue<Boolean> OptImplicitNullChecks = new OptionValue<>(true);
 
     @Option(help = "", type = OptionType.Debug)
-    public static final OptionValue<Boolean> OptLivenessAnalysis = new OptionValue<>(true);
+    public static final OptionValue<Boolean> OptClearNonLiveLocals = new OptionValue<>(true);
 
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<Boolean> OptLoopTransform = new OptionValue<>(true);
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/RegisterAllocationConfig.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/RegisterAllocationConfig.java	Thu May 28 17:44:05 2015 +0200
@@ -36,6 +36,36 @@
  */
 public class RegisterAllocationConfig {
 
+    public static final class AllocatableRegisters {
+        public final Register[] allocatableRegisters;
+        public final int minRegisterNumber;
+        public final int maxRegisterNumber;
+
+        public AllocatableRegisters(Register[] allocatableRegisters, int minRegisterNumber, int maxRegisterNumber) {
+            this.allocatableRegisters = allocatableRegisters;
+            this.minRegisterNumber = minRegisterNumber;
+            this.maxRegisterNumber = maxRegisterNumber;
+            assert verify(allocatableRegisters, minRegisterNumber, maxRegisterNumber);
+        }
+
+        private static boolean verify(Register[] allocatableRegisters, int minRegisterNumber, int maxRegisterNumber) {
+            int min = Integer.MAX_VALUE;
+            int max = Integer.MIN_VALUE;
+            for (Register reg : allocatableRegisters) {
+                int number = reg.number;
+                if (number < min) {
+                    min = number;
+                }
+                if (number > max) {
+                    max = number;
+                }
+            }
+            assert minRegisterNumber == min;
+            assert maxRegisterNumber == max;
+            return true;
+        }
+    }
+
     public static final String ALL_REGISTERS = "<all>";
 
     private static Register findRegister(String name, Register[] all) {
@@ -47,7 +77,7 @@
         throw new IllegalArgumentException("register " + name + " is not allocatable");
     }
 
-    private static Register[] initAllocatable(Register[] registers) {
+    protected Register[] initAllocatable(Register[] registers) {
         if (RegisterPressure.getValue() != null && !RegisterPressure.getValue().equals(ALL_REGISTERS)) {
             String[] names = RegisterPressure.getValue().split(",");
             Register[] regs = new Register[names.length];
@@ -60,11 +90,12 @@
         return registers;
     }
 
-    private final RegisterConfig registerConfig;
-    private final Map<PlatformKind.Key, Register[]> categorized = new HashMap<>();
+    protected final RegisterConfig registerConfig;
+    private final Map<PlatformKind.Key, AllocatableRegisters> categorized = new HashMap<>();
     private Register[] cachedRegisters;
 
     public RegisterAllocationConfig(RegisterConfig registerConfig) {
+        assert registerConfig != null;
         this.registerConfig = registerConfig;
     }
 
@@ -72,17 +103,19 @@
      * Gets the set of registers that can be used by the register allocator for a value of a
      * particular kind.
      */
-    public Register[] getAllocatableRegisters(PlatformKind kind) {
+    public AllocatableRegisters getAllocatableRegisters(PlatformKind kind) {
         PlatformKind.Key key = kind.getKey();
         if (categorized.containsKey(key)) {
-            Register[] val = categorized.get(key);
+            AllocatableRegisters val = categorized.get(key);
             return val;
         }
-
-        Register[] ret = registerConfig.filterAllocatableRegisters(kind, getAllocatableRegisters());
+        AllocatableRegisters ret = createAllocatableRegisters(registerConfig.filterAllocatableRegisters(kind, getAllocatableRegisters()));
         categorized.put(key, ret);
         return ret;
+    }
 
+    protected AllocatableRegisters createAllocatableRegisters(Register[] registers) {
+        return new AllocatableRegisters(registers, registers[0].number, registers[registers.length - 1].number);
     }
 
     /**
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java	Thu May 28 17:44:05 2015 +0200
@@ -43,6 +43,11 @@
     protected abstract AbstractObjectStamp copyWith(ResolvedJavaType newType, boolean newExactType, boolean newNonNull, boolean newAlwaysNull);
 
     @Override
+    protected final AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) {
+        return copyWith(type, exactType, newNonNull, newAlwaysNull);
+    }
+
+    @Override
     public Stamp unrestricted() {
         return copyWith(null, false, false, false);
     }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractPointerStamp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractPointerStamp.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,8 @@
         return alwaysNull;
     }
 
+    protected abstract AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull);
+
     @Override
     public int hashCode() {
         final int prime = 31;
@@ -55,6 +57,36 @@
     }
 
     @Override
+    public Stamp join(Stamp stamp) {
+        AbstractPointerStamp other = (AbstractPointerStamp) stamp;
+        boolean joinNonNull = this.nonNull || other.nonNull;
+        boolean joinAlwaysNull = this.alwaysNull || other.alwaysNull;
+        if (joinNonNull && joinAlwaysNull) {
+            return empty();
+        } else {
+            return copyWith(joinNonNull, joinAlwaysNull);
+        }
+    }
+
+    @Override
+    public Stamp improveWith(Stamp other) {
+        return join(other);
+    }
+
+    @Override
+    public Stamp meet(Stamp stamp) {
+        AbstractPointerStamp other = (AbstractPointerStamp) stamp;
+        boolean meetNonNull = this.nonNull && other.nonNull;
+        boolean meetAlwaysNull = this.alwaysNull && other.alwaysNull;
+        return copyWith(meetNonNull, meetAlwaysNull);
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return copyWith(false, false);
+    }
+
+    @Override
     public boolean equals(Object obj) {
         if (this == obj) {
             return true;
--- a/graal/com.oracle.graal.compiler.sparc.test/src/com/oracle/graal/compiler/sparc/test/SPARCAllocatorTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.sparc.test/src/com/oracle/graal/compiler/sparc/test/SPARCAllocatorTest.java	Thu May 28 17:44:05 2015 +0200
@@ -58,7 +58,7 @@
 
     @Test
     public void test3() {
-        testAllocation("test3snippet", 3, 1, 0);
+        testAllocation("test3snippet", 3, 0, 0);
     }
 
     public static long test3snippet(long x) {
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Thu May 28 17:44:05 2015 +0200
@@ -52,15 +52,7 @@
 import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp;
 import com.oracle.graal.lir.sparc.SPARCControlFlow.StrategySwitchOp;
 import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp;
-import com.oracle.graal.lir.sparc.SPARCMove.LoadAddressOp;
-import com.oracle.graal.lir.sparc.SPARCMove.LoadDataAddressOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MembarOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MoveFpGp;
-import com.oracle.graal.lir.sparc.SPARCMove.MoveFpGpVIS3;
-import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp;
-import com.oracle.graal.lir.sparc.SPARCMove.SPARCStackMove;
-import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp;
+import com.oracle.graal.lir.sparc.SPARCMove.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.sparc.*;
 import com.oracle.graal.sparc.SPARC.CPUFeature;
@@ -82,7 +74,7 @@
 
         @Override
         public LIRInstruction createStackMove(AllocatableValue result, Value input) {
-            return new SPARCStackMove(result, input);
+            return SPARCLIRGenerator.this.createStackMove(result, input);
         }
     }
 
@@ -125,6 +117,10 @@
         }
     }
 
+    protected LIRInstruction createStackMove(AllocatableValue result, Value input) {
+        return new SPARCStackMove(result, input);
+    }
+
     @Override
     public void emitMove(AllocatableValue dst, Value src) {
         append(createMove(dst, src));
@@ -158,15 +154,15 @@
                 finalDisp += asConstant(index).asLong() * scale;
                 indexRegister = Value.ILLEGAL;
             } else {
+                Value longIndex = index.getKind() == Kind.Long ? index : emitSignExtend(index, 32, 64);
                 if (scale != 1) {
-                    Value longIndex = index.getKind() == Kind.Long ? index : emitSignExtend(index, 32, 64);
                     if (CodeUtil.isPowerOf2(scale)) {
                         indexRegister = emitShl(longIndex, JavaConstant.forLong(CodeUtil.log2(scale)));
                     } else {
                         indexRegister = emitMul(longIndex, JavaConstant.forLong(scale), false);
                     }
                 } else {
-                    indexRegister = asAllocatable(index);
+                    indexRegister = asAllocatable(longIndex);
                 }
             }
         } else {
@@ -856,9 +852,10 @@
             case F2D:
                 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), F2D, input);
             case I2F: {
-                AllocatableValue convertedFloatReg = newVariable(LIRKind.derive(input).changeType(Kind.Float));
-                moveBetweenFpGp(convertedFloatReg, input);
-                append(new Unary2Op(I2F, convertedFloatReg, convertedFloatReg));
+                AllocatableValue intEncodedFloatReg = newVariable(LIRKind.derive(input).changeType(Kind.Float));
+                moveBetweenFpGp(intEncodedFloatReg, input);
+                AllocatableValue convertedFloatReg = newVariable(intEncodedFloatReg.getLIRKind());
+                append(new Unary2Op(I2F, convertedFloatReg, intEncodedFloatReg));
                 return convertedFloatReg;
             }
             case I2D: {
@@ -871,9 +868,10 @@
                 return convertedDoubleReg;
             }
             case L2D: {
-                AllocatableValue convertedDoubleReg = newVariable(LIRKind.derive(input).changeType(Kind.Double));
-                moveBetweenFpGp(convertedDoubleReg, input);
-                append(new Unary2Op(L2D, convertedDoubleReg, convertedDoubleReg));
+                AllocatableValue longEncodedDoubleReg = newVariable(LIRKind.derive(input).changeType(Kind.Double));
+                moveBetweenFpGp(longEncodedDoubleReg, input);
+                AllocatableValue convertedDoubleReg = newVariable(longEncodedDoubleReg.getLIRKind());
+                append(new Unary2Op(L2D, convertedDoubleReg, longEncodedDoubleReg));
                 return convertedDoubleReg;
             }
             case D2I: {
@@ -1070,4 +1068,16 @@
         append(new ReturnOp(Value.ILLEGAL));
     }
 
+    public Value emitSignExtendLoad(LIRKind kind, Value address, LIRFrameState state) {
+        SPARCAddressValue loadAddress = asAddressValue(address);
+        Variable result = newVariable(kind);
+        append(new LoadOp((Kind) kind.getPlatformKind(), result, loadAddress, state, true));
+        return result;
+    }
+
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        PlatformKind kind = address.getPlatformKind();
+        assert kind == Kind.Object || kind == Kind.Long : address + " - " + kind + " not an object!";
+        append(new NullCheckOp(asAddressValue(address), state));
+    }
 }
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,12 +29,12 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 
 /**
  * This class implements the SPARC specific portion of the LIR generator.
@@ -106,7 +106,7 @@
         Kind localToKind = toKind;
         return builder -> {
             Value address = access.accessLocation().generateAddress(builder, gen, operand(access.object()));
-            Value v = getLIRGeneratorTool().emitLoad(LIRKind.value(localFromKind), address, getState(access));
+            Value v = getLIRGeneratorTool().emitSignExtendLoad(LIRKind.value(localFromKind), address, getState(access));
             return getLIRGeneratorTool().emitReinterpret(LIRKind.value(localToKind), v);
         };
     }
@@ -116,4 +116,9 @@
     public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
         return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
     }
+
+    @Override
+    public SPARCLIRGenerator getLIRGeneratorTool() {
+        return (SPARCLIRGenerator) super.getLIRGeneratorTool();
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingTest.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import org.junit.*;
+
+public class BoxingTest extends GraalCompilerTest {
+
+    public static Object boxSnippet(int arg) {
+        return arg;
+    }
+
+    @Test
+    public void test0() {
+        test("boxSnippet", 0);
+    }
+
+    @Test
+    public void test5() {
+        test("boxSnippet", 5);
+    }
+
+    @Test
+    public void testMinus5() {
+        test("boxSnippet", -5);
+    }
+
+    @Test
+    public void test300() {
+        test("boxSnippet", 300);
+    }
+
+    @Test
+    public void testMinus300() {
+        test("boxSnippet", -300);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CopyOfVirtualizationTest.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.test;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+
+public class CopyOfVirtualizationTest extends GraalCompilerTest {
+
+    @Override
+    protected boolean checkMidTierGraph(StructuredGraph graph) {
+        assertTrue(graph.getNodes().filter(node -> node instanceof NewArrayNode).count() == 0, "shouldn't require allocation in %s", graph);
+        return super.checkMidTierGraph(graph);
+    }
+
+    public byte byteCopyOfVirtualization(int index) {
+        byte[] array = new byte[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public short shortCopyOfVirtualization(int index) {
+        short[] array = new short[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public char charCopyOfVirtualization(int index) {
+        char[] array = new char[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public int intCopyOfVirtualization(int index) {
+        int[] array = new int[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public long longCopyOfVirtualization(int index) {
+        long[] array = new long[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public float floatCopyOfVirtualization(int index) {
+        float[] array = new float[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public double doubleCopyOfVirtualization(int index) {
+        double[] array = new double[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public Object objectCopyOfVirtualization(int index) {
+        Object[] array = new Object[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    // @Test
+    public void testCopyOfVirtualization() {
+        test("byteCopyOfVirtualization", 3);
+        test("shortCopyOfVirtualization", 3);
+        test("charCopyOfVirtualization", 3);
+        test("intCopyOfVirtualization", 3);
+        test("longCopyOfVirtualization", 3);
+        test("floatCopyOfVirtualization", 3);
+        test("doubleCopyOfVirtualization", 3);
+        test("objectCopyOfVirtualization", 3);
+    }
+
+    static final byte[] byteArray = new byte[]{1, 2, 3, 4};
+
+    public byte byteCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(byteArray, byteArray.length)[3];
+    }
+
+    static final short[] shortArray = new short[]{1, 2, 3, 4};
+
+    public short shortCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(shortArray, shortArray.length)[3];
+    }
+
+    static final char[] charArray = new char[]{1, 2, 3, 4};
+
+    public char charCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(charArray, charArray.length)[3];
+    }
+
+    static final int[] intArray = new int[]{1, 2, 3, 4};
+
+    public int intCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(intArray, intArray.length)[3];
+    }
+
+    static final long[] longArray = new long[]{1, 2, 3, 4};
+
+    public long longCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(longArray, longArray.length)[3];
+    }
+
+    static final float[] floatArray = new float[]{1, 2, 3, 4};
+
+    public float floatCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(floatArray, floatArray.length)[3];
+    }
+
+    static final double[] doubleArray = new double[]{1, 2, 3, 4};
+
+    public double doubleCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(doubleArray, doubleArray.length)[3];
+    }
+
+    static final Object[] objectArray = new Object[]{1, 2, 3, 4};
+
+    public Object objectCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(objectArray, objectArray.length)[3];
+    }
+
+    @Test
+    public void testCopyOfVirtualizableAllocation() {
+        test("byteCopyOfVirtualizableAllocation");
+        test("shortCopyOfVirtualizableAllocation");
+        test("charCopyOfVirtualizableAllocation");
+        test("intCopyOfVirtualizableAllocation");
+        test("longCopyOfVirtualizableAllocation");
+        test("floatCopyOfVirtualizableAllocation");
+        test("doubleCopyOfVirtualizableAllocation");
+        test("objectCopyOfVirtualizableAllocation");
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Thu May 28 17:44:05 2015 +0200
@@ -321,7 +321,7 @@
             result.append("\n");
             for (Node node : schedule.getBlockToNodesMap().get(block)) {
                 if (node instanceof ValueNode && node.isAlive()) {
-                    if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode)) {
+                    if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof InfopointNode)) {
                         if (node instanceof ConstantNode) {
                             String name = checkConstants ? node.toString(Verbosity.Name) : node.getClass().getSimpleName();
                             String str = name + (excludeVirtual ? "\n" : "    (" + node.getUsageCount() + ")\n");
@@ -436,8 +436,8 @@
 
     protected static class Result {
 
-        final Object returnValue;
-        final Throwable exception;
+        public final Object returnValue;
+        public final Throwable exception;
 
         public Result(Object returnValue, Throwable exception) {
             this.returnValue = returnValue;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.options.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/OnStackReplacementTest.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import org.junit.*;
+
+public class OnStackReplacementTest extends GraalCompilerTest {
+
+    @Test
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    static int limit = 10000;
+
+    public static void test1Snippet() {
+        for (int i = 0; !Thread.currentThread().isInterrupted() && i < limit; i++) {
+            for (int j = 0; !Thread.currentThread().isInterrupted() && j < limit; j++) {
+            }
+        }
+
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.common.*;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Thu May 28 17:44:05 2015 +0200
@@ -51,6 +51,7 @@
     public static class TestClassInt {
         public int x;
         public int y;
+        public int z;
 
         public TestClassInt() {
             this(0, 0);
@@ -68,7 +69,7 @@
         @Override
         public boolean equals(Object obj) {
             TestClassInt other = (TestClassInt) obj;
-            return x == other.x && y == other.y;
+            return x == other.x && y == other.y && z == other.z;
         }
 
         @Override
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Thu May 28 17:44:05 2015 +0200
@@ -23,12 +23,14 @@
 package com.oracle.graal.compiler.test.ea;
 
 import java.lang.ref.*;
+
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.common.*;
@@ -191,6 +193,23 @@
         assertTrue(graph.getNodes().filter(ReturnNode.class).first().result() == graph.getParameter(0));
     }
 
+    public static int testBoxLoopSnippet(int n) {
+        Integer sum = 0;
+        for (Integer i = 0; i < n; i++) {
+            if (sum == null) {
+                sum = null;
+            } else {
+                sum += i;
+            }
+        }
+        return sum;
+    }
+
+    @Test
+    public void testBoxLoop() {
+        testPartialEscapeAnalysis("testBoxLoopSnippet", 0, 0, BoxNode.class, UnboxNode.class);
+    }
+
     @SafeVarargs
     protected final void testPartialEscapeAnalysis(String snippet, double expectedProbability, int expectedCount, Class<? extends Node>... invalidNodeClasses) {
         prepareGraph(snippet, false);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java	Thu May 28 17:44:05 2015 +0200
@@ -36,15 +36,23 @@
     public static int zero = 0;
 
     private static final Unsafe unsafe;
-    private static final long fieldOffsetX;
-    private static final long fieldOffsetY;
+    private static final long fieldOffset1;
+    private static final long fieldOffset2;
 
     static {
         unsafe = UnsafeAccess.unsafe;
         try {
-            fieldOffsetX = unsafe.objectFieldOffset(TestClassInt.class.getField("x"));
-            fieldOffsetY = unsafe.objectFieldOffset(TestClassInt.class.getField("y"));
-            assert fieldOffsetY == fieldOffsetX + 4;
+            long localFieldOffset1 = unsafe.objectFieldOffset(TestClassInt.class.getField("x"));
+            // Make the fields 8 byte aligned (Required for testing setLong on Architectures which
+            // does not support unaligned memory access
+            if (localFieldOffset1 % 8 == 0) {
+                fieldOffset1 = localFieldOffset1;
+                fieldOffset2 = unsafe.objectFieldOffset(TestClassInt.class.getField("y"));
+            } else {
+                fieldOffset1 = unsafe.objectFieldOffset(TestClassInt.class.getField("y"));
+                fieldOffset2 = unsafe.objectFieldOffset(TestClassInt.class.getField("z"));
+            }
+            assert fieldOffset2 == fieldOffset1 + 4;
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -57,8 +65,8 @@
 
     public static int testSimpleIntSnippet() {
         TestClassInt x = new TestClassInt();
-        unsafe.putInt(x, fieldOffsetX, 101);
-        return unsafe.getInt(x, fieldOffsetX);
+        unsafe.putInt(x, fieldOffset1, 101);
+        return unsafe.getInt(x, fieldOffset1);
     }
 
     @Test
@@ -68,7 +76,7 @@
 
     public static TestClassInt testMaterializedIntSnippet() {
         TestClassInt x = new TestClassInt();
-        unsafe.putInt(x, fieldOffsetX, 101);
+        unsafe.putInt(x, fieldOffset1, 101);
         return x;
     }
 
@@ -79,8 +87,8 @@
 
     public static double testSimpleDoubleSnippet() {
         TestClassInt x = new TestClassInt();
-        unsafe.putDouble(x, fieldOffsetX, 10.1);
-        return unsafe.getDouble(x, fieldOffsetX);
+        unsafe.putDouble(x, fieldOffset1, 10.1);
+        return unsafe.getDouble(x, fieldOffset1);
     }
 
     @Test
@@ -97,12 +105,12 @@
         TestClassInt x;
         if (a) {
             x = new TestClassInt(0, 0);
-            unsafe.putDouble(x, fieldOffsetX, doubleField);
+            unsafe.putDouble(x, fieldOffset1, doubleField);
         } else {
             x = new TestClassInt();
-            unsafe.putDouble(x, fieldOffsetX, doubleField2);
+            unsafe.putDouble(x, fieldOffset1, doubleField2);
         }
-        return unsafe.getDouble(x, fieldOffsetX);
+        return unsafe.getDouble(x, fieldOffset1);
     }
 
     @Test
@@ -112,7 +120,7 @@
 
     public static TestClassInt testMaterializedDoubleSnippet() {
         TestClassInt x = new TestClassInt();
-        unsafe.putDouble(x, fieldOffsetX, 10.1);
+        unsafe.putDouble(x, fieldOffset1, 10.1);
         return x;
     }
 
@@ -126,10 +134,10 @@
 
     public static TestClassInt testDeoptDoubleVarSnippet() {
         TestClassInt x = new TestClassInt();
-        unsafe.putDouble(x, fieldOffsetX, doubleField);
+        unsafe.putDouble(x, fieldOffset1, doubleField);
         doubleField2 = 123;
         try {
-            doubleField = ((int) unsafe.getDouble(x, fieldOffsetX)) / zero;
+            doubleField = ((int) unsafe.getDouble(x, fieldOffset1)) / zero;
         } catch (RuntimeException e) {
             return x;
         }
@@ -143,10 +151,10 @@
 
     public static TestClassInt testDeoptDoubleConstantSnippet() {
         TestClassInt x = new TestClassInt();
-        unsafe.putDouble(x, fieldOffsetX, 10.123);
+        unsafe.putDouble(x, fieldOffset1, 10.123);
         doubleField2 = 123;
         try {
-            doubleField = ((int) unsafe.getDouble(x, fieldOffsetX)) / zero;
+            doubleField = ((int) unsafe.getDouble(x, fieldOffset1)) / zero;
         } catch (RuntimeException e) {
             return x;
         }
@@ -163,10 +171,10 @@
 
     public static TestClassInt testDeoptLongVarSnippet() {
         TestClassInt x = new TestClassInt();
-        unsafe.putLong(x, fieldOffsetX, longField);
+        unsafe.putLong(x, fieldOffset1, longField);
         longField2 = 123;
         try {
-            longField = unsafe.getLong(x, fieldOffsetX) / zero;
+            longField = unsafe.getLong(x, fieldOffset1) / zero;
         } catch (RuntimeException e) {
             return x;
         }
@@ -180,10 +188,10 @@
 
     public static TestClassInt testDeoptLongConstantSnippet() {
         TestClassInt x = new TestClassInt();
-        unsafe.putLong(x, fieldOffsetX, 0x2222222210123L);
+        unsafe.putLong(x, fieldOffset1, 0x2222222210123L);
         longField2 = 123;
         try {
-            longField = unsafe.getLong(x, fieldOffsetX) / zero;
+            longField = unsafe.getLong(x, fieldOffset1) / zero;
         } catch (RuntimeException e) {
             return x;
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Thu May 28 17:44:05 2015 +0200
@@ -223,7 +223,7 @@
 
     public static <T extends CompilationResult> void emitBackEnd(StructuredGraph graph, Object stub, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Backend backend,
                     TargetDescription target, T compilationResult, CompilationResultBuilderFactory factory, SchedulePhase schedule, RegisterConfig registerConfig, LIRSuites lirSuites) {
-        try (Scope s = Debug.scope("BackEnd"); DebugCloseable a = BackEnd.start()) {
+        try (Scope s = Debug.scope("BackEnd", schedule); DebugCloseable a = BackEnd.start()) {
             // Repeatedly run the LIR code generation pass to improve statistical profiling results.
             for (int i = 0; i < EmitLIRRepeatCount.getValue(); i++) {
                 SchedulePhase dummySchedule = new SchedulePhase();
@@ -300,7 +300,7 @@
             }
 
             try (Scope s = Debug.scope("LIRStages", nodeLirGen, lir)) {
-                return emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, lirGen, lirSuites);
+                return emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig));
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
@@ -310,11 +310,11 @@
     }
 
     public static <T extends AbstractBlockBase<T>> LIRGenerationResult emitLowLevel(TargetDescription target, List<T> codeEmittingOrder, List<T> linearScanOrder, LIRGenerationResult lirGenRes,
-                    LIRGeneratorTool lirGen, LIRSuites lirSuites) {
+                    LIRGeneratorTool lirGen, LIRSuites lirSuites, RegisterAllocationConfig registerAllocationConfig) {
         PreAllocationOptimizationContext preAllocOptContext = new PreAllocationOptimizationContext(lirGen);
         lirSuites.getPreAllocationOptimizationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, preAllocOptContext);
 
-        AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory());
+        AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory(), registerAllocationConfig);
         lirSuites.getAllocationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, allocContext);
 
         PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext(lirGen);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu May 28 17:44:05 2015 +0200
@@ -113,7 +113,6 @@
         }
         objectStates.clear();
 
-        assert frame.validateFormat(false);
         return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray);
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Thu May 28 17:44:05 2015 +0200
@@ -51,6 +51,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
 
@@ -194,17 +195,21 @@
     }
 
     protected LIRKind getExactPhiKind(PhiNode phi) {
-        ArrayList<Value> values = new ArrayList<>(phi.valueCount());
+        // TODO (je): maybe turn this into generator-style instead of allocating an ArrayList.
+        ArrayList<LIRKind> values = new ArrayList<>(phi.valueCount());
         for (int i = 0; i < phi.valueCount(); i++) {
             ValueNode node = phi.valueAt(i);
             Value value = node instanceof ConstantNode ? ((ConstantNode) node).asJavaConstant() : getOperand(node);
             if (value != null) {
-                values.add(value);
+                values.add(value.getLIRKind());
             } else {
-                assert isPhiInputFromBackedge(phi, i);
+                assert node instanceof ConstantNode || isPhiInputFromBackedge(phi, i) : String.format("Input %s to phi node %s is not yet available although it is not coming from a loop back edge",
+                                node, phi);
+                // non-java constant -> get Kind from stamp.
+                values.add(getLIRGeneratorTool().getLIRKind(node.stamp()));
             }
         }
-        LIRKind derivedKind = LIRKind.merge(values.toArray(new Value[values.size()]));
+        LIRKind derivedKind = LIRKind.merge(values);
         assert verifyPHIKind(derivedKind, gen.getLIRKind(phi.stamp()));
         return derivedKind;
     }
@@ -212,7 +217,7 @@
     private static boolean verifyPHIKind(LIRKind derivedKind, LIRKind phiKind) {
         assert derivedKind.getPlatformKind() != Kind.Object || !derivedKind.isDerivedReference();
         PlatformKind phiPlatformKind = phiKind.getPlatformKind();
-        assert derivedKind.getPlatformKind().equals(phiPlatformKind instanceof Kind ? ((Kind) phiPlatformKind).getStackKind() : phiPlatformKind);
+        assert derivedKind.equals(phiKind) || derivedKind.getPlatformKind().equals(phiPlatformKind instanceof Kind ? ((Kind) phiPlatformKind).getStackKind() : phiPlatformKind);
         return true;
     }
 
@@ -238,6 +243,13 @@
         for (PhiNode phi : merge.valuePhis()) {
             Value value = operand(phi.valueAt(pred));
             assert value != null;
+            if (isRegister(value)) {
+                /*
+                 * Fixed register intervals are not allowed at block boundaries so we introduce a
+                 * new Variable.
+                 */
+                value = gen.emitMove(value);
+            }
             values.add(value);
         }
         return values.toArray(new Value[values.size()]);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java	Thu May 28 17:44:05 2015 +0200
@@ -31,13 +31,12 @@
  * usually occur here.
  */
 public class ComplexMatchValue extends AbstractValue {
-    private static final long serialVersionUID = -4734670273590368770L;
 
     /**
      * This is the Value of a node which was matched as part of a complex match. The value isn't
      * actually useable but this marks it as having been evaluated.
      */
-    @SuppressWarnings("serial") public static final Value INTERIOR_MATCH = new AbstractValue(LIRKind.Illegal) {
+    public static final Value INTERIOR_MATCH = new AbstractValue(LIRKind.Illegal) {
 
         @Override
         public String toString() {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/GraphChangeMonitoringPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/GraphChangeMonitoringPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -66,7 +66,7 @@
          * having their inputs change are the main interesting differences.
          */
         HashSetNodeEventListener listener = new HashSetNodeEventListener().exclude(NodeEvent.NODE_ADDED);
-        StructuredGraph graphCopy = graph.copy();
+        StructuredGraph graphCopy = (StructuredGraph) graph.copy();
         try (NodeEventScope s = graphCopy.trackNodeEvents(listener)) {
             try (Scope s2 = Debug.sandbox("WithoutMonitoring", null)) {
                 super.run(graphCopy, context);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Thu May 28 17:44:05 2015 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
@@ -82,6 +83,8 @@
      */
     public abstract FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig);
 
+    public abstract RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig);
+
     public abstract FrameMap newFrameMap(RegisterConfig registerConfig);
 
     public abstract LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Thu May 28 17:44:05 2015 +0200
@@ -269,9 +269,10 @@
     /**
      * This method exists mainly to allow a debugger (e.g., Eclipse) to force dump a graph.
      */
-    public static void forceDump(Object object, String message) {
+    public static void forceDump(Object object, String format, Object... args) {
         DebugConfig config = getConfig();
         if (config != null) {
+            String message = String.format(format, args);
             for (DebugDumpHandler dumpHandler : config.dumpHandlers()) {
                 dumpHandler.dump(object, message);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/CachedGraph.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.graph;
+
+import java.util.*;
+import java.util.function.*;
+
+/**
+ * This class is a container of a graph that needs to be readonly and optionally a lazily created
+ * mutable copy of the graph.
+ */
+public final class CachedGraph<G extends Graph> {
+
+    private final G readonlyCopy;
+    private G mutableCopy;
+
+    private CachedGraph(G readonlyCopy, G mutableCopy) {
+        this.readonlyCopy = readonlyCopy;
+        this.mutableCopy = mutableCopy;
+    }
+
+    public static <G extends Graph> CachedGraph<G> fromReadonlyCopy(G graph) {
+        return new CachedGraph<>(graph, null);
+    }
+
+    public static <G extends Graph> CachedGraph<G> fromMutableCopy(G graph) {
+        return new CachedGraph<>(graph, graph);
+    }
+
+    public G getReadonlyCopy() {
+        if (hasMutableCopy()) {
+            return mutableCopy;
+        }
+        return readonlyCopy;
+    }
+
+    public boolean hasMutableCopy() {
+        return mutableCopy != null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public G getMutableCopy(Consumer<Map<Node, Node>> duplicationMapCallback) {
+        if (!hasMutableCopy()) {
+            mutableCopy = (G) readonlyCopy.copy(duplicationMapCallback);
+        }
+        return mutableCopy;
+    }
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Thu May 28 17:44:05 2015 +0200
@@ -57,7 +57,7 @@
 
     public static void translateInto(Edges edges, ArrayList<EdgeInfo> infos) {
         for (int index = 0; index < edges.getCount(); index++) {
-            infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index)));
+            infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index), edges.getDeclaringClass(index)));
         }
     }
 
@@ -547,10 +547,6 @@
         }
     }
 
-    public long[] getOffsets() {
-        return this.offsets;
-    }
-
     public void pushAll(Node node, NodeStack stack) {
         int index = 0;
         int curDirectCount = this.directCount;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Thu May 28 17:44:05 2015 +0200
@@ -25,6 +25,7 @@
 import static com.oracle.graal.graph.Edges.Type.*;
 
 import java.util.*;
+import java.util.function.*;
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
@@ -219,8 +220,17 @@
     /**
      * Creates a copy of this graph.
      */
-    public Graph copy() {
-        return copy(name);
+    public final Graph copy() {
+        return copy(name, null);
+    }
+
+    /**
+     * Creates a copy of this graph.
+     *
+     * @param duplicationMapCallback consumer of the duplication map created during the copying
+     */
+    public final Graph copy(Consumer<Map<Node, Node>> duplicationMapCallback) {
+        return copy(name, duplicationMapCallback);
     }
 
     /**
@@ -228,9 +238,22 @@
      *
      * @param newName the name of the copy, used for debugging purposes (can be null)
      */
-    public Graph copy(String newName) {
+    public final Graph copy(String newName) {
+        return copy(newName, null);
+    }
+
+    /**
+     * Creates a copy of this graph.
+     *
+     * @param newName the name of the copy, used for debugging purposes (can be null)
+     * @param duplicationMapCallback consumer of the duplication map created during the copying
+     */
+    protected Graph copy(String newName, Consumer<Map<Node, Node>> duplicationMapCallback) {
         Graph copy = new Graph(newName);
-        copy.addDuplicates(getNodes(), this, this.getNodeCount(), (Map<Node, Node>) null);
+        Map<Node, Node> duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), (Map<Node, Node>) null);
+        if (duplicationMapCallback != null) {
+            duplicationMapCallback.accept(duplicates);
+        }
         return copy;
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java	Thu May 28 17:44:05 2015 +0200
@@ -47,7 +47,7 @@
 
     public static void translateInto(InputEdges inputs, ArrayList<InputInfo> infos) {
         for (int index = 0; index < inputs.getCount(); index++) {
-            infos.add(new InputInfo(inputs.offsets[index], inputs.getName(index), inputs.getType(index), inputs.inputTypes[index], inputs.isOptional(index)));
+            infos.add(new InputInfo(inputs.offsets[index], inputs.getName(index), inputs.getType(index), inputs.getDeclaringClass(index), inputs.inputTypes[index], inputs.isOptional(index)));
         }
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Thu May 28 17:44:05 2015 +0200
@@ -241,6 +241,11 @@
         return shortName;
     }
 
+    @Override
+    public Fields[] getAllFields() {
+        return new Fields[]{data, inputs, successors};
+    }
+
     public int[] iterableIds() {
         nodeIterableCount.increment();
         return iterableIds;
@@ -288,8 +293,8 @@
      */
     protected static class EdgeInfo extends FieldsScanner.FieldInfo {
 
-        public EdgeInfo(long offset, String name, Class<?> type) {
-            super(offset, name, type);
+        public EdgeInfo(long offset, String name, Class<?> type, Class<?> declaringClass) {
+            super(offset, name, type, declaringClass);
         }
 
         /**
@@ -317,8 +322,8 @@
         final InputType inputType;
         final boolean optional;
 
-        public InputInfo(long offset, String name, Class<?> type, InputType inputType, boolean optional) {
-            super(offset, name, type);
+        public InputInfo(long offset, String name, Class<?> type, Class<?> declaringClass, InputType inputType, boolean optional) {
+            super(offset, name, type, declaringClass);
             this.inputType = inputType;
             this.optional = optional;
         }
@@ -375,7 +380,7 @@
                     } else {
                         inputType = optionalInputAnnotation.value();
                     }
-                    inputs.add(new InputInfo(offset, field.getName(), type, inputType, field.isAnnotationPresent(Node.OptionalInput.class)));
+                    inputs.add(new InputInfo(offset, field.getName(), type, field.getDeclaringClass(), inputType, field.isAnnotationPresent(Node.OptionalInput.class)));
                 } else if (successorAnnotation != null) {
                     if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) {
                         // NodeSuccessorList fields should not be final since they are
@@ -387,7 +392,7 @@
                         GraalInternalError.guarantee(!Modifier.isFinal(modifiers), "Node successor field %s should not be final", field);
                         directSuccessors++;
                     }
-                    successors.add(new EdgeInfo(offset, field.getName(), type));
+                    successors.add(new EdgeInfo(offset, field.getName(), type, field.getDeclaringClass()));
                 } else {
                     GraalInternalError.guarantee(!NODE_CLASS.isAssignableFrom(type) || field.getName().equals("Null"), "suspicious node field: %s", field);
                     GraalInternalError.guarantee(!INPUT_LIST_CLASS.isAssignableFrom(type), "suspicious node input list field: %s", field);
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java	Thu May 28 17:44:05 2015 +0200
@@ -41,7 +41,9 @@
     }
 
     public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode[] args) {
-        b.addPush(new ForeignCallNode(foreignCalls, descriptor, args));
+        ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, descriptor, args);
+        foreignCall.setBci(b.bci());
+        b.addPush(foreignCall);
         return true;
     }
 }
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Thu May 28 17:44:05 2015 +0200
@@ -131,9 +131,10 @@
 
     private final boolean eagerResolving;
     private final boolean omitAllExceptionEdges;
+    private final boolean omitAssertions;
     private final ResolvedJavaType[] skippedExceptionTypes;
     private final DebugInfoMode debugInfoMode;
-    private final boolean doLivenessAnalysis;
+    private final boolean clearNonLiveLocals;
     private boolean useProfiling;
     private final Plugins plugins;
 
@@ -161,13 +162,14 @@
         Full,
     }
 
-    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, boolean doLivenessAnalysis,
-                    Plugins plugins) {
+    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, boolean omitAssertions, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes,
+                    boolean clearNonLiveLocals, Plugins plugins) {
         this.eagerResolving = eagerResolving;
         this.omitAllExceptionEdges = omitAllExceptionEdges;
+        this.omitAssertions = omitAssertions;
         this.debugInfoMode = debugInfoMode;
         this.skippedExceptionTypes = skippedExceptionTypes;
-        this.doLivenessAnalysis = doLivenessAnalysis;
+        this.clearNonLiveLocals = clearNonLiveLocals;
         this.useProfiling = true;
         this.plugins = plugins;
     }
@@ -179,7 +181,7 @@
      */
     public GraphBuilderConfiguration copy() {
         Plugins newPlugins = new Plugins(plugins);
-        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newPlugins);
+        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, newPlugins);
         result.useProfiling = useProfiling;
         return result;
     }
@@ -193,20 +195,24 @@
     }
 
     public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, plugins);
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins);
     }
 
     public GraphBuilderConfiguration withOmitAllExceptionEdges(boolean newOmitAllExceptionEdges) {
-        return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, plugins);
+        return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins);
+    }
+
+    public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) {
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newOmitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins);
     }
 
     public GraphBuilderConfiguration withDebugInfoMode(DebugInfoMode newDebugInfoMode) {
         ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newDebugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, plugins);
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, newDebugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins);
     }
 
-    public GraphBuilderConfiguration withDoLivenessAnalysis(boolean newLivenessAnalysis) {
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis, plugins);
+    public GraphBuilderConfiguration withClearNonLiveLocals(boolean newClearNonLiveLocals) {
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, newClearNonLiveLocals, plugins);
     }
 
     public ResolvedJavaType[] getSkippedExceptionTypes() {
@@ -221,6 +227,10 @@
         return omitAllExceptionEdges;
     }
 
+    public boolean omitAssertions() {
+        return omitAssertions;
+    }
+
     public boolean insertNonSafepointDebugInfo() {
         return debugInfoMode.ordinal() >= DebugInfoMode.Simple.ordinal();
     }
@@ -229,32 +239,36 @@
         return debugInfoMode.ordinal() >= DebugInfoMode.Full.ordinal();
     }
 
-    public boolean doLivenessAnalysis() {
-        return doLivenessAnalysis;
+    public boolean insertSimpleDebugInfo() {
+        return debugInfoMode == DebugInfoMode.Simple;
+    }
+
+    public boolean clearNonLiveLocals() {
+        return clearNonLiveLocals;
     }
 
     public static GraphBuilderConfiguration getDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(false, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     public static GraphBuilderConfiguration getInfopointDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     public static GraphBuilderConfiguration getEagerDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     public static GraphBuilderConfiguration getInfopointEagerDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, true, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(true, true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     public static GraphBuilderConfiguration getFullDebugDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     /**
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Thu May 28 17:44:05 2015 +0200
@@ -36,43 +36,12 @@
 import com.oracle.graal.nodes.type.*;
 
 /**
- * Used by a {@link GraphBuilderPlugin} to interface with a graph builder object.
+ * Used by a {@link GraphBuilderPlugin} to interface with an object that parses the bytecode of a
+ * single {@linkplain #getMethod() method} as part of building a {@linkplain #getGraph() graph} .
  */
 public interface GraphBuilderContext {
 
     /**
-     * Information about a snippet or method substitution currently being processed by the graph
-     * builder. When in the scope of a replacement, the graph builder does not check the value kinds
-     * flowing through the JVM state since replacements can employ non-Java kinds to represent
-     * values such as raw machine words and pointers.
-     */
-    public interface Replacement {
-
-        /**
-         * Gets the method being replaced.
-         */
-        ResolvedJavaMethod getOriginalMethod();
-
-        /**
-         * Gets the replacement method.
-         */
-        ResolvedJavaMethod getReplacementMethod();
-
-        /**
-         * Determines if this replacement is being inlined as a compiler intrinsic. A compiler
-         * intrinsic is atomic with respect to deoptimization. Deoptimization within a compiler
-         * intrinsic will restart the interpreter at the intrinsified call.
-         */
-        boolean isIntrinsic();
-
-        /**
-         * Determines if a call within the compilation scope of this replacement represents a call
-         * to the {@linkplain #getOriginalMethod() original} method.
-         */
-        boolean isCallToOriginal(ResolvedJavaMethod method);
-    }
-
-    /**
      * Raw operation for adding a node to the graph when neither {@link #add},
      * {@link #addPush(ValueNode)} nor {@link #addPush(Kind, ValueNode)} can be used.
      *
@@ -115,8 +84,8 @@
         T equivalentValue = append(value);
         if (equivalentValue instanceof StateSplit) {
             StateSplit stateSplit = (StateSplit) equivalentValue;
-            if (stateSplit.stateAfter() == null) {
-                stateSplit.setStateAfter(createStateAfter());
+            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
+                setStateAfter(stateSplit);
             }
         }
         return equivalentValue;
@@ -149,8 +118,8 @@
         push(kind.getStackKind(), equivalentValue);
         if (equivalentValue instanceof StateSplit) {
             StateSplit stateSplit = (StateSplit) equivalentValue;
-            if (stateSplit.stateAfter() == null) {
-                stateSplit.setStateAfter(createStateAfter());
+            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
+                setStateAfter(stateSplit);
             }
         }
         return equivalentValue;
@@ -194,9 +163,12 @@
 
     /**
      * Creates a snap shot of the current frame state with the BCI of the instruction after the one
-     * currently being parsed.
+     * currently being parsed and assigns it to a given {@linkplain StateSplit#hasSideEffect() side
+     * effect} node.
+     *
+     * @param sideEffect a side effect node just appended to the graph
      */
-    FrameState createStateAfter();
+    void setStateAfter(StateSplit sideEffect);
 
     /**
      * Gets the parsing context for the method that inlines the method being parsed by this context.
@@ -204,7 +176,19 @@
     GraphBuilderContext getParent();
 
     /**
-     * Gets the method currently being parsed.
+     * Gets the first ancestor parsing context that is not parsing a
+     * {@linkplain #parsingIntrinsic() intrinsic}.
+     */
+    default GraphBuilderContext getNonIntrinsicAncestor() {
+        GraphBuilderContext ancestor = getParent();
+        while (ancestor != null && ancestor.parsingIntrinsic()) {
+            ancestor = ancestor.getParent();
+        }
+        return ancestor;
+    }
+
+    /**
+     * Gets the method being parsed by this context.
      */
     ResolvedJavaMethod getMethod();
 
@@ -223,9 +207,18 @@
      */
     JavaType getInvokeReturnType();
 
+    default Stamp getInvokeReturnStamp() {
+        JavaType returnType = getInvokeReturnType();
+        if (returnType.getKind() == Kind.Object && returnType instanceof ResolvedJavaType) {
+            return StampFactory.declared((ResolvedJavaType) returnType);
+        } else {
+            return StampFactory.forKind(returnType.getKind());
+        }
+    }
+
     /**
-     * Gets the inline depth of this context. 0 implies this is the context for the compilation root
-     * method.
+     * Gets the inline depth of this context. A return value of 0 implies that this is the context
+     * for the parse root.
      */
     default int getDepth() {
         GraphBuilderContext parent = getParent();
@@ -233,17 +226,18 @@
     }
 
     /**
-     * Determines if the current parsing context is a snippet or method substitution.
+     * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined
+     * by an intrinsic.
      */
-    default boolean parsingReplacement() {
-        return getReplacement() != null;
+    default boolean parsingIntrinsic() {
+        return getIntrinsic() != null;
     }
 
     /**
-     * Gets the replacement of the current parsing context or {@code null} if not
-     * {@link #parsingReplacement() parsing a replacement}.
+     * Gets the intrinsic of the current parsing context or {@code null} if not
+     * {@link #parsingIntrinsic() parsing an intrinsic}.
      */
-    Replacement getReplacement();
+    IntrinsicContext getIntrinsic();
 
     BailoutException bailout(String string);
 
@@ -268,5 +262,4 @@
         }
         return value;
     }
-
 }
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java	Thu May 28 17:44:05 2015 +0200
@@ -26,8 +26,9 @@
 import com.oracle.graal.nodes.*;
 
 /**
- * Plugin for specifying what is inlined during graph parsing or for post-processing non-inlined
- * invocations that result in {@link Invoke} nodes.
+ * Plugin for specifying what is inlined during graph parsing. This plugin is also
+ * {@linkplain #notifyOfNoninlinedInvoke notified} of non-inlined invocations (i.e., those for which
+ * an {@link Invoke} node is created).
  */
 public interface InlineInvokePlugin extends GraphBuilderPlugin {
 
@@ -39,24 +40,14 @@
         public final ResolvedJavaMethod methodToInline;
 
         /**
-         * Specifies if {@link #methodToInline} is to be considered a
-         * {@linkplain GraphBuilderContext.Replacement replacement} for the {@code method} passed to
-         * {@link InlineInvokePlugin#getInlineInfo}.
-         */
-        public final boolean isReplacement;
-
-        /**
-         * Specifies if {@link #methodToInline} is an intrinsic for the original method. If so, any
-         * {@link StateSplit} node created in the (recursive) inlining scope will be given a frame
-         * state that restarts the interpreter just before the intrinsified invocation.
+         * Specifies if {@link #methodToInline} is an intrinsic for the original method (i.e., the
+         * {@code method} passed to {@link InlineInvokePlugin#getInlineInfo}).
          */
         public final boolean isIntrinsic;
 
-        public InlineInfo(ResolvedJavaMethod methodToInline, boolean isReplacement, boolean isIntrinsic) {
+        public InlineInfo(ResolvedJavaMethod methodToInline, boolean isIntrinsic) {
             this.methodToInline = methodToInline;
             this.isIntrinsic = isIntrinsic;
-            this.isReplacement = isReplacement;
-            assert !isIntrinsic || isReplacement : "cannot be an intrinsic without also being a replacement";
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/IntrinsicContext.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.graphbuilderconf;
+
+import static com.oracle.graal.api.code.BytecodeFrame.*;
+import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * An intrinsic is a substitute implementation of a Java method (or a bytecode in the case of
+ * snippets) that is itself implemented in Java. This interface provides information about the
+ * intrinsic currently being processed by the graph builder.
+ *
+ * When in the scope of an intrinsic, the graph builder does not check the value kinds flowing
+ * through the JVM state since intrinsics can employ non-Java kinds to represent values such as raw
+ * machine words and pointers.
+ */
+public class IntrinsicContext {
+
+    /**
+     * Gets the method being intrinsified.
+     */
+    final ResolvedJavaMethod method;
+
+    /**
+     * Gets the method providing the intrinsic implementation.
+     */
+    final ResolvedJavaMethod intrinsic;
+
+    public ResolvedJavaMethod getOriginalMethod() {
+        return method;
+    }
+
+    public ResolvedJavaMethod getIntrinsicMethod() {
+        return intrinsic;
+    }
+
+    /**
+     * Determines if a call within the compilation scope of this intrinsic represents a call to the
+     * {@linkplain #getOriginalMethod() original} method. This denotes the path where a partial
+     * intrinsification falls back to the original method.
+     */
+    public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) {
+        return method.equals(targetMethod) || intrinsic.equals(targetMethod);
+    }
+
+    final CompilationContext compilationContext;
+
+    public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, CompilationContext compilationContext) {
+        this.method = method;
+        this.intrinsic = intrinsic;
+        this.compilationContext = compilationContext;
+        assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
+    }
+
+    public boolean isPostParseInlined() {
+        return compilationContext.equals(INLINE_AFTER_PARSING);
+    }
+
+    public boolean isCompilationRoot() {
+        return compilationContext.equals(ROOT_COMPILATION);
+    }
+
+    /**
+     * Denotes the compilation context in which an intrinsic is being parsed.
+     */
+    public enum CompilationContext {
+        /**
+         * An intrinsic is being processed when parsing an invoke bytecode that calls the
+         * intrinsified method.
+         */
+        INLINE_DURING_PARSING,
+
+        /**
+         * An intrinsic is being processed when inlining an {@link Invoke} in an existing graph.
+         */
+        INLINE_AFTER_PARSING,
+
+        /**
+         * An intrinsic is the root of compilation.
+         */
+        ROOT_COMPILATION
+    }
+
+    /**
+     * Models the state of a graph in terms of {@link StateSplit#hasSideEffect() side effects} that
+     * are control flow predecessors of the current point in a graph.
+     */
+    public interface SideEffectsState {
+
+        /**
+         * Determines if the current program point is preceded by one or more side effects.
+         */
+        boolean isAfterSideEffect();
+
+        /**
+         * Gets the side effects preceding the current program point.
+         */
+        Iterable<StateSplit> sideEffects();
+
+        /**
+         * Records a side effect for the current program point.
+         */
+        void addSideEffect(StateSplit sideEffect);
+    }
+
+    public FrameState createFrameState(StructuredGraph graph, SideEffectsState sideEffects, StateSplit forStateSplit) {
+        assert forStateSplit != graph.start();
+        if (forStateSplit.hasSideEffect()) {
+            if (sideEffects.isAfterSideEffect()) {
+                // Only the last side effect on any execution path in a replacement
+                // can inherit the stateAfter of the replaced node
+                FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI));
+                for (StateSplit lastSideEffect : sideEffects.sideEffects()) {
+                    lastSideEffect.setStateAfter(invalid);
+                }
+            }
+            sideEffects.addSideEffect(forStateSplit);
+            return graph.add(new FrameState(AFTER_BCI));
+        } else {
+            if (forStateSplit instanceof AbstractMergeNode) {
+                // Merge nodes always need a frame state
+                if (sideEffects.isAfterSideEffect()) {
+                    // A merge after one or more side effects
+                    return graph.add(new FrameState(AFTER_BCI));
+                } else {
+                    // A merge before any side effects
+                    return graph.add(new FrameState(BEFORE_BCI));
+                }
+            } else {
+                // Other non-side-effects do not need a state
+                return null;
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", intrinsic: " + intrinsic.format("%H.%n(%p)") + ", context: " + compilationContext + "}";
+    }
+}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Thu May 28 17:44:05 2015 +0200
@@ -227,6 +227,14 @@
     }
 
     /**
+     * Disallows new registrations of new plugins, and creates the internal tables for method
+     * lookup.
+     */
+    public void closeRegistration() {
+        plugins.createEntries();
+    }
+
+    /**
      * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched}
      * before searching in this object.
      */
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java	Thu May 28 17:44:05 2015 +0200
@@ -40,7 +40,7 @@
         JavaConstant result = constantReflection.readConstantFieldValue(field, receiver);
         if (result != null) {
             ConstantNode constantNode = ConstantNode.forConstant(result, metaAccess);
-            b.addPush(constantNode.getKind().getStackKind(), constantNode);
+            b.addPush(field.getKind(), constantNode);
             return true;
         }
         return false;
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdHolder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdHolder.java	Thu May 28 17:44:05 2015 +0200
@@ -62,7 +62,7 @@
                     idVerifierMap.put(holder, id);
                 }
             } else {
-                assert idVerifierMap.get(holder) == id;
+                assert !idVerifierMap.containsKey(holder) || idVerifierMap.get(holder) == id;
             }
             return id;
         }
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdMap.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdMap.java	Thu May 28 17:44:05 2015 +0200
@@ -199,38 +199,7 @@
 
     public V get(MethodIdHolder method) {
         if (entries == null) {
-            // 'assignIds' synchronizes on a global lock which ensures thread safe
-            // allocation of identifiers across all MethodIdHolder objects
-            MethodIdHolder.assignIds(new Consumer<MethodIdAllocator>() {
-
-                public void accept(MethodIdAllocator idAllocator) {
-                    if (entries == null) {
-                        if (registrations.isEmpty()) {
-                            entries = allocateEntries(0);
-                        } else {
-                            int max = Integer.MIN_VALUE;
-                            for (MethodKey<V> methodKey : registrations) {
-                                MethodIdHolder m = methodKey.resolve(metaAccess);
-                                int id = idAllocator.assignId(m);
-                                if (id < minId) {
-                                    minId = id;
-                                }
-                                if (id > max) {
-                                    max = id;
-                                }
-                                methodKey.id = id;
-                            }
-
-                            int length = (max - minId) + 1;
-                            entries = allocateEntries(length);
-                            for (MethodKey<V> m : registrations) {
-                                int index = m.id - minId;
-                                entries[index] = m.value;
-                            }
-                        }
-                    }
-                }
-            });
+            createEntries();
         }
 
         int id = method.getMethodId();
@@ -238,6 +207,41 @@
         return index >= 0 && index < entries.length ? entries[index] : null;
     }
 
+    public void createEntries() {
+        // 'assignIds' synchronizes on a global lock which ensures thread safe
+        // allocation of identifiers across all MethodIdHolder objects
+        MethodIdHolder.assignIds(new Consumer<MethodIdAllocator>() {
+
+            public void accept(MethodIdAllocator idAllocator) {
+                if (entries == null) {
+                    if (registrations.isEmpty()) {
+                        entries = allocateEntries(0);
+                    } else {
+                        int max = Integer.MIN_VALUE;
+                        for (MethodKey<V> methodKey : registrations) {
+                            MethodIdHolder m = methodKey.resolve(metaAccess);
+                            int id = idAllocator.assignId(m);
+                            if (id < minId) {
+                                minId = id;
+                            }
+                            if (id > max) {
+                                max = id;
+                            }
+                            methodKey.id = id;
+                        }
+
+                        int length = (max - minId) + 1;
+                        entries = allocateEntries(length);
+                        for (MethodKey<V> m : registrations) {
+                            int index = m.id - minId;
+                            entries[index] = m.value;
+                        }
+                    }
+                }
+            }
+        });
+    }
+
     @Override
     public String toString() {
         return registrations.stream().map(MethodKey::toString).collect(Collectors.joining(", "));
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Thu May 28 17:44:05 2015 +0200
@@ -36,10 +36,10 @@
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
+import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
@@ -251,7 +251,7 @@
         emitCodeBody(installedCodeOwner, crb, lir);
 
         // Emit the suffix
-        emitCodeSuffix(installedCodeOwner, crb, asm, frameMap);
+        emitCodeSuffix(installedCodeOwner, crb, asm, config, frameMap);
 
         // Profile assembler instructions
         profileInstructions(lir, crb);
@@ -265,7 +265,7 @@
     public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, RegisterConfig regConfig, HotSpotVMConfig config, Label verifiedEntry) {
         HotSpotProviders providers = getProviders();
         if (installedCodeOwner != null && !installedCodeOwner.isStatic()) {
-            MarkId.recordMark(crb, MarkId.UNVERIFIED_ENTRY);
+            crb.recordMark(config.MARKID_UNVERIFIED_ENTRY);
             CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, getTarget(), false);
             Register inlineCacheKlass = rax; // see definition of IC_Klass in
                                              // c1_LIRAssembler_x86.cpp
@@ -287,9 +287,9 @@
         }
 
         asm.align(config.codeEntryAlignment);
-        MarkId.recordMark(crb, MarkId.OSR_ENTRY);
+        crb.recordMark(config.MARKID_OSR_ENTRY);
         asm.bind(verifiedEntry);
-        MarkId.recordMark(crb, MarkId.VERIFIED_ENTRY);
+        crb.recordMark(config.MARKID_VERIFIED_ENTRY);
     }
 
     /**
@@ -303,15 +303,16 @@
 
     /**
      * @param installedCodeOwner see {@link Backend#emitCode}
+     * @param config
      */
-    public void emitCodeSuffix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, FrameMap frameMap) {
+    public void emitCodeSuffix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, HotSpotVMConfig config, FrameMap frameMap) {
         HotSpotProviders providers = getProviders();
         HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
         if (!frameContext.isStub) {
             HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
-            MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY);
+            crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
             AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
-            MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY);
+            crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
             AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null);
         } else {
             // No need to emit the stubs for entries back into the method since
@@ -324,4 +325,10 @@
         }
     }
 
+    @Override
+    public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new AMD64HotSpotRegisterAllocationConfig(registerConfigNonNull);
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Thu May 28 17:44:05 2015 +0200
@@ -223,7 +223,7 @@
     }
 
     protected HotSpotCodeCacheProvider createCodeCache(HotSpotGraalRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) {
-        return new HotSpotCodeCacheProvider(runtime, target, regConfig);
+        return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig);
     }
 
     protected HotSpotMetaAccessProvider createMetaAccess(HotSpotGraalRuntimeProvider runtime) {
@@ -269,15 +269,15 @@
         } else {
             /*
              * System V Application Binary Interface, AMD64 Architecture Processor Supplement
-             *
+             * 
              * Draft Version 0.96
-             *
+             * 
              * http://www.uclibc.org/docs/psABI-x86_64.pdf
-             *
+             * 
              * 3.2.1
-             *
+             * 
              * ...
-             *
+             * 
              * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12
              * through %r15 "belong" to the calling function and the called function is required to
              * preserve their values. In other words, a called function must preserve these
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableAddressOp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableAddressOp.java	Thu May 28 17:44:05 2015 +0200
@@ -25,20 +25,22 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.*;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.hotspot.HotSpotGraalRuntime;
 
 public final class AMD64HotSpotCardTableAddressOp extends AMD64LIRInstruction {
     public static final LIRInstructionClass<AMD64HotSpotCardTableAddressOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCardTableAddressOp.class);
 
     @Def({OperandFlag.REG}) private AllocatableValue result;
 
-    public AMD64HotSpotCardTableAddressOp(AllocatableValue result) {
+    private final HotSpotVMConfig config;
+
+    public AMD64HotSpotCardTableAddressOp(AllocatableValue result, HotSpotVMConfig config) {
         super(TYPE);
         this.result = result;
+        this.config = config;
     }
 
     @Override
@@ -48,7 +50,7 @@
         JavaConstant address = JavaConstant.forIntegerKind(hostWordKind, 0);
         // recordDataReferenceInCode forces the mov to be rip-relative
         asm.movq(ValueUtil.asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(address, alignment));
-        MarkId.recordMark(crb, MarkId.CARD_TABLE_ADDRESS);
+        crb.recordMark(config.MARKID_CARD_TABLE_ADDRESS);
     }
 
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableShiftOp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableShiftOp.java	Thu May 28 17:44:05 2015 +0200
@@ -25,20 +25,22 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.*;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.hotspot.HotSpotGraalRuntime;
 
 public final class AMD64HotSpotCardTableShiftOp extends AMD64LIRInstruction {
     public static final LIRInstructionClass<AMD64HotSpotCardTableShiftOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCardTableShiftOp.class);
 
     @Def({OperandFlag.REG, OperandFlag.ILLEGAL}) private AllocatableValue result;
 
-    public AMD64HotSpotCardTableShiftOp(AllocatableValue result) {
+    private final HotSpotVMConfig config;
+
+    public AMD64HotSpotCardTableShiftOp(AllocatableValue result, HotSpotVMConfig config) {
         super(TYPE);
         this.result = result;
+        this.config = config;
     }
 
     @Override
@@ -48,6 +50,6 @@
         JavaConstant shift = JavaConstant.forIntegerKind(hostWordKind, 0);
         // recordDataReferenceInCode forces the mov to be rip-relative
         asm.movq(ValueUtil.asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(shift, alignment));
-        MarkId.recordMark(crb, MarkId.CARD_TABLE_SHIFT);
+        crb.recordMark(config.MARKID_CARD_TABLE_SHIFT);
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Thu May 28 17:44:05 2015 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot.amd64;
 
 import static com.oracle.graal.amd64.AMD64.*;
-import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*;
 import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*;
 import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
@@ -34,13 +33,10 @@
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp;
 import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.spi.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
@@ -52,8 +48,6 @@
 import com.oracle.graal.lir.StandardOp.NoOp;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
-import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
 import com.oracle.graal.lir.asm.*;
@@ -261,14 +255,14 @@
     @Override
     public Value emitCardTableShift() {
         Variable result = newVariable(LIRKind.value(Kind.Long));
-        append(new AMD64HotSpotCardTableShiftOp(result));
+        append(new AMD64HotSpotCardTableShiftOp(result, config));
         return result;
     }
 
     @Override
     public Value emitCardTableAddress() {
         Variable result = newVariable(LIRKind.value(Kind.Long));
-        append(new AMD64HotSpotCardTableAddressOp(result));
+        append(new AMD64HotSpotCardTableAddressOp(result, config));
         return result;
     }
 
@@ -494,15 +488,6 @@
         }
     }
 
-    private static LIRKind toStackKind(LIRKind kind) {
-        if (kind.getPlatformKind() instanceof Kind) {
-            Kind stackKind = ((Kind) kind.getPlatformKind()).getStackKind();
-            return kind.changeType(stackKind);
-        } else {
-            return kind;
-        }
-    }
-
     public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
         Variable frameSizeVariable = load(frameSize);
         Variable framePcVariable = load(framePc);
@@ -512,47 +497,8 @@
     }
 
     @Override
-    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
-        AMD64AddressValue loadAddress = asAddressValue(address);
-        Variable result = newVariable(toStackKind(kind));
-        switch ((Kind) kind.getPlatformKind()) {
-            case Boolean:
-                append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, loadAddress, state));
-                break;
-            case Byte:
-                append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state));
-                break;
-            case Char:
-                append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, loadAddress, state));
-                break;
-            case Short:
-                append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state));
-                break;
-            case Int:
-                append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state));
-                break;
-            case Long:
-            case Object:
-                append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state));
-                break;
-            case Float:
-                append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state));
-                break;
-            case Double:
-                append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-        return result;
-    }
-
-    private void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) {
-        if (value.isNull()) {
-            assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object;
-            OperandSize size = kind == Kind.Int ? DWORD : QWORD;
-            append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state));
-        } else if (value instanceof HotSpotConstant) {
+    protected void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) {
+        if (value instanceof HotSpotConstant && value.isNonNull()) {
             HotSpotConstant c = (HotSpotConstant) value;
             if (c.isCompressed()) {
                 assert kind == Kind.Int;
@@ -565,86 +511,7 @@
                 emitStore(kind, address, asAllocatable(value), state);
             }
         } else {
-            AMD64MIOp op = AMD64MIOp.MOV;
-            OperandSize size;
-            long imm;
-
-            switch (kind) {
-                case Boolean:
-                case Byte:
-                    op = AMD64MIOp.MOVB;
-                    size = BYTE;
-                    imm = value.asInt();
-                    break;
-                case Char:
-                case Short:
-                    size = WORD;
-                    imm = value.asInt();
-                    break;
-                case Int:
-                    size = DWORD;
-                    imm = value.asInt();
-                    break;
-                case Long:
-                    size = QWORD;
-                    imm = value.asLong();
-                    break;
-                case Float:
-                    size = DWORD;
-                    imm = Float.floatToRawIntBits(value.asFloat());
-                    break;
-                case Double:
-                    size = QWORD;
-                    imm = Double.doubleToRawLongBits(value.asDouble());
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere("unexpected kind " + kind);
-            }
-
-            if (NumUtil.isInt(imm)) {
-                append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state));
-            } else {
-                emitStore(kind, address, asAllocatable(value), state);
-            }
-        }
-    }
-
-    private void emitStore(Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) {
-        switch (kind) {
-            case Boolean:
-            case Byte:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state));
-                break;
-            case Char:
-            case Short:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state));
-                break;
-            case Int:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state));
-                break;
-            case Long:
-            case Object:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state));
-                break;
-            case Float:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state));
-                break;
-            case Double:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    @Override
-    public void emitStore(LIRKind lirKind, Value address, Value input, LIRFrameState state) {
-        AMD64AddressValue storeAddress = asAddressValue(address);
-        Kind kind = (Kind) lirKind.getPlatformKind();
-        if (isConstant(input)) {
-            emitStoreConst(kind, storeAddress, asConstant(input), state);
-        } else {
-            emitStore(kind, storeAddress, asAllocatable(input), state);
+            super.emitStoreConst(kind, address, value, state);
         }
     }
 
@@ -699,40 +566,7 @@
         }
     }
 
-    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
-        LIRKind kind = newValue.getLIRKind();
-        assert kind.equals(expectedValue.getLIRKind());
-        Kind memKind = (Kind) kind.getPlatformKind();
-
-        AMD64AddressValue addressValue = asAddressValue(address);
-        RegisterValue raxRes = AMD64.rax.asValue(kind);
-        emitMove(raxRes, expectedValue);
-        append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
-
-        assert trueValue.getLIRKind().equals(falseValue.getLIRKind());
-        Variable result = newVariable(trueValue.getLIRKind());
-        append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
-        return result;
-    }
-
-    public Value emitAtomicReadAndAdd(Value address, Value delta) {
-        LIRKind kind = delta.getLIRKind();
-        Kind memKind = (Kind) kind.getPlatformKind();
-        Variable result = newVariable(kind);
-        AMD64AddressValue addressValue = asAddressValue(address);
-        append(new AMD64Move.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta)));
-        return result;
-    }
-
-    public Value emitAtomicReadAndWrite(Value address, Value newValue) {
-        LIRKind kind = newValue.getLIRKind();
-        Kind memKind = (Kind) kind.getPlatformKind();
-        Variable result = newVariable(kind);
-        AMD64AddressValue addressValue = asAddressValue(address);
-        append(new AMD64Move.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue)));
-        return result;
-    }
-
+    @Override
     public void emitNullCheck(Value address, LIRFrameState state) {
         if (address.getLIRKind().getPlatformKind() == Kind.Int) {
             CompressEncoding encoding = config.getOopEncoding();
@@ -744,8 +578,7 @@
             }
             append(new AMD64Move.NullCheckOp(asAddressValue(uncompressed), state));
         } else {
-            assert address.getKind() == Kind.Object || address.getKind() == Kind.Long : address + " - " + address.getKind() + " not a pointer!";
-            append(new AMD64Move.NullCheckOp(asAddressValue(address), state));
+            super.emitNullCheck(address, state);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Thu May 28 17:44:05 2015 +0200
@@ -53,6 +53,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 
 /**
  * LIR generator specialized for AMD64 HotSpot.
@@ -158,7 +159,7 @@
             assert invokeKind.isDirect();
             HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
             assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method.";
-            append(new AMD64HotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind));
+            append(new AMD64HotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, runtime.getConfig()));
         }
     }
 
@@ -171,7 +172,7 @@
             AllocatableValue targetAddressDst = AMD64.rax.asValue(targetAddressSrc.getLIRKind());
             gen.emitMove(metaspaceMethodDst, metaspaceMethodSrc);
             gen.emitMove(targetAddressDst, targetAddressSrc);
-            append(new AMD64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethodDst, targetAddressDst, callState));
+            append(new AMD64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethodDst, targetAddressDst, callState, runtime.getConfig()));
         } else {
             super.emitIndirectCall(callTarget, result, parameters, temps, callState);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterAllocationConfig.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.alloc.*;
+
+class AMD64HotSpotRegisterAllocationConfig extends RegisterAllocationConfig {
+    /**
+     * Specify priority of register selection within phases of register allocation. Highest priority
+     * is first. A useful heuristic is to give registers a low priority when they are required by
+     * machine instructions, like EAX and EDX on I486, and choose no-save registers before
+     * save-on-call, & save-on-call before save-on-entry. Registers which participate in fixed
+     * calling sequences should come last. Registers which are used as pairs must fall on an even
+     * boundary.
+     *
+     * Adopted from x86_64.ad.
+     */
+    // @formatter:off
+    static final Register[] registerAllocationOrder = {
+        r10, r11, r8, r9, r12, rcx, rbx, rdi, rdx, rsi, rax, rbp, r13, r14, /*r15,*/ /*rsp,*/
+        xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
+        xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
+    };
+    // @formatter:on
+
+    public AMD64HotSpotRegisterAllocationConfig(RegisterConfig registerConfig) {
+        super(registerConfig);
+    }
+
+    @Override
+    protected Register[] initAllocatable(Register[] registers) {
+        BitSet regMap = new BitSet(registerConfig.getAllocatableRegisters().length);
+        Register[] regs = super.initAllocatable(registers);
+        for (Register reg : regs) {
+            regMap.set(reg.number);
+        }
+
+        Register[] allocatableRegisters = new Register[regs.length];
+        int i = 0;
+        for (Register reg : registerAllocationOrder) {
+            if (regMap.get(reg.number)) {
+                allocatableRegisters[i++] = reg;
+            }
+        }
+
+        assert i == allocatableRegisters.length;
+        return allocatableRegisters;
+    }
+
+    @Override
+    protected AllocatableRegisters createAllocatableRegisters(Register[] registers) {
+        int min = Integer.MAX_VALUE;
+        int max = Integer.MIN_VALUE;
+        for (Register reg : registers) {
+            int number = reg.number;
+            if (number < min) {
+                min = number;
+            }
+            if (number > max) {
+                max = number;
+            }
+        }
+        assert min < max;
+        return new AllocatableRegisters(registers, min, max);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Thu May 28 17:44:05 2015 +0200
@@ -30,7 +30,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
@@ -84,21 +83,21 @@
             // co-located with the immutable code.
             asm.movq(scratch, (AMD64Address) crb.recordDataReferenceInCode(pollingPageAddress, alignment));
             final int pos = asm.position();
-            MarkId.recordMark(crb, atReturn ? MarkId.POLL_RETURN_FAR : MarkId.POLL_FAR);
+            crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
             if (state != null) {
                 crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
             }
             asm.testl(rax, new AMD64Address(scratch));
         } else if (isPollingPageFar(config)) {
             asm.movq(scratch, config.safepointPollingAddress);
-            MarkId.recordMark(crb, atReturn ? MarkId.POLL_RETURN_FAR : MarkId.POLL_FAR);
+            crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
             final int pos = asm.position();
             if (state != null) {
                 crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
             }
             asm.testl(rax, new AMD64Address(scratch));
         } else {
-            MarkId.recordMark(crb, atReturn ? MarkId.POLL_RETURN_NEAR : MarkId.POLL_NEAR);
+            crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_NEAR : config.MARKID_POLL_NEAR);
             final int pos = asm.position();
             if (state != null) {
                 crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java	Thu May 28 17:44:05 2015 +0200
@@ -24,7 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp;
 import com.oracle.graal.lir.asm.*;
@@ -39,16 +39,18 @@
     public static final LIRInstructionClass<AMD64HotspotDirectStaticCallOp> TYPE = LIRInstructionClass.create(AMD64HotspotDirectStaticCallOp.class);
 
     private final InvokeKind invokeKind;
+    private final HotSpotVMConfig config;
 
-    AMD64HotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind) {
+    AMD64HotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, HotSpotVMConfig config) {
         super(TYPE, target, result, parameters, temps, state);
         assert invokeKind.isDirect();
         this.invokeKind = invokeKind;
+        this.config = config;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        MarkId.recordMark(crb, invokeKind == InvokeKind.Static ? MarkId.INVOKESTATIC : MarkId.INVOKESPECIAL);
+        crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL);
         super.emitCode(crb, masm);
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java	Thu May 28 17:44:05 2015 +0200
@@ -26,9 +26,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.AMD64Call.*;
+import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 
@@ -54,7 +53,7 @@
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
         // The mark for an invocation that uses an inline cache must be placed at the
         // instruction that loads the Klass from the inline cache.
-        MarkId.recordMark(crb, invokeKind == InvokeKind.Virtual ? MarkId.INVOKEVIRTUAL : MarkId.INVOKEINTERFACE);
+        crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE);
         // This must be emitted exactly like this to ensure it's patchable
         masm.movq(AMD64.rax, config.nonOopBits);
         super.emitCode(crb, masm);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java	Thu May 28 17:44:05 2015 +0200
@@ -29,7 +29,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.amd64.AMD64Call.IndirectCallOp;
@@ -52,14 +52,17 @@
 
     @Use({REG}) protected Value metaspaceMethod;
 
-    AMD64IndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state) {
+    private final HotSpotVMConfig config;
+
+    AMD64IndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state, HotSpotVMConfig config) {
         super(TYPE, targetMethod, result, parameters, temps, targetAddress, state);
         this.metaspaceMethod = metaspaceMethod;
+        this.config = config;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        MarkId.recordMark(crb, MarkId.INLINE_INVOKE);
+        crb.recordMark(config.MARKID_INLINE_INVOKE);
         Register callReg = asRegister(targetAddress);
         assert !callReg.equals(METHOD);
         AMD64Call.indirectCall(crb, masm, callReg, callTarget, state);
--- a/graal/com.oracle.graal.hotspot.server/overview.html	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-<html>
-<head>
-<!--
-
-Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
-DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-
-This code is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 2 only, as
-published by the Free Software Foundation.  Oracle designates this
-particular file as subject to the "Classpath" exception as provided
-by Oracle in the LICENSE file that accompanied this code.
-
-This code is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-version 2 for more details (a copy is included in the LICENSE file that
-accompanied this code).
-
-You should have received a copy of the GNU General Public License version
-2 along with this work; if not, write to the Free Software Foundation,
-Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-or visit www.oracle.com if you need additional information or have any
-questions.
--->
-
-</head>
-<body>
-
-Documentation for the <code>com.oracle.graal.hotspot.server</code> project.
-
-</body>
-</html>
--- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/CompilationServer.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.server;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-
-import javax.net.*;
-
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.bridge.*;
-import com.oracle.graal.hotspot.logging.*;
-
-/**
- * Server side of the client/server compilation model. The server listens for connections on the
- * hardcoded port 1199.
- */
-public class CompilationServer implements Runnable {
-
-    public static void main(String[] args) throws Exception {
-        new CompilationServer(false).run();
-    }
-
-    public interface ConnectionObserver {
-
-        void connectionStarted(HotSpotGraalRuntimeProvider compiler);
-
-        void connectionFinished(HotSpotGraalRuntimeProvider compiler);
-    }
-
-    private final boolean multiple;
-    private final ArrayList<ConnectionObserver> observers = new ArrayList<>();
-
-    /**
-     * Creates a new Compilation server. The server is activated by calling {@link #run()} directly
-     * or via a new {@link Thread}.
-     *
-     * @param multiple true if the server should server should serve an infinite amount of
-     *            consecutive connections, false if it should terminate after the first connection
-     *            ends.
-     */
-    public CompilationServer(boolean multiple) {
-        this.multiple = multiple;
-    }
-
-    public void addConnectionObserver(ConnectionObserver observer) {
-        observers.add(observer);
-    }
-
-    public void removeConnectionObserver(ConnectionObserver observer) {
-        observers.remove(observer);
-    }
-
-    public void run() {
-        final ServerSocket serverSocket;
-        try {
-            serverSocket = ServerSocketFactory.getDefault().createServerSocket(1199);
-        } catch (IOException e) {
-            throw new RuntimeException("Couldn't create compilation server", e);
-        }
-        do {
-            Socket socket = null;
-            try {
-                Logger.log("Compilation server ready, waiting for client to connect...");
-                socket = serverSocket.accept();
-                Logger.log("Connected to " + socket.getRemoteSocketAddress());
-
-                ReplacingStreams streams = new ReplacingStreams(socket.getOutputStream(), socket.getInputStream());
-
-                // get the CompilerToVM proxy from the client
-                CompilerToVM toVM = (CompilerToVM) streams.getInvocation().waitForResult(false);
-
-                // return the initialized compiler to the client
-                HotSpotGraalRuntimeProvider compiler = initializeServer(toVM);
-                streams.getInvocation().sendResult(compiler);
-
-                for (ConnectionObserver observer : observers) {
-                    observer.connectionStarted(compiler);
-                }
-
-                streams.getInvocation().waitForResult(true);
-
-                for (ConnectionObserver observer : observers) {
-                    observer.connectionFinished(compiler);
-                }
-            } catch (IOException e) {
-                e.printStackTrace();
-            } catch (ClassNotFoundException e) {
-                throw new RuntimeException(e);
-            } finally {
-                if (socket != null) {
-                    try {
-                        socket.close();
-                    } catch (IOException e) {
-                    }
-                }
-            }
-        } while (multiple);
-    }
-
-    @SuppressWarnings("unused")
-    private static HotSpotGraalRuntimeProvider initializeServer(CompilerToVM toVM) {
-        // TODO(thomaswue): Fix creation of compiler instances on server side.
-        return null;
-    }
-}
--- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/InvocationSocket.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,284 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.server;
-
-import java.io.*;
-import java.lang.reflect.*;
-import java.util.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.hotspot.logging.*;
-
-/**
- * A collection of java.lang.reflect proxies that communicate over a socket connection.
- *
- * Calling a method sends the method name and the parameters through the socket. Afterwards this
- * class waits for a result. While waiting for a result three types of objects can arrive through
- * the socket: a method invocation, a method result or an exception. Method invocation can thus be
- * recursive.
- */
-public class InvocationSocket {
-
-    private static final boolean DEBUG = false;
-    private static final boolean COUNT_CALLS = false;
-
-    private static final HashSet<String> cachedMethodNames = new HashSet<>();
-    private static final HashSet<String> forbiddenMethodNames = new HashSet<>();
-
-    static {
-        cachedMethodNames.add("name");
-        cachedMethodNames.add("kind");
-        cachedMethodNames.add("isResolved");
-        cachedMethodNames.add("getCompilerToVM");
-        cachedMethodNames.add("exactType");
-        cachedMethodNames.add("isInitialized");
-        forbiddenMethodNames.add("javaClass");
-    }
-
-    private final ObjectOutputStream output;
-    private final ObjectInputStream input;
-
-    private final Map<String, Integer> counts = new HashMap<>();
-
-    public InvocationSocket(ObjectOutputStream output, ObjectInputStream input) {
-        this.output = output;
-        this.input = input;
-
-        if (COUNT_CALLS) {
-            Runtime.getRuntime().addShutdownHook(new Thread() {
-
-                @Override
-                public void run() {
-                    SortedMap<Integer, String> sorted = new TreeMap<>();
-                    for (Map.Entry<String, Integer> entry : counts.entrySet()) {
-                        sorted.put(entry.getValue(), entry.getKey());
-                    }
-                    for (Map.Entry<Integer, String> entry : sorted.entrySet()) {
-                        TTY.println(entry.getKey() + ": " + entry.getValue());
-                    }
-                }
-            });
-        }
-    }
-
-    /**
-     * Represents one invocation of a method that is transferred via the socket connection.
-     *
-     */
-    private static class Invocation implements Serializable {
-
-        private static final long serialVersionUID = -799162779226626066L;
-
-        public Object receiver;
-        public String methodName;
-        public Object[] args;
-
-        public Invocation(Object receiver, String methodName, Object[] args) {
-            this.receiver = receiver;
-            this.methodName = methodName;
-            this.args = args;
-        }
-    }
-
-    /**
-     * Represents the result of an invocation that is transferred via the socket connection.
-     *
-     */
-    private static class Result implements Serializable {
-
-        private static final long serialVersionUID = -7496058356272415814L;
-
-        public Object result;
-
-        public Result(Object result) {
-            this.result = result;
-        }
-    }
-
-    private void incCount(String name, Object[] args) {
-        if (COUNT_CALLS) {
-            String nameAndArgCount = name + (args == null ? 0 : args.length);
-            if (counts.get(nameAndArgCount) != null) {
-                counts.put(nameAndArgCount, counts.get(nameAndArgCount) + 1);
-            } else {
-                counts.put(nameAndArgCount, 1);
-            }
-        }
-    }
-
-    /**
-     * Each instance of this class handles remote invocations for one instance of a Remote class. It
-     * will forward all interface methods to the other end of the socket and cache the results of
-     * calls to certain methods.
-     *
-     */
-    public class Handler implements InvocationHandler {
-
-        private final Object receiver;
-        private final HashMap<String, Object> cache = new HashMap<>();
-
-        public Handler(Object receiver) {
-            this.receiver = receiver;
-        }
-
-        @Override
-        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-            // only interface methods can be transferred, java.lang.Object methods
-            if (method.getDeclaringClass() == Object.class) {
-                return method.invoke(receiver, args);
-            }
-            String methodName = method.getName();
-            // check if the result of this zero-arg method was cached
-            if (args == null || args.length == 0) {
-                if (cache.containsKey(methodName)) {
-                    return cache.get(methodName);
-                }
-            }
-            if (forbiddenMethodNames.contains(methodName)) {
-                throw new IllegalAccessException(methodName + " not allowed");
-            }
-            Object result = null;
-            try {
-                if (DEBUG) {
-                    Logger.startScope("invoking remote " + methodName);
-                }
-                incCount(methodName, args);
-
-                output.writeObject(new Invocation(receiver, methodName, args));
-                output.flush();
-                result = waitForResult(false);
-
-                // result caching for selected methods
-                if ((args == null || args.length == 0) && cachedMethodNames.contains(methodName)) {
-                    cache.put(methodName, result);
-                }
-                return result;
-            } catch (Throwable t) {
-                t.printStackTrace();
-                throw t;
-            } finally {
-                if (DEBUG) {
-                    Logger.endScope(" = " + result);
-                }
-            }
-        }
-    }
-
-    /**
-     * Waits for the result of a remote method invocation. Invocations that should be executed in
-     * this VM might arrive while waiting for the result, and these invocations will be executed
-     * before again waiting fort he result.
-     */
-    @SuppressWarnings("unused")
-    public Object waitForResult(boolean eofExpected) throws IOException, ClassNotFoundException {
-        while (true) {
-            Object in;
-            try {
-                in = input.readObject();
-            } catch (EOFException e) {
-                if (eofExpected) {
-                    return null;
-                }
-                throw e;
-            }
-            if (in instanceof Result) {
-                return ((Result) in).result;
-            } else if (in instanceof RuntimeException) {
-                throw (RuntimeException) in;
-            } else if (in instanceof Throwable) {
-                throw new RuntimeException((Throwable) in);
-            }
-
-            Invocation invoke = (Invocation) in;
-            Method method = null;
-            for (Class<?> clazz = invoke.receiver.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
-                for (Method m : clazz.getDeclaredMethods()) {
-                    if (invoke.methodName.equals(m.getName())) {
-                        method = m;
-                        break;
-                    }
-                }
-            }
-            if (method == null) {
-                Exception e = new UnsupportedOperationException("unknown method " + invoke.methodName);
-                e.printStackTrace();
-                output.writeObject(e);
-                output.flush();
-            } else {
-                Object result = null;
-                try {
-                    if (invoke.args == null) {
-                        if (DEBUG) {
-                            Logger.startScope("invoking local " + invoke.methodName);
-                        }
-                        result = method.invoke(invoke.receiver);
-                    } else {
-                        if (Logger.ENABLED && DEBUG) {
-                            StringBuilder str = new StringBuilder();
-                            str.append("invoking local " + invoke.methodName + "(");
-                            for (int i = 0; i < invoke.args.length; i++) {
-                                str.append(i == 0 ? "" : ", ");
-                                str.append(Logger.pretty(invoke.args[i]));
-                            }
-                            str.append(")");
-                            Logger.startScope(str.toString());
-                        }
-                        result = method.invoke(invoke.receiver, invoke.args);
-                    }
-                    result = new Result(result);
-                } catch (IllegalArgumentException e) {
-                    TTY.println("error while invoking " + invoke.methodName);
-                    e.getCause().printStackTrace();
-                    result = e.getCause();
-                } catch (InvocationTargetException e) {
-                    TTY.println("error while invoking " + invoke.methodName);
-                    e.getCause().printStackTrace();
-                    result = e.getCause();
-                } catch (IllegalAccessException e) {
-                    TTY.println("error while invoking " + invoke.methodName);
-                    e.getCause().printStackTrace();
-                    result = e.getCause();
-                } finally {
-                    if (DEBUG) {
-                        if (result instanceof Result) {
-                            Logger.endScope(" = " + ((Result) result).result);
-                        } else {
-                            Logger.endScope(" = " + result);
-                        }
-                    }
-                }
-                output.writeObject(result);
-                output.flush();
-            }
-        }
-    }
-
-    /**
-     * Sends a result without invoking a method, used by CompilationServer startup code.
-     */
-    public void sendResult(Object obj) throws IOException {
-        output.writeObject(new Result(obj));
-        output.flush();
-    }
-    // CheckStyle: resume system..print check
-}
--- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/Remote.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.server;
-
-public interface Remote {
-
-}
--- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/ReplacingStreams.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.server;
-
-import static com.oracle.graal.graph.util.CollectionsAccess.*;
-
-import java.io.*;
-import java.lang.reflect.*;
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.logging.*;
-
-public class ReplacingStreams {
-
-    private Map<Object, Placeholder> objectMap = newIdentityMap();
-    private ArrayList<Object> objectList = new ArrayList<>();
-
-    private ReplacingOutputStream output;
-    private ReplacingInputStream input;
-
-    private InvocationSocket invocation;
-
-    public ReplacingStreams(OutputStream outputStream, InputStream inputStream) throws IOException {
-        output = new ReplacingOutputStream(new BufferedOutputStream(outputStream));
-        // required, because creating an ObjectOutputStream writes a header, but doesn't flush the
-        // stream
-        output.flush();
-        input = new ReplacingInputStream(new BufferedInputStream(inputStream));
-        invocation = new InvocationSocket(output, input);
-
-        addStaticObject(Value.ILLEGAL);
-    }
-
-    public void setInvocationSocket(InvocationSocket invocation) {
-        this.invocation = invocation;
-    }
-
-    public ReplacingOutputStream getOutput() {
-        return output;
-    }
-
-    public ReplacingInputStream getInput() {
-        return input;
-    }
-
-    public InvocationSocket getInvocation() {
-        return invocation;
-    }
-
-    private void addStaticObject(Object obj) {
-        int id = objectList.size();
-        objectList.add(obj);
-        objectMap.put(obj, new Placeholder(id));
-    }
-
-    public static class Placeholder implements Serializable {
-
-        private static final long serialVersionUID = 6071894297788156945L;
-        public final int id;
-
-        public Placeholder(int id) {
-            this.id = id;
-        }
-
-        @Override
-        public String toString() {
-            return "#<" + id + ">";
-        }
-    }
-
-    public static class NewRemoteCallPlaceholder implements Serializable {
-
-        private static final long serialVersionUID = 3084101671389500206L;
-        public final Class<?>[] interfaces;
-
-        public NewRemoteCallPlaceholder(Class<?>[] interfaces) {
-            this.interfaces = interfaces;
-        }
-    }
-
-    public static class NewDummyPlaceholder implements Serializable {
-
-        private static final long serialVersionUID = 2692666726573532288L;
-    }
-
-    /**
-     * Replaces certain cir objects that cannot easily be made Serializable.
-     */
-    public class ReplacingInputStream extends ObjectInputStream {
-
-        public ReplacingInputStream(InputStream in) throws IOException {
-            super(in);
-            enableResolveObject(true);
-        }
-
-        @Override
-        protected Object resolveObject(Object obj) throws IOException {
-            // see ReplacingInputStream.replaceObject for details on when these types of objects are
-            // created
-
-            if (obj instanceof Placeholder) {
-                Placeholder placeholder = (Placeholder) obj;
-                Object resolvedObj = objectList.get(placeholder.id);
-                return resolvedObj;
-            }
-
-            if (obj instanceof NewRemoteCallPlaceholder) {
-                NewRemoteCallPlaceholder newPlaceholder = (NewRemoteCallPlaceholder) obj;
-                Placeholder placeholder = new Placeholder(objectList.size());
-                Object resolvedObj = Proxy.newProxyInstance(getClass().getClassLoader(), newPlaceholder.interfaces, invocation.new Handler(placeholder));
-                objectMap.put(resolvedObj, placeholder);
-                objectList.add(resolvedObj);
-                return resolvedObj;
-            }
-
-            if (obj instanceof NewDummyPlaceholder) {
-                Object resolvedObj = new Placeholder(objectList.size());
-                objectMap.put(resolvedObj, (Placeholder) resolvedObj);
-                objectList.add(resolvedObj);
-                return resolvedObj;
-            }
-
-            return obj;
-        }
-    }
-
-    /**
-     * Replaces certain objects that cannot easily be made Serializable.
-     */
-    public class ReplacingOutputStream extends ObjectOutputStream {
-
-        public ReplacingOutputStream(OutputStream out) throws IOException {
-            super(out);
-            enableReplaceObject(true);
-        }
-
-        @Override
-        protected Object replaceObject(Object obj) throws IOException {
-            // is the object a known instance?
-            Placeholder placeholder = objectMap.get(obj);
-            if (placeholder != null) {
-                return placeholder;
-            }
-
-            // is the object an instance of a class that will always be executed remotely?
-            if (obj instanceof Remote) {
-                return createRemoteCallPlaceholder(obj);
-            }
-
-            // Remote object constants must implement Remote
-            assert !(obj instanceof JavaConstant) || ((JavaConstant) obj).getKind() != Kind.Object;
-
-            return obj;
-        }
-    }
-
-    private Object createRemoteCallPlaceholder(Object obj) {
-        // collect all interfaces that this object's class implements (proxies only support
-        // interfaces)
-        objectMap.put(obj, new Placeholder(objectList.size()));
-        objectList.add(obj);
-        return new NewRemoteCallPlaceholder(ProxyUtil.getAllInterfaces(obj.getClass()));
-    }
-}
--- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/package-info.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-/**
- * Implementation of a compilation server socket that delegates incoming requests to Graal.
- */
-package com.oracle.graal.hotspot.server;
-
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Thu May 28 17:44:05 2015 +0200
@@ -40,9 +40,9 @@
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister;
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
+import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
@@ -222,7 +222,7 @@
 
             // Emit the prefix
             if (unverifiedStub != null) {
-                MarkId.recordMark(crb, MarkId.UNVERIFIED_ENTRY);
+                crb.recordMark(config.MARKID_UNVERIFIED_ENTRY);
                 // We need to use JavaCall here because we haven't entered the frame yet.
                 CallingConvention cc = regConfig.getCallingConvention(JavaCall, null, new JavaType[]{getProviders().getMetaAccess().lookupJavaType(Object.class)}, getTarget(), false);
                 Register inlineCacheKlass = g5; // see MacroAssembler::ic_call
@@ -240,8 +240,8 @@
             }
 
             masm.align(config.codeEntryAlignment);
-            MarkId.recordMark(crb, MarkId.OSR_ENTRY);
-            MarkId.recordMark(crb, MarkId.VERIFIED_ENTRY);
+            crb.recordMark(config.MARKID_OSR_ENTRY);
+            crb.recordMark(config.MARKID_VERIFIED_ENTRY);
 
             // Emit code for the LIR
             crb.emit(lir);
@@ -252,9 +252,9 @@
         HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
         HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls();
         if (!frameContext.isStub) {
-            MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY);
+            crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
             SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
-            MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY);
+            crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
             SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null);
         } else {
             // No need to emit the stubs for entries back into the method since
@@ -378,4 +378,10 @@
             return overlap;
         }
     }
+
+    @Override
+    public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new RegisterAllocationConfig(registerConfigNonNull);
+    }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Thu May 28 17:44:05 2015 +0200
@@ -91,7 +91,7 @@
     }
 
     protected HotSpotCodeCacheProvider createCodeCache(HotSpotGraalRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) {
-        return new HotSpotCodeCacheProvider(runtime, target, regConfig);
+        return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig);
     }
 
     protected SPARCHotSpotBackend createBackend(HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerOp.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.sparc.*;
+
+/**
+ * Jumps to the exception handler specified by {@link #address} and leaves the current window. It
+ * does not modify the i7 register, as the exception handler stub expects the throwing pc in it.
+ * <p>
+ * See also:
+ * <li>Runtime1::generate_handle_exception c1_Runtime1_sparc.cpp
+ * <li>SharedRuntime::generate_deopt_blob at exception_in_tls_offset (sharedRuntime_sparc.cpp)
+ */
+@Opcode("JUMP_TO_EXCEPTION_HANDLER")
+final class SPARCHotSpotJumpToExceptionHandlerOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotJumpToExceptionHandlerOp> TYPE = LIRInstructionClass.create(SPARCHotSpotJumpToExceptionHandlerOp.class);
+
+    @Use(REG) AllocatableValue address;
+
+    SPARCHotSpotJumpToExceptionHandlerOp(AllocatableValue address) {
+        super(TYPE);
+        this.address = address;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        Register addrRegister = asLongReg(address);
+        masm.jmp(addrRegister);
+        masm.restoreWindow();
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Thu May 28 17:44:05 2015 +0200
@@ -49,6 +49,7 @@
 import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreOp;
+import com.oracle.graal.sparc.*;
 
 public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator {
 
@@ -214,6 +215,17 @@
     }
 
     @Override
+    public boolean canInlineConstant(JavaConstant c) {
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+            return true;
+        } else if (c instanceof HotSpotObjectConstant) {
+            return ((HotSpotObjectConstant) c).isCompressed();
+        } else {
+            return super.canInlineConstant(c);
+        }
+    }
+
+    @Override
     public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) {
         SPARCAddressValue storeAddress = asAddressValue(address);
         if (isConstant(inputVal)) {
@@ -243,15 +255,85 @@
     }
 
     @Override
+    protected SPARCLIRInstruction createMove(AllocatableValue dst, Value src) {
+        if (src instanceof JavaConstant) {
+            return new SPARCHotSpotMove.HotSpotLoadConstantOp(dst, (JavaConstant) src);
+        } else {
+            return super.createMove(dst, src);
+        }
+    }
+
+    @Override
+    public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability) {
+        Value localX = x;
+        Value localY = y;
+        if (localX instanceof HotSpotObjectConstant) {
+            localX = load(localX);
+        }
+        if (localY instanceof HotSpotObjectConstant) {
+            localY = load(localY);
+        }
+        super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability);
+    }
+
+    @Override
+    protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b) {
+        Value localA = a;
+        Value localB = b;
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(localA)) {
+            localA = SPARC.g0.asValue(LIRKind.value(Kind.Int));
+        } else if (localA instanceof HotSpotObjectConstant) {
+            localA = load(localA);
+        }
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(localB)) {
+            localB = SPARC.g0.asValue(LIRKind.value(Kind.Int));
+        } else if (localB instanceof HotSpotObjectConstant) {
+            localB = load(localB);
+        }
+        return super.emitCompare(cmpKind, localA, localB);
+    }
+
+    @Override
     public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
-        // TODO
-        throw GraalInternalError.unimplemented();
+        LIRKind inputKind = pointer.getLIRKind();
+        assert inputKind.getPlatformKind() == Kind.Long || inputKind.getPlatformKind() == Kind.Object;
+        if (inputKind.isReference(0)) {
+            // oop
+            Variable result = newVariable(LIRKind.reference(Kind.Int));
+            append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
+            return result;
+        } else {
+            // metaspace pointer
+            Variable result = newVariable(LIRKind.value(Kind.Int));
+            AllocatableValue base = Value.ILLEGAL;
+            if (encoding.base != 0) {
+                base = emitMove(JavaConstant.forLong(encoding.base));
+            }
+            append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
+            return result;
+        }
     }
 
     @Override
     public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
-        // TODO
-        throw GraalInternalError.unimplemented();
+        LIRKind inputKind = pointer.getLIRKind();
+        assert inputKind.getPlatformKind() == Kind.Int;
+        if (inputKind.isReference(0)) {
+            // oop
+            Variable result = newVariable(LIRKind.reference(Kind.Object));
+            append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
+            return result;
+        } else {
+            // metaspace pointer
+            Variable result = newVariable(LIRKind.value(Kind.Long));
+            AllocatableValue base = Value.ILLEGAL;
+            if (encoding.base != 0) {
+                base = emitMove(JavaConstant.forLong(encoding.base));
+            }
+            append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
+            return result;
+        }
     }
 
     /**
@@ -358,10 +440,16 @@
         return result;
     }
 
+    @Override
     public void emitNullCheck(Value address, LIRFrameState state) {
-        PlatformKind kind = address.getLIRKind().getPlatformKind();
-        assert kind == Kind.Object || kind == Kind.Long : address + " - " + kind + " not an object!";
-        append(new NullCheckOp(load(address), state));
+        PlatformKind kind = address.getPlatformKind();
+        if (kind == Kind.Int) {
+            CompressEncoding encoding = config.getOopEncoding();
+            Value uncompressed = emitUncompress(address, encoding, false);
+            append(new NullCheckOp(asAddressValue(uncompressed), state));
+        } else {
+            super.emitNullCheck(address, state);
+        }
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotMove.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Annul;
+import com.oracle.graal.asm.sparc.SPARCAssembler.BranchPredict;
+import com.oracle.graal.asm.sparc.SPARCAssembler.CC;
+import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag;
+import com.oracle.graal.asm.sparc.SPARCAssembler.RCondition;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.sparc.*;
+
+public class SPARCHotSpotMove {
+
+    public static final class HotSpotLoadConstantOp extends SPARCLIRInstruction implements MoveOp {
+        public static final LIRInstructionClass<HotSpotLoadConstantOp> TYPE = LIRInstructionClass.create(HotSpotLoadConstantOp.class);
+
+        @Def({REG, STACK}) private AllocatableValue result;
+        private final JavaConstant input;
+
+        public HotSpotLoadConstantOp(AllocatableValue result, JavaConstant input) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            if (isStackSlot(result)) {
+                StackSlot ss = asStackSlot(result);
+                try (ScratchRegister s1 = masm.getScratchRegister()) {
+                    Register sr1 = s1.getRegister();
+                    loadToRegister(crb, masm, sr1.asValue(), input);
+                    try (ScratchRegister s2 = masm.getScratchRegister()) {
+                        Register sr2 = s2.getRegister();
+                        int stackBias = HotSpotGraalRuntime.runtime().getConfig().stackBias;
+                        int offset = crb.frameMap.offsetForStackSlot(ss);
+                        new SPARCMacroAssembler.Setx(offset + stackBias, sr2).emit(masm);
+                        SPARCAddress addr = new SPARCAddress(SPARC.sp, sr2);
+                        Kind resultKind = (Kind) result.getPlatformKind();
+                        switch (resultKind) {
+                            case Int:
+                                masm.stw(sr1, addr);
+                                break;
+                            case Long:
+                            case Object:
+                                masm.stx(sr1, addr);
+                                break;
+                            default:
+                                throw GraalInternalError.shouldNotReachHere();
+                        }
+                    }
+                }
+            } else {
+                loadToRegister(crb, masm, result, input);
+            }
+        }
+
+        private static void loadToRegister(CompilationResultBuilder crb, SPARCMacroAssembler masm, AllocatableValue dest, JavaConstant constant) {
+            assert isRegister(dest);
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(constant)) {
+                masm.mov(0, asRegister(dest));
+            } else if (constant instanceof HotSpotObjectConstant) {
+                boolean compressed = ((HotSpotObjectConstant) constant).isCompressed();
+                if (crb.target.inlineObjects) {
+                    crb.recordInlineDataInCode(constant);
+                    if (compressed) {
+                        masm.sethi(0xDEADDEAD >>> 10, asRegister(dest));
+                        masm.add(asRegister(dest), 0xAD & 0x3F, asRegister(dest));
+                    } else {
+                        new SPARCMacroAssembler.Setx(0xDEADDEADDEADDEADL, asRegister(dest), true).emit(masm);
+                    }
+                } else {
+                    GraalInternalError.unimplemented();
+                }
+            } else if (constant instanceof HotSpotMetaspaceConstant) {
+                assert constant.getKind() == Kind.Int || constant.getKind() == Kind.Long;
+                boolean compressed = constant.getKind() == Kind.Int;
+                boolean isImmutable = GraalOptions.ImmutableCode.getValue();
+                boolean generatePIC = GraalOptions.GeneratePIC.getValue();
+                crb.recordInlineDataInCode(constant);
+                if (compressed) {
+                    if (isImmutable && generatePIC) {
+                        GraalInternalError.unimplemented();
+                    } else {
+                        new SPARCMacroAssembler.Setx(constant.asInt(), asRegister(dest), true).emit(masm);
+                    }
+                } else {
+                    if (isImmutable && generatePIC) {
+                        GraalInternalError.unimplemented();
+                    } else {
+                        new SPARCMacroAssembler.Setx(constant.asLong(), asRegister(dest), true).emit(masm);
+                    }
+                }
+            } else {
+                SPARCMove.move(crb, masm, dest, constant, SPARCDelayedControlTransfer.DUMMY);
+            }
+        }
+
+        public Value getInput() {
+            return input;
+        }
+
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    public static final class CompressPointer extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<CompressPointer> TYPE = LIRInstructionClass.create(CompressPointer.class);
+
+        private final CompressEncoding encoding;
+        private final boolean nonNull;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
+
+        public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+            this.baseRegister = baseRegister;
+            this.encoding = encoding;
+            this.nonNull = nonNull;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            SPARCMove.move(crb, masm, result, input, SPARCDelayedControlTransfer.DUMMY);
+
+            Register resReg = asRegister(result);
+            if (encoding.base != 0) {
+                Register baseReg = asRegister(baseRegister);
+                if (!nonNull) {
+                    masm.cmp(resReg, baseReg);
+                    masm.movcc(ConditionFlag.Equal, CC.Xcc, baseReg, resReg);
+                }
+                masm.sub(resReg, baseReg, resReg);
+            }
+
+            if (encoding.shift != 0) {
+                masm.srlx(resReg, encoding.shift, resReg);
+            }
+        }
+    }
+
+    public static final class UncompressPointer extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<UncompressPointer> TYPE = LIRInstructionClass.create(UncompressPointer.class);
+
+        private final CompressEncoding encoding;
+        private final boolean nonNull;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
+
+        public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+            this.baseRegister = baseRegister;
+            this.encoding = encoding;
+            this.nonNull = nonNull;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            SPARCMove.move(crb, masm, result, input, SPARCDelayedControlTransfer.DUMMY);
+
+            Register resReg = asRegister(result);
+            if (encoding.shift != 0) {
+                masm.sll(resReg, encoding.shift, resReg);
+            }
+
+            if (encoding.base != 0) {
+                if (nonNull) {
+                    masm.add(resReg, asRegister(baseRegister), resReg);
+                } else {
+                    masm.cmp(resReg, resReg);
+
+                    Label done = new Label();
+                    masm.bpr(RCondition.Rc_nz, Annul.ANNUL, done, BranchPredict.PREDICT_TAKEN, resReg);
+                    masm.add(asRegister(baseRegister), resReg, resReg);
+                    masm.bind(done);
+                }
+            }
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -104,7 +104,7 @@
             assert invokeKind.isDirect();
             HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
             assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method.";
-            append(new SPARCHotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind));
+            append(new SPARCHotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, runtime.getConfig()));
         }
     }
 
@@ -117,7 +117,7 @@
         Value targetAddressSrc = operand(callTarget.computedAddress());
         AllocatableValue targetAddress = o7.asValue(targetAddressSrc.getLIRKind());
         gen.emitMove(targetAddress, targetAddressSrc);
-        append(new SPARCIndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
+        append(new SPARCIndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethod, targetAddress, callState, runtime.getConfig()));
     }
 
     @Override
@@ -125,6 +125,10 @@
         append(new SPARCHotSpotPatchReturnAddressOp(gen.load(operand(address))));
     }
 
+    public void emitJumpToExceptionHandler(ValueNode address) {
+        append(new SPARCHotSpotJumpToExceptionHandlerOp(gen.load(operand(address))));
+    }
+
     @Override
     public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
         Variable handler = gen.load(operand(handlerInCallerPc));
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Thu May 28 17:44:05 2015 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.gen.*;
@@ -64,7 +63,7 @@
 
     public static void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm, HotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) {
         new Setx(config.safepointPollingAddress, scratch).emit(masm);
-        MarkId.recordMark(crb, atReturn ? MarkId.POLL_RETURN_FAR : MarkId.POLL_FAR);
+        crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
         final int pos = masm.position();
         masm.ldx(new SPARCAddress(scratch, 0), g0);
         if (state != null) {
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java	Thu May 28 17:44:05 2015 +0200
@@ -24,7 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.sparc.SPARCCall.DirectCallOp;
@@ -39,15 +39,17 @@
     public static final LIRInstructionClass<SPARCHotspotDirectStaticCallOp> TYPE = LIRInstructionClass.create(SPARCHotspotDirectStaticCallOp.class);
 
     private final InvokeKind invokeKind;
+    private final HotSpotVMConfig config;
 
-    SPARCHotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind) {
+    SPARCHotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, HotSpotVMConfig config) {
         super(TYPE, target, result, parameters, temps, state);
         assert invokeKind.isDirect();
         this.invokeKind = invokeKind;
+        this.config = config;
     }
 
     @Override
     public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-        MarkId.recordMark(crb, invokeKind == InvokeKind.Static ? MarkId.INVOKESTATIC : MarkId.INVOKESPECIAL);
+        crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL);
     }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java	Thu May 28 17:44:05 2015 +0200
@@ -27,9 +27,8 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.sparc.SPARCCall.DirectCallOp;
@@ -57,7 +56,7 @@
     public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
         // The mark for an invocation that uses an inline cache must be placed at the
         // instruction that loads the Klass from the inline cache.
-        MarkId.recordMark(crb, invokeKind == InvokeKind.Virtual ? MarkId.INVOKEVIRTUAL : MarkId.INVOKEINTERFACE);
+        crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE);
         Register scratchRegister = g5;
         new Setx(config.nonOopBits, scratchRegister, true).emit(masm);
     }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCIndirectCallOp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCIndirectCallOp.java	Thu May 28 17:44:05 2015 +0200
@@ -29,7 +29,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.sparc.*;
@@ -52,14 +52,17 @@
 
     @Use({REG}) protected Value metaspaceMethod;
 
-    SPARCIndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state) {
+    private final HotSpotVMConfig config;
+
+    SPARCIndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state, HotSpotVMConfig config) {
         super(TYPE, targetMethod, result, parameters, temps, targetAddress, state);
         this.metaspaceMethod = metaspaceMethod;
+        this.config = config;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-        MarkId.recordMark(crb, MarkId.INLINE_INVOKE);
+        crb.recordMark(config.MARKID_INLINE_INVOKE);
         Register callReg = asRegister(targetAddress);
         assert !callReg.equals(METHOD);
         SPARCCall.indirectCall(crb, masm, callReg, callTarget, state);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,7 @@
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.phases.*;
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ArrayCopyIntrinsificationTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ArrayCopyIntrinsificationTest.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.replacements.arraycopy.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -52,9 +53,14 @@
                         Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode);
                         LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget();
                         JavaMethod callee = directCall.targetMethod();
-                        Assert.assertTrue(callee.getName().equals("<init>"));
-                        Assert.assertTrue(getMetaAccess().lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) ||
-                                        getMetaAccess().lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass()));
+                        if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) {
+                            // A partial snippet (e.g., ArrayCopySnippets.checkcastArraycopy) may
+                            // call the original arraycopy method
+                        } else {
+                            Assert.assertTrue(callee.toString(), callee.getName().equals("<init>"));
+                            Assert.assertTrue(getMetaAccess().lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) ||
+                                            getMetaAccess().lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass()));
+                        }
                     }
                 }
             } else {
@@ -81,12 +87,9 @@
 
     @Test
     public void test0() {
-        mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified
         // Array store checks
         test("genericArraycopy", new Object(), 0, new Object[0], 0, 0);
         test("genericArraycopy", new Object[0], 0, new Object(), 0, 0);
-
-        mustIntrinsify = true;
     }
 
     @Test
@@ -145,25 +148,28 @@
 
     @Test
     public void testObject() {
-        mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified
-
         Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()};
         testHelper("objectArraycopy", src);
+    }
 
-        mustIntrinsify = true;
+    /**
+     * Tests {@link ArrayCopySnippets#checkcastArraycopyWork(Object, int, Object, int, int)}.
+     */
+    @Test
+    public void testArrayStoreException() {
+        Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()};
+        Object[] dst = new CharSequence[src.length];
+        // Will throw ArrayStoreException for 4th element
+        test("objectArraycopy", src, 0, dst, 0, src.length);
     }
 
     @Test
     public void testDisjointObject() {
-        mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified
-
         Integer[] src1 = {1, 2, 3, 4};
         test("objectArraycopy", src1, 0, src1, 1, src1.length - 1);
 
         Integer[] src2 = {1, 2, 3, 4};
         test("objectArraycopy", src2, 1, src2, 0, src2.length - 1);
-
-        mustIntrinsify = true;
     }
 
     @Test
@@ -258,10 +264,8 @@
      */
     @Test
     public void testCopyRows() {
-        mustIntrinsify = false;
         Object[][] rows = {{"a1", "a2", "a3", "a4"}, {"b1", "b2", "b3", "b4"}, {"c1", "c2", "c3", "c4"}};
         test("copyRows", rows, 4, new Integer(rows.length));
-        mustIntrinsify = true;
     }
 
     public static Object[][] copyRows(Object[][] rows, int rowSize, Integer rowCount) {
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Thu May 28 17:44:05 2015 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.test;
 
-import static com.oracle.graal.java.IntrinsicContext.*;
+import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -37,11 +37,10 @@
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.StructuredGraph.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 
 /**
@@ -54,8 +53,9 @@
         HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
         HotSpotNmethod installedCode = new HotSpotNmethod(hsMethod, compResult.getName(), true);
         HotSpotCompiledNmethod compiledNmethod = new HotSpotCompiledNmethod(hsMethod, compResult);
-        CodeInstallResult result = runtime().getCompilerToVM().installCode(compiledNmethod, installedCode, null);
-        Assert.assertEquals("Error installing method " + method + ": " + result, result, CodeInstallResult.OK);
+        int result = runtime().getCompilerToVM().installCode(compiledNmethod, installedCode, null);
+        HotSpotVMConfig config = runtime().getConfig();
+        Assert.assertEquals("Error installing method " + method + ": " + config.getCodeInstallResultDescription(result), result, config.codeInstallResultOk);
 
         // HotSpotRuntime hsRuntime = (HotSpotRuntime) getCodeCache();
         // TTY.println(hsMethod.toString());
@@ -132,7 +132,7 @@
                     StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES);
                     Plugins plugins = new Plugins(((HotSpotProviders) getProviders()).getGraphBuilderPlugins());
                     GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
-                    IntrinsicContext initialReplacementContext = new IntrinsicContext(installedCodeOwner, substMethod, null, ROOT_COMPILATION_BCI);
+                    IntrinsicContext initialReplacementContext = new IntrinsicContext(installedCodeOwner, substMethod, ROOT_COMPILATION);
                     new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph);
                     Assert.assertNotNull(getCode(installedCodeOwner, graph, true));
                     atLeastOneCompiled = true;
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,10 +39,11 @@
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
+import com.oracle.graal.nodes.memory.HeapAccess.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,7 @@
 import com.oracle.graal.hotspot.replacements.arraycopy.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Thu May 28 17:44:05 2015 +0200
@@ -31,7 +31,6 @@
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.meta.HotSpotSuitesProvider.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
-import static com.oracle.graal.phases.common.inlining.InliningUtil.*;
 
 import java.lang.management.*;
 import java.util.concurrent.*;
@@ -116,7 +115,12 @@
     /**
      * Time spent in compilation.
      */
-    public static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
+    private static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
+
+    /**
+     * Meters the {@linkplain StructuredGraph#getBytecodeSize() bytecodes} compiled.
+     */
+    private static final DebugMetric CompiledBytecodes = Debug.metric("CompiledBytecodes");
 
     public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
 
@@ -151,8 +155,7 @@
     public void runCompilation() {
         HotSpotVMConfig config = backend.getRuntime().getConfig();
         final long threadId = Thread.currentThread().getId();
-        long previousInlinedBytecodes = InlinedBytecodes.getCurrentValue();
-        long previousCompilationTime = CompilationTime.getCurrentValue();
+        long startCompilationTime = System.nanoTime();
         HotSpotInstalledCode installedCode = null;
         final boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
 
@@ -160,14 +163,14 @@
         EventProvider eventProvider = Graal.getRequiredCapability(EventProvider.class);
         CompilationEvent compilationEvent = eventProvider.newCompilationEvent();
 
+        // If there is already compiled code for this method on our level we simply return.
+        // Graal compiles are always at the highest compile level, even in non-tiered mode so we
+        // only need to check for that value.
+        if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) {
+            return;
+        }
+
         try (DebugCloseable a = CompilationTime.start()) {
-            // If there is already compiled code for this method on our level we simply return.
-            // Graal compiles are always at the highest compile level, even in non-tiered mode so we
-            // only need to check for that value.
-            if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) {
-                return;
-            }
-
             CompilationStatistics stats = CompilationStatistics.create(method, isOSR);
             final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed();
             if (printCompilation) {
@@ -183,14 +186,11 @@
                 // Begin the compilation event.
                 compilationEvent.begin();
 
-                boolean recordEvolMethodDeps = graalEnv == 0 || unsafe.getByte(graalEnv + config.graalEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0;
-
                 HotSpotProviders providers = backend.getProviders();
                 graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue()));
-                if (!recordEvolMethodDeps) {
+                if (shouldDisableMethodInliningRecording(config)) {
                     graph.disableInlinedMethodRecording();
                 }
-                InlinedBytecodes.add(method.getCodeSize());
                 CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
                 if (graph.getEntryBCI() != StructuredGraph.INVOCATION_ENTRY_BCI) {
                     // for OSR, only a pointer is passed to the method.
@@ -270,7 +270,8 @@
                 System.exit(-1);
             }
         } finally {
-            final int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes);
+            final int compiledBytecodes = graph.getBytecodeSize();
+            CompiledBytecodes.add(compiledBytecodes);
 
             // Log a compilation event.
             if (compilationEvent.shouldWrite() && installedCode != null) {
@@ -280,25 +281,40 @@
                 compilationEvent.setSucceeded(true);
                 compilationEvent.setIsOsr(isOSR);
                 compilationEvent.setCodeSize(installedCode.getSize());
-                compilationEvent.setInlinedBytes(processedBytes);
+                compilationEvent.setInlinedBytes(compiledBytecodes);
                 compilationEvent.commit();
             }
 
             if (graalEnv != 0) {
                 long ctask = unsafe.getAddress(graalEnv + config.graalEnvTaskOffset);
                 assert ctask != 0L;
-                unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, processedBytes);
+                unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, compiledBytecodes);
             }
+            long compilationTime = System.nanoTime() - startCompilationTime;
             if ((config.ciTime || config.ciTimeEach) && installedCode != null) {
-                long time = CompilationTime.getCurrentValue() - previousCompilationTime;
-                TimeUnit timeUnit = CompilationTime.getTimeUnit();
-                long timeUnitsPerSecond = timeUnit.convert(1, TimeUnit.SECONDS);
+                long timeUnitsPerSecond = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS);
                 CompilerToVM c2vm = backend.getRuntime().getCompilerToVM();
-                c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, processedBytes, time, timeUnitsPerSecond, installedCode);
+                c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, compiledBytecodes, compilationTime, timeUnitsPerSecond, installedCode);
             }
         }
     }
 
+    /**
+     * Determines whether to {@linkplain StructuredGraph#disableInlinedMethodRecording() disable}
+     * method inlining recording for the method being compiled.
+     *
+     * @see StructuredGraph#getBytecodeSize()
+     */
+    private boolean shouldDisableMethodInliningRecording(HotSpotVMConfig config) {
+        if (config.ciTime || config.ciTimeEach || CompiledBytecodes.isEnabled()) {
+            return false;
+        }
+        if (graalEnv == 0 || unsafe.getByte(graalEnv + config.graalEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0) {
+            return false;
+        }
+        return true;
+    }
+
     private String getMethodDescription() {
         return String.format("%-6d Graal %-70s %-45s %-50s %s", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature().toMethodDescriptor(),
                         entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") ");
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Thu May 28 17:44:05 2015 +0200
@@ -302,7 +302,7 @@
                 }
                 if (excludeMethodFilters != null && excludeMethodFilters.length > 0) {
                     String exclude = Arrays.asList(excludeMethodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", "));
-                    println("CompileTheWorld : Excluding all methods matching one of the follwing filters: " + exclude);
+                    println("CompileTheWorld : Excluding all methods matching one of the following filters: " + exclude);
                 }
                 println();
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerObject.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot;
-
-import java.io.*;
-
-import com.oracle.graal.api.meta.Kind.FormatWithToString;
-
-/**
- * Parent class for all HotSpot types that need to be serialized.
- */
-public abstract class CompilerObject implements Serializable, FormatWithToString {
-
-    private static final long serialVersionUID = -4551670987101214877L;
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Thu May 28 17:44:05 2015 +0200
@@ -64,8 +64,8 @@
 
     /**
      * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the
-     * {@linkplain HotSpotVMConfig#codeInstallerMarkIdExceptionHandlerEntry exception handler} in a
-     * compiled method.
+     * {@linkplain HotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception handler} in a compiled
+     * method.
      */
     public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledCode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledCode.java	Thu May 28 17:44:05 2015 +0200
@@ -36,24 +36,37 @@
 import com.oracle.graal.api.code.CompilationResult.JumpTable;
 import com.oracle.graal.api.code.CompilationResult.Mark;
 import com.oracle.graal.api.code.CompilationResult.Site;
+import com.oracle.graal.api.meta.Assumptions.Assumption;
+import com.oracle.graal.api.meta.*;
 
 /**
  * A {@link CompilationResult} with additional HotSpot-specific information required for installing
  * the code in HotSpot's code cache.
  */
-public abstract class HotSpotCompiledCode extends CompilerObject {
-
-    private static final long serialVersionUID = 7807321392203253218L;
-    public final CompilationResult comp;
+public abstract class HotSpotCompiledCode {
 
     public final Site[] sites;
     public final ExceptionHandler[] exceptionHandlers;
     public final Comment[] comments;
+    public final Assumption[] assumptions;
+
+    public final byte[] targetCode;
+    public final int targetCodeSize;
 
     public final byte[] dataSection;
     public final int dataSectionAlignment;
     public final DataPatch[] dataSectionPatches;
 
+    public final int totalFrameSize;
+    public final int customStackAreaOffset;
+
+    /**
+     * The list of the methods whose bytecodes were used as input to the compilation. If
+     * {@code null}, then the compilation did not record method dependencies. Otherwise, the first
+     * element of this array is the root method of the compilation.
+     */
+    public final ResolvedJavaMethod[] methods;
+
     public static class Comment {
 
         public final String text;
@@ -66,7 +79,6 @@
     }
 
     public HotSpotCompiledCode(CompilationResult compResult) {
-        this.comp = compResult;
         sites = getSortedSites(compResult);
         if (compResult.getExceptionHandlers().isEmpty()) {
             exceptionHandlers = null;
@@ -91,8 +103,12 @@
                 comments[i] = new Comment(annotation.position, text);
             }
         }
+        assumptions = compResult.getAssumptions();
         assert validateFrames();
 
+        targetCode = compResult.getTargetCode();
+        targetCodeSize = compResult.getTargetCodeSize();
+
         DataSection data = compResult.getDataSection();
         data.finalizeLayout();
         dataSection = new byte[data.getSectionSize()];
@@ -103,6 +119,11 @@
 
         dataSectionAlignment = data.getSectionAlignment();
         dataSectionPatches = patchBuilder.build().toArray(len -> new DataPatch[len]);
+
+        totalFrameSize = compResult.getTotalFrameSize();
+        customStackAreaOffset = compResult.getCustomStackAreaOffset();
+
+        methods = compResult.getMethods();
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Thu May 28 17:44:05 2015 +0200
@@ -32,7 +32,6 @@
  */
 public final class HotSpotCompiledNmethod extends HotSpotCompiledCode {
 
-    private static final long serialVersionUID = 1492412603674834024L;
     public final HotSpotResolvedJavaMethod method;
     public final int entryBCI;
     public final int id;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Thu May 28 17:44:05 2015 +0200
@@ -37,8 +37,6 @@
  */
 public final class HotSpotCompiledRuntimeStub extends HotSpotCompiledCode {
 
-    private static final long serialVersionUID = -4506206868419153274L;
-
     public final String stubName;
 
     public HotSpotCompiledRuntimeStub(Stub stub, CompilationResult compResult) {
@@ -55,7 +53,7 @@
 
         // Stubs cannot be recompiled so they cannot be compiled with
         // assumptions and there is no point in recording evol_method dependencies
-        assert compResult.getAssumptions().isEmpty() : "stubs should not use assumptions: " + this;
+        assert compResult.getAssumptions() == null : "stubs should not use assumptions: " + this;
         assert compResult.getMethods() == null : "stubs should not record evol_method dependencies: " + this;
 
         for (DataPatch data : compResult.getDataPatches()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,10 @@
 
     void emitPatchReturnAddress(ValueNode address);
 
+    default void emitJumpToExceptionHandler(ValueNode address) {
+        emitPatchReturnAddress(address);
+    }
+
     void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc);
 
     void emitPrefetchAllocate(ValueNode address, ValueNode distance);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Thu May 28 17:44:05 2015 +0200
@@ -25,13 +25,9 @@
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
 import static com.oracle.graal.options.OptionsLoader.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.options.*;
-import com.oracle.graal.phases.common.inlining.*;
 
 //JaCoCo Exclude
 
@@ -43,13 +39,7 @@
 
     private static final String GRAAL_OPTION_PREFIX = "-G:";
 
-    private static native boolean isCITimingEnabled();
-
     static {
-        if (isCITimingEnabled()) {
-            unconditionallyEnableTimerOrMetric(InliningUtil.class, "InlinedBytecodes");
-            unconditionallyEnableTimerOrMetric(CompilationTask.class, "CompilationTime");
-        }
         assert !Debug.Initialization.isDebugInitialized() : "The class " + Debug.class.getName() + " must not be initialized before the Graal runtime has been initialized. " +
                         "This can be fixed by placing a call to " + Graal.class.getName() + ".runtime() on the path that triggers initialization of " + Debug.class.getName();
         if (areDebugScopePatternsEnabled()) {
@@ -70,34 +60,5 @@
         OptionUtils.printFlags(options, GRAAL_OPTION_PREFIX);
     }
 
-    /**
-     * Sets the relevant system property such that a {@link DebugTimer} or {@link DebugMetric}
-     * associated with a field in a class will be unconditionally enabled when it is created.
-     * <p>
-     * This method verifies that the named field exists and is of an expected type. However, it does
-     * not verify that the timer or metric created has the same name of the field.
-     *
-     * @param c the class in which the field is declared
-     * @param name the name of the field
-     */
-    private static void unconditionallyEnableTimerOrMetric(Class<?> c, String name) {
-        try {
-            Field field = c.getDeclaredField(name);
-            String propertyName;
-            if (DebugTimer.class.isAssignableFrom(field.getType())) {
-                propertyName = Debug.ENABLE_TIMER_PROPERTY_NAME_PREFIX + name;
-            } else {
-                assert DebugMetric.class.isAssignableFrom(field.getType());
-                propertyName = Debug.ENABLE_METRIC_PROPERTY_NAME_PREFIX + name;
-            }
-            String previous = System.setProperty(propertyName, "true");
-            if (previous != null) {
-                System.err.println("Overrode value \"" + previous + "\" of system property \"" + propertyName + "\" with \"true\"");
-            }
-        } catch (Exception e) {
-            throw new GraalInternalError(e);
-        }
-    }
-
     public native Object getOptionValue(String optionName);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Thu May 28 17:44:05 2015 +0200
@@ -22,15 +22,13 @@
  */
 package com.oracle.graal.hotspot;
 
-import java.io.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
 
-public final class HotSpotReferenceMap extends ReferenceMap implements Serializable {
+public final class HotSpotReferenceMap extends ReferenceMap {
 
     static final int OOP64 = 0b1010;
     static final int OOP32 = 0b01;
@@ -104,9 +102,7 @@
      * map consists of 4 bit entries that represent 8 bytes of memory.
      *
      */
-    class HotSpotOopMap implements Cloneable, Serializable {
-
-        private static final long serialVersionUID = -4997600265320131213L;
+    class HotSpotOopMap implements Cloneable {
 
         /**
          * Each entry is 4 bits long and covers 8 bytes of memory.
@@ -282,8 +278,6 @@
         }
     }
 
-    private static final long serialVersionUID = -1052183095979496819L;
-
     /**
      * Contains 3 bits per scalar register, and n*3 bits per n-word vector register (e.g., on a
      * 64-bit system, a 256-bit vector register requires 12 reference map bits).
@@ -352,7 +346,7 @@
 
     private void set(HotSpotOopMap refMap, int index, LIRKind kind) {
         if (kind.isDerivedReference()) {
-            throw GraalInternalError.shouldNotReachHere("derived reference cannot be inserted in ReferenceMap");
+            throw new InternalError("derived reference cannot be inserted in ReferenceMap");
         }
 
         int bytesPerElement = bytesPerElement(kind);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -27,7 +27,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
@@ -63,10 +62,6 @@
                     return null;
                 }
             }
-        } else if (substituteClass == CRC32Substitutions.class) {
-            if (!config.useCRC32Intrinsics) {
-                return null;
-            }
         }
         return super.registerMethodSubstitution(cr, originalMethod, substituteMethod);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu May 28 17:44:05 2015 +0200
@@ -39,9 +39,7 @@
  *
  * All non-static, public fields in this class are so that they can be compiled as constants.
  */
-public class HotSpotVMConfig extends CompilerObject {
-
-    private static final long serialVersionUID = -4744897993263044184L;
+public class HotSpotVMConfig {
 
     /**
      * Determines if the current architecture is included in a given architecture set specification.
@@ -1511,26 +1509,49 @@
     @HotSpotVMConstant(name = "GraalEnv::cache_full") @Stable public int codeInstallResultCacheFull;
     @HotSpotVMConstant(name = "GraalEnv::code_too_large") @Stable public int codeInstallResultCodeTooLarge;
 
+    public String getCodeInstallResultDescription(int codeInstallResult) {
+        if (codeInstallResult == codeInstallResultOk) {
+            return "ok";
+        }
+        if (codeInstallResult == codeInstallResultDependenciesFailed) {
+            return "dependencies failed";
+        }
+        if (codeInstallResult == codeInstallResultDependenciesInvalid) {
+            return "dependencies invalid";
+        }
+        if (codeInstallResult == codeInstallResultCacheFull) {
+            return "code cache is full";
+        }
+        if (codeInstallResult == codeInstallResultCodeTooLarge) {
+            return "code is too large";
+        }
+        assert false : codeInstallResult;
+        return "unknown";
+    }
+
     @HotSpotVMConstant(name = "CompilerToVM::KLASS_TAG") @Stable public int compilerToVMKlassTag;
     @HotSpotVMConstant(name = "CompilerToVM::SYMBOL_TAG") @Stable public int compilerToVMSymbolTag;
 
-    @HotSpotVMConstant(name = "CodeInstaller::VERIFIED_ENTRY") @Stable public int codeInstallerMarkIdVerifiedEntry;
-    @HotSpotVMConstant(name = "CodeInstaller::UNVERIFIED_ENTRY") @Stable public int codeInstallerMarkIdUnverifiedEntry;
-    @HotSpotVMConstant(name = "CodeInstaller::OSR_ENTRY") @Stable public int codeInstallerMarkIdOsrEntry;
-    @HotSpotVMConstant(name = "CodeInstaller::EXCEPTION_HANDLER_ENTRY") @Stable public int codeInstallerMarkIdExceptionHandlerEntry;
-    @HotSpotVMConstant(name = "CodeInstaller::DEOPT_HANDLER_ENTRY") @Stable public int codeInstallerMarkIdDeoptHandlerEntry;
-    @HotSpotVMConstant(name = "CodeInstaller::INVOKEINTERFACE") @Stable public int codeInstallerMarkIdInvokeinterface;
-    @HotSpotVMConstant(name = "CodeInstaller::INVOKEVIRTUAL") @Stable public int codeInstallerMarkIdInvokevirtual;
-    @HotSpotVMConstant(name = "CodeInstaller::INVOKESTATIC") @Stable public int codeInstallerMarkIdInvokestatic;
-    @HotSpotVMConstant(name = "CodeInstaller::INVOKESPECIAL") @Stable public int codeInstallerMarkIdInvokespecial;
-    @HotSpotVMConstant(name = "CodeInstaller::INLINE_INVOKE") @Stable public int codeInstallerMarkIdInlineInvoke;
-    @HotSpotVMConstant(name = "CodeInstaller::POLL_NEAR") @Stable public int codeInstallerMarkIdPollNear;
-    @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_NEAR") @Stable public int codeInstallerMarkIdPollReturnNear;
-    @HotSpotVMConstant(name = "CodeInstaller::POLL_FAR") @Stable public int codeInstallerMarkIdPollFar;
-    @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_FAR") @Stable public int codeInstallerMarkIdPollReturnFar;
-    @HotSpotVMConstant(name = "CodeInstaller::CARD_TABLE_SHIFT") @Stable public int codeInstallerMarkIdCardTableShift;
-    @HotSpotVMConstant(name = "CodeInstaller::CARD_TABLE_ADDRESS") @Stable public int codeInstallerMarkIdCardTableAddress;
-    @HotSpotVMConstant(name = "CodeInstaller::INVOKE_INVALID") @Stable public int codeInstallerMarkIdInvokeInvalid;
+    // Checkstyle: stop
+    @HotSpotVMConstant(name = "CodeInstaller::VERIFIED_ENTRY") @Stable public int MARKID_VERIFIED_ENTRY;
+    @HotSpotVMConstant(name = "CodeInstaller::UNVERIFIED_ENTRY") @Stable public int MARKID_UNVERIFIED_ENTRY;
+    @HotSpotVMConstant(name = "CodeInstaller::OSR_ENTRY") @Stable public int MARKID_OSR_ENTRY;
+    @HotSpotVMConstant(name = "CodeInstaller::EXCEPTION_HANDLER_ENTRY") @Stable public int MARKID_EXCEPTION_HANDLER_ENTRY;
+    @HotSpotVMConstant(name = "CodeInstaller::DEOPT_HANDLER_ENTRY") @Stable public int MARKID_DEOPT_HANDLER_ENTRY;
+    @HotSpotVMConstant(name = "CodeInstaller::INVOKEINTERFACE") @Stable public int MARKID_INVOKEINTERFACE;
+    @HotSpotVMConstant(name = "CodeInstaller::INVOKEVIRTUAL") @Stable public int MARKID_INVOKEVIRTUAL;
+    @HotSpotVMConstant(name = "CodeInstaller::INVOKESTATIC") @Stable public int MARKID_INVOKESTATIC;
+    @HotSpotVMConstant(name = "CodeInstaller::INVOKESPECIAL") @Stable public int MARKID_INVOKESPECIAL;
+    @HotSpotVMConstant(name = "CodeInstaller::INLINE_INVOKE") @Stable public int MARKID_INLINE_INVOKE;
+    @HotSpotVMConstant(name = "CodeInstaller::POLL_NEAR") @Stable public int MARKID_POLL_NEAR;
+    @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_NEAR") @Stable public int MARKID_POLL_RETURN_NEAR;
+    @HotSpotVMConstant(name = "CodeInstaller::POLL_FAR") @Stable public int MARKID_POLL_FAR;
+    @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_FAR") @Stable public int MARKID_POLL_RETURN_FAR;
+    @HotSpotVMConstant(name = "CodeInstaller::CARD_TABLE_SHIFT") @Stable public int MARKID_CARD_TABLE_SHIFT;
+    @HotSpotVMConstant(name = "CodeInstaller::CARD_TABLE_ADDRESS") @Stable public int MARKID_CARD_TABLE_ADDRESS;
+    @HotSpotVMConstant(name = "CodeInstaller::INVOKE_INVALID") @Stable public int MARKID_INVOKE_INVALID;
+
+    // Checkstyle: resume
 
     public boolean check() {
         for (Field f : getClass().getDeclaredFields()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Thu May 28 17:44:05 2015 +0200
@@ -27,9 +27,9 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
+
 import com.oracle.graal.hotspotvmconfig.*;
 
 /**
@@ -176,66 +176,19 @@
 
     Object lookupAppendixInPool(long metaspaceConstantPool, int cpi);
 
-    public enum CodeInstallResult {
-        OK("ok"),
-        DEPENDENCIES_FAILED("dependencies failed"),
-        DEPENDENCIES_INVALID("dependencies invalid"),
-        CACHE_FULL("code cache is full"),
-        CODE_TOO_LARGE("code is too large");
-
-        private int value;
-        private String message;
-
-        private CodeInstallResult(String name) {
-            HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig();
-            switch (name) {
-                case "ok":
-                    this.value = config.codeInstallResultOk;
-                    break;
-                case "dependencies failed":
-                    this.value = config.codeInstallResultDependenciesFailed;
-                    break;
-                case "dependencies invalid":
-                    this.value = config.codeInstallResultDependenciesInvalid;
-                    break;
-                case "code cache is full":
-                    this.value = config.codeInstallResultCacheFull;
-                    break;
-                case "code is too large":
-                    this.value = config.codeInstallResultCodeTooLarge;
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere("unknown enum name " + name);
-            }
-            this.message = name;
-        }
-
-        /**
-         * Returns the enum object for the given value.
-         */
-        public static CodeInstallResult getEnum(int value) {
-            for (CodeInstallResult e : values()) {
-                if (e.value == value) {
-                    return e;
-                }
-            }
-            throw GraalInternalError.shouldNotReachHere("unknown enum value " + value);
-        }
-
-        @Override
-        public String toString() {
-            return message;
-        }
-    }
-
     /**
      * Installs the result of a compilation into the code cache.
      *
      * @param compiledCode the result of a compilation
      * @param code the details of the installed CodeBlob are written to this object
-     * @return the outcome of the installation as a {@link CodeInstallResult}.
+     * @return the outcome of the installation which will be one of
+     *         {@link HotSpotVMConfig#codeInstallResultOk},
+     *         {@link HotSpotVMConfig#codeInstallResultCacheFull},
+     *         {@link HotSpotVMConfig#codeInstallResultCodeTooLarge},
+     *         {@link HotSpotVMConfig#codeInstallResultDependenciesFailed} or
+     *         {@link HotSpotVMConfig#codeInstallResultDependenciesInvalid}.
      */
-    CodeInstallResult installCode(HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog);
+    int installCode(HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog);
 
     /**
      * Notifies the VM of statistics for a completed compilation.
@@ -294,8 +247,8 @@
     long readUnsafeKlassPointer(Object o);
 
     /**
-     * Reads an object pointer within a VM data structures. That is, any {@link HotSpotVMField}
-     * whose {@link HotSpotVMField#type() type} is {@code "oop"} (e.g.,
+     * Reads an object pointer within a VM data structure. That is, any {@link HotSpotVMField} whose
+     * {@link HotSpotVMField#type() type} is {@code "oop"} (e.g.,
      * {@code ArrayKlass::_component_mirror}, {@code Klass::_java_mirror},
      * {@code JavaThread::_threadObj}).
      *
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -45,12 +45,8 @@
         }
     }
 
-    private native int installCode0(HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog);
-
     @Override
-    public CodeInstallResult installCode(HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog) {
-        return CodeInstallResult.getEnum(installCode0(compiledCode, code, speculationLog));
-    }
+    public native int installCode(HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog);
 
     @Override
     public native long getMetaspaceMethod(Class<?> holder, int slot);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LineNumberTableImpl.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.debug;
-
-import com.oracle.graal.api.meta.*;
-
-public class LineNumberTableImpl implements LineNumberTable {
-
-    private final int[] lineNumbers;
-    private final int[] bci;
-
-    public LineNumberTableImpl(int[] lineNumbers, int[] bci) {
-        this.lineNumbers = lineNumbers;
-        this.bci = bci;
-    }
-
-    @Override
-    public int[] getLineNumberEntries() {
-        return lineNumbers;
-    }
-
-    @Override
-    public int[] getBciEntries() {
-        return bci;
-    }
-
-    @Override
-    public int getLineNumber(@SuppressWarnings("hiding") int bci) {
-        for (int i = 0; i < this.bci.length - 1; i++) {
-            if (this.bci[i] <= bci && bci < this.bci[i + 1]) {
-                return lineNumbers[i];
-            }
-        }
-        return lineNumbers[lineNumbers.length - 1];
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalImpl.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.debug;
-
-import com.oracle.graal.api.meta.*;
-
-public class LocalImpl implements Local {
-
-    private final String name;
-    private final int startBci;
-    private final int endBci;
-    private final int slot;
-    private final JavaType type;
-
-    public LocalImpl(String name, JavaType type, int startBci, int endBci, int slot) {
-        this.name = name;
-        this.startBci = startBci;
-        this.endBci = endBci;
-        this.slot = slot;
-        this.type = type;
-    }
-
-    @Override
-    public int getStartBCI() {
-        return startBci;
-    }
-
-    @Override
-    public int getEndBCI() {
-        return endBci;
-    }
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public JavaType getType() {
-        return type;
-    }
-
-    @Override
-    public int getSlot() {
-        return slot;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof LocalImpl)) {
-            return false;
-        }
-        LocalImpl that = (LocalImpl) obj;
-        return this.name.equals(that.name) && this.startBci == that.startBci && this.endBci == that.endBci && this.slot == that.slot && this.type.equals(that.type);
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return "LocalImpl<name=" + name + ", type=" + type + ", startBci=" + startBci + ", endBci=" + endBci + ", slot=" + slot + ">";
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalVariableTableImpl.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.debug;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-
-public class LocalVariableTableImpl implements LocalVariableTable {
-
-    private final Local[] locals;
-
-    public LocalVariableTableImpl(Local[] locals) {
-        this.locals = locals;
-    }
-
-    @Override
-    public Local getLocal(int slot, int bci) {
-        Local result = null;
-        for (Local local : locals) {
-            if (local.getSlot() == slot && local.getStartBCI() <= bci && local.getEndBCI() >= bci) {
-                if (result == null) {
-                    result = local;
-                } else {
-                    throw new IllegalStateException("Locals overlap!");
-                }
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public Local[] getLocals() {
-        return locals;
-    }
-
-    @Override
-    public Local[] getLocalsAt(int bci) {
-        List<Local> result = new ArrayList<>();
-        for (Local l : locals) {
-            if (l.getStartBCI() <= bci && bci <= l.getEndBCI()) {
-                result.add(l);
-            }
-        }
-        return result.toArray(new Local[result.size()]);
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,11 +41,12 @@
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.replacements.arraycopy.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
+import com.oracle.graal.nodes.memory.HeapAccess.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
@@ -68,6 +69,7 @@
     protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
     protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
     protected AssertionSnippets.Templates assertionSnippets;
+    protected ArrayCopySnippets.Templates arraycopySnippets;
 
     public DefaultHotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
                     TargetDescription target) {
@@ -89,6 +91,7 @@
         exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
         unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
         assertionSnippets = new AssertionSnippets.Templates(providers, target);
+        arraycopySnippets = new ArrayCopySnippets.Templates(providers, target);
         providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
     }
 
@@ -154,6 +157,12 @@
             if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
                 monitorSnippets.lower((MonitorExitNode) n, tool);
             }
+        } else if (n instanceof ArrayCopyNode) {
+            arraycopySnippets.lower((ArrayCopyNode) n, tool);
+        } else if (n instanceof ArrayCopySlowPathNode) {
+            ArrayCopySlowPathNode slowpath = (ArrayCopySlowPathNode) n;
+            // FrameState stateAfter = slowpath.stateAfter();
+            arraycopySnippets.lower(slowpath, tool);
         } else if (n instanceof G1PreWriteBarrier) {
             writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
         } else if (n instanceof G1PostWriteBarrier) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Thu May 28 17:44:05 2015 +0200
@@ -42,9 +42,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
-import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
-import com.oracle.graal.java.*;
-import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.printer.*;
 
 /**
@@ -53,65 +50,17 @@
 public class HotSpotCodeCacheProvider implements CodeCacheProvider {
 
     protected final HotSpotGraalRuntimeProvider runtime;
+    public final HotSpotVMConfig config;
     protected final TargetDescription target;
     protected final RegisterConfig regConfig;
 
-    public HotSpotCodeCacheProvider(HotSpotGraalRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) {
+    public HotSpotCodeCacheProvider(HotSpotGraalRuntimeProvider runtime, HotSpotVMConfig config, TargetDescription target, RegisterConfig regConfig) {
         this.runtime = runtime;
+        this.config = config;
         this.target = target;
         this.regConfig = regConfig;
     }
 
-    /**
-     * Constants used to mark special positions in code being installed into the code cache by Graal
-     * C++ code.
-     */
-    public enum MarkId {
-        VERIFIED_ENTRY(config().codeInstallerMarkIdVerifiedEntry),
-        UNVERIFIED_ENTRY(config().codeInstallerMarkIdUnverifiedEntry),
-        OSR_ENTRY(config().codeInstallerMarkIdOsrEntry),
-        EXCEPTION_HANDLER_ENTRY(config().codeInstallerMarkIdExceptionHandlerEntry),
-        DEOPT_HANDLER_ENTRY(config().codeInstallerMarkIdDeoptHandlerEntry),
-        INVOKEINTERFACE(config().codeInstallerMarkIdInvokeinterface),
-        INVOKEVIRTUAL(config().codeInstallerMarkIdInvokevirtual),
-        INVOKESTATIC(config().codeInstallerMarkIdInvokestatic),
-        INVOKESPECIAL(config().codeInstallerMarkIdInvokespecial),
-        INLINE_INVOKE(config().codeInstallerMarkIdInlineInvoke),
-        POLL_NEAR(config().codeInstallerMarkIdPollNear),
-        POLL_RETURN_NEAR(config().codeInstallerMarkIdPollReturnNear),
-        POLL_FAR(config().codeInstallerMarkIdPollFar),
-        POLL_RETURN_FAR(config().codeInstallerMarkIdPollReturnFar),
-        CARD_TABLE_SHIFT(config().codeInstallerMarkIdCardTableShift),
-        CARD_TABLE_ADDRESS(config().codeInstallerMarkIdCardTableAddress);
-
-        private final int value;
-
-        private MarkId(int value) {
-            this.value = value;
-        }
-
-        private static HotSpotVMConfig config() {
-            return HotSpotGraalRuntime.runtime().getConfig();
-        }
-
-        public static MarkId getEnum(int value) {
-            for (MarkId e : values()) {
-                if (e.value == value) {
-                    return e;
-                }
-            }
-            throw GraalInternalError.shouldNotReachHere("unknown enum value " + value);
-        }
-
-        /**
-         * Helper method to {@link CompilationResultBuilder#recordMark(Object) record a mark} with a
-         * {@link CompilationResultBuilder}.
-         */
-        public static void recordMark(CompilationResultBuilder crb, MarkId mark) {
-            crb.recordMark(mark.value);
-        }
-    }
-
     @Override
     public String disassemble(CompilationResult compResult, InstalledCode installedCode) {
         byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode();
@@ -144,7 +93,7 @@
                 hcf.addOperandComment(site.pcOffset, "{" + site.reference.toString() + "}");
             }
             for (Mark mark : compResult.getMarks()) {
-                hcf.addComment(mark.pcOffset, MarkId.getEnum((int) mark.id).toString());
+                hcf.addComment(mark.pcOffset, getMarkIdName((int) mark.id));
             }
         }
         String hcfEmbeddedString = hcf.toEmbeddedString();
@@ -181,6 +130,22 @@
         }
     }
 
+    private String getMarkIdName(int markId) {
+        Field[] fields = runtime.getConfig().getClass().getDeclaredFields();
+        for (Field f : fields) {
+            if (f.getName().startsWith("MARKID_")) {
+                f.setAccessible(true);
+                try {
+                    if (f.getInt(runtime.getConfig()) == markId) {
+                        return f.getName();
+                    }
+                } catch (Exception e) {
+                }
+            }
+        }
+        return String.valueOf(markId);
+    }
+
     /**
      * Decodes a call target to a mnemonic if possible.
      */
@@ -260,18 +225,19 @@
             installedCode = code;
         }
         HotSpotCompiledNmethod compiledCode = new HotSpotCompiledNmethod(hotspotMethod, compResult);
-        CodeInstallResult result = runtime.getCompilerToVM().installCode(compiledCode, installedCode, log);
-        if (result != CodeInstallResult.OK) {
+        int result = runtime.getCompilerToVM().installCode(compiledCode, installedCode, log);
+        if (result != config.codeInstallResultOk) {
             String msg = compiledCode.getInstallationFailureMessage();
+            String resultDesc = config.getCodeInstallResultDescription(result);
             if (msg != null) {
-                msg = String.format("Code installation failed: %s%n%s", result, msg);
+                msg = String.format("Code installation failed: %s%n%s", resultDesc, msg);
             } else {
-                msg = String.format("Code installation failed: %s", result);
+                msg = String.format("Code installation failed: %s", resultDesc);
             }
-            if (result == CodeInstallResult.DEPENDENCIES_INVALID) {
-                throw new AssertionError(result + " " + msg);
+            if (result == config.codeInstallResultDependenciesInvalid) {
+                throw new AssertionError(resultDesc + " " + msg);
             }
-            throw new BailoutException(result != CodeInstallResult.DEPENDENCIES_FAILED, msg);
+            throw new BailoutException(result != config.codeInstallResultDependenciesFailed, msg);
         }
         return logOrDump(installedCode, compResult);
     }
@@ -290,8 +256,8 @@
         HotSpotNmethod code = new HotSpotNmethod(javaMethod, compResult.getName(), false, true);
         HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(javaMethod, compResult);
         CompilerToVM vm = runtime.getCompilerToVM();
-        CodeInstallResult result = vm.installCode(compiled, code, null);
-        if (result != CodeInstallResult.OK) {
+        int result = vm.installCode(compiled, code, null);
+        if (result != runtime.getConfig().codeInstallResultOk) {
             return null;
         }
         return code;
@@ -361,10 +327,6 @@
         return null;
     }
 
-    public String disassemble(ResolvedJavaMethod method) {
-        return new BytecodeDisassembler().disassemble(method);
-    }
-
     public SpeculationLog createSpeculationLog() {
         return new HotSpotSpeculationLog();
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java	Thu May 28 17:44:05 2015 +0200
@@ -29,8 +29,6 @@
  */
 public final class HotSpotCompressedNullConstant extends AbstractValue implements JavaConstant, HotSpotConstant {
 
-    private static final long serialVersionUID = 8906209595800783961L;
-
     public static final JavaConstant COMPRESSED_NULL = new HotSpotCompressedNullConstant();
 
     private HotSpotCompressedNullConstant() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java	Thu May 28 17:44:05 2015 +0200
@@ -35,9 +35,7 @@
 /**
  * Implementation of {@link ConstantPool} for HotSpot.
  */
-public class HotSpotConstantPool extends CompilerObject implements ConstantPool, HotSpotProxified {
-
-    private static final long serialVersionUID = -5443206401485234850L;
+public class HotSpotConstantPool implements ConstantPool, HotSpotProxified {
 
     /**
      * Enum of all {@code JVM_CONSTANT} constants used in the VM. This includes the public and
@@ -115,13 +113,23 @@
         }
     }
 
+    private static class LookupTypeCacheElement {
+        int lastCpi = Integer.MIN_VALUE;
+        JavaType javaType;
+
+        public LookupTypeCacheElement(int lastCpi, JavaType javaType) {
+            super();
+            this.lastCpi = lastCpi;
+            this.javaType = javaType;
+        }
+    }
+
     /**
      * Reference to the C++ ConstantPool object.
      */
     private final long metaspaceConstantPool;
     private final Object[] cache;
-    private ResolvedJavaType lastType;
-    private int lastTypeCpi = Integer.MIN_VALUE;
+    private volatile LookupTypeCacheElement lastLookupType;
 
     public HotSpotConstantPool(long metaspaceConstantPool) {
         this.metaspaceConstantPool = metaspaceConstantPool;
@@ -489,22 +497,17 @@
 
     @Override
     public JavaType lookupType(int cpi, int opcode) {
-        if (cpi == this.lastTypeCpi) {
-            synchronized (this) {
-                if (cpi == this.lastTypeCpi) {
-                    return this.lastType;
-                }
+        final LookupTypeCacheElement elem = this.lastLookupType;
+        if (elem != null && elem.lastCpi == cpi) {
+            return elem.javaType;
+        } else {
+            final long metaspacePointer = runtime().getCompilerToVM().lookupKlassInPool(metaspaceConstantPool, cpi);
+            JavaType result = getJavaType(metaspacePointer);
+            if (result instanceof ResolvedJavaType) {
+                this.lastLookupType = new LookupTypeCacheElement(cpi, result);
             }
+            return result;
         }
-        final long metaspacePointer = runtime().getCompilerToVM().lookupKlassInPool(metaspaceConstantPool, cpi);
-        JavaType result = getJavaType(metaspacePointer);
-        if (result instanceof ResolvedJavaType) {
-            synchronized (this) {
-                this.lastType = (ResolvedJavaType) result;
-                this.lastTypeCpi = cpi;
-            }
-        }
-        return result;
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Thu May 28 17:44:05 2015 +0200
@@ -35,7 +35,6 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 
 /**
@@ -97,6 +96,40 @@
         return null;
     }
 
+    /**
+     * Try to convert {@code offset} into an an index into {@code array}.
+     *
+     * @return -1 if the offset isn't within the array or the computed index
+     */
+    private int indexForOffset(JavaConstant array, long offset) {
+        if (array.getKind() != Kind.Object || array.isNull()) {
+            return -1;
+        }
+        Class<?> componentType = ((HotSpotObjectConstantImpl) array).object().getClass().getComponentType();
+        Kind kind = runtime.getHostProviders().getMetaAccess().lookupJavaType(componentType).getKind();
+        int arraybase = runtime.getArrayBaseOffset(kind);
+        int scale = runtime.getArrayIndexScale(kind);
+        if (offset < arraybase) {
+            return -1;
+        }
+        long index = offset - arraybase;
+        if (index % scale != 0) {
+            return -1;
+        }
+        long result = index / scale;
+        if (result >= Integer.MAX_VALUE) {
+            return -1;
+        }
+        return (int) result;
+    }
+
+    public JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset) {
+        if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) {
+            return readConstantArrayElement(array, indexForOffset(array, offset));
+        }
+        return null;
+    }
+
     @Override
     public JavaConstant readArrayElement(JavaConstant array, int index) {
         if (array.getKind() != Kind.Object || array.isNull()) {
@@ -198,8 +231,7 @@
         assert !ImmutableCode.getValue() || isCalledForSnippets() || SnippetGraphUnderConstruction.get() != null || HotSpotLoadFieldPlugin.FieldReadEnabledInImmutableCode.get() == Boolean.TRUE : receiver;
         HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
 
-        if (receiver == null) {
-            assert hotspotField.isStatic();
+        if (hotspotField.isStatic()) {
             if (hotspotField.isFinal() || hotspotField.isStable()) {
                 ResolvedJavaType holder = hotspotField.getDeclaringClass();
                 if (holder.isInitialized() && !holder.getName().equals(SystemClassName) && isEmbeddable(hotspotField)) {
@@ -214,7 +246,6 @@
              * for non-static final fields, we must assume that they are only initialized if they
              * have a non-default value.
              */
-            assert !hotspotField.isStatic();
             Object object = receiver.isNull() ? null : ((HotSpotObjectConstantImpl) receiver).object();
 
             // Canonicalization may attempt to process an unsafe read before
@@ -260,18 +291,17 @@
 
     private JavaConstant readNonStableFieldValue(JavaField field, JavaConstant receiver) {
         HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
-        if (receiver == null) {
-            assert hotspotField.isStatic();
+        if (hotspotField.isStatic()) {
             HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass();
             if (holder.isInitialized()) {
                 return memoryAccess.readUnsafeConstant(hotspotField.getKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), hotspotField.offset());
             }
-            return null;
         } else {
-            assert !hotspotField.isStatic();
-            assert receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object());
-            return memoryAccess.readUnsafeConstant(hotspotField.getKind(), receiver, hotspotField.offset());
+            if (receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object())) {
+                return memoryAccess.readUnsafeConstant(hotspotField.getKind(), receiver, hotspotField.offset());
+            }
         }
+        return null;
     }
 
     public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) {
@@ -314,7 +344,7 @@
         ResolvedJavaMethod initMethod = null;
         try {
             Class<?> rjm = ResolvedJavaMethod.class;
-            makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, FrameStateProcessing.class));
+            makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm));
             initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class));
         } catch (NoSuchMethodException | SecurityException e) {
             throw new GraalInternalError(e);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
 
 import java.lang.invoke.*;
+import java.util.zip.*;
 
 import sun.reflect.*;
 
@@ -42,8 +43,8 @@
 import com.oracle.graal.hotspot.replacements.arraycopy.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.HeapAccess.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.options.*;
@@ -65,7 +66,7 @@
      */
     public static Plugins create(HotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection,
                     SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements) {
-        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess, constantReflection.getMethodHandleAccess());
+        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
 
         Plugins plugins = new Plugins(invocationPlugins);
         NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider);
@@ -76,7 +77,8 @@
         plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes));
         plugins.setTypeCheckPlugin(wordOperationPlugin);
         plugins.setInlineInvokePlugin(new DefaultInlineInvokePlugin(replacements));
-        plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification, wordOperationPlugin));
+        plugins.setGenericInvocationPlugin(new MethodHandleInvocationPlugin(constantReflection.getMethodHandleAccess(), new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification,
+                        wordOperationPlugin)));
 
         registerObjectPlugins(invocationPlugins);
         registerClassPlugins(plugins);
@@ -86,6 +88,7 @@
         registerReflectionPlugins(invocationPlugins);
         registerStableOptionPlugins(invocationPlugins);
         registerAESPlugins(invocationPlugins, config);
+        registerCRC32Plugins(invocationPlugins, config);
         StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, invocationPlugins, !config.useHeapProfiler);
 
         return plugins;
@@ -187,7 +190,7 @@
         });
         r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
-                b.add(new ArrayCopyNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), src, srcPos, dst, dstPos, length));
+                b.add(new ArrayCopyNode(b.bci(), src, srcPos, dst, dstPos, length));
                 return true;
             }
 
@@ -248,4 +251,17 @@
             }
         }
     }
+
+    private static void registerCRC32Plugins(InvocationPlugins plugins, HotSpotVMConfig config) {
+        if (config.useCRC32Intrinsics) {
+            assert config.aescryptEncryptBlockStub != 0L;
+            assert config.aescryptDecryptBlockStub != 0L;
+            assert config.cipherBlockChainingEncryptAESCryptStub != 0L;
+            assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
+            Registration r = new Registration(plugins, CRC32.class);
+            r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class);
+            r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
+            r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Thu May 28 17:44:05 2015 +0200
@@ -71,11 +71,16 @@
         return checkcastArraycopyDescriptors[uninit ? 1 : 0];
     }
 
-    public static ForeignCallDescriptor lookupArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint, boolean uninit) {
+    public static ForeignCallDescriptor lookupArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny) {
         if (uninit) {
             assert kind == Kind.Object;
+            assert !killAny : "unsupported";
             return uninitObjectArraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0];
         }
+        if (killAny) {
+            assert kind == Kind.Object;
+            return objectArraycopyDescriptorsKillAny[aligned ? 1 : 0][disjoint ? 1 : 0];
+        }
         return arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].get(kind);
     }
 
@@ -83,6 +88,7 @@
 
     private static final ForeignCallDescriptor[][] uninitObjectArraycopyDescriptors = new ForeignCallDescriptor[2][2];
     private static final ForeignCallDescriptor[] checkcastArraycopyDescriptors = new ForeignCallDescriptor[2];
+    private static ForeignCallDescriptor[][] objectArraycopyDescriptorsKillAny = new ForeignCallDescriptor[2][2];
 
     static {
         // Populate the EnumMap instances
@@ -93,13 +99,10 @@
         }
     }
 
-    private void registerArraycopyDescriptor(Map<Long, ForeignCallDescriptor> descMap, Kind kind, boolean aligned, boolean disjoint, boolean uninit, long routine) {
+    private void registerArraycopyDescriptor(Map<Long, ForeignCallDescriptor> descMap, Kind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny, long routine) {
         ForeignCallDescriptor desc = descMap.get(routine);
         if (desc == null) {
-            String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + (uninit ? "Uninit" : "") + "Arraycopy";
-            desc = new ForeignCallDescriptor(name, void.class, Word.class, Word.class, Word.class);
-            LocationIdentity killed = NamedLocationIdentity.getArrayLocation(kind);
-            registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+            desc = buildDescriptor(kind, aligned, disjoint, uninit, killAny, routine);
             descMap.put(routine, desc);
         }
         if (uninit) {
@@ -110,6 +113,15 @@
         }
     }
 
+    private ForeignCallDescriptor buildDescriptor(Kind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny, long routine) {
+        assert !killAny || kind == Kind.Object;
+        String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + (uninit ? "Uninit" : "") + "Arraycopy" + (killAny ? "KillAny" : "");
+        ForeignCallDescriptor desc = new ForeignCallDescriptor(name, void.class, Word.class, Word.class, Word.class);
+        LocationIdentity killed = killAny ? LocationIdentity.any() : NamedLocationIdentity.getArrayLocation(kind);
+        registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+        return desc;
+    }
+
     private void registerCheckcastArraycopyDescriptor(boolean uninit, long routine) {
         String name = "Object" + (uninit ? "Uninit" : "") + "Checkcast";
         // Input:
@@ -125,15 +137,28 @@
         checkcastArraycopyDescriptors[uninit ? 1 : 0] = desc;
     }
 
-    private void registerArrayCopy(Map<Long, ForeignCallDescriptor> descMap, Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) {
-        registerArrayCopy(descMap, kind, routine, alignedRoutine, disjointRoutine, alignedDisjointRoutine, false);
+    private void registerArrayCopy(Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) {
+        registerArrayCopy(kind, routine, alignedRoutine, disjointRoutine, alignedDisjointRoutine, false);
     }
 
-    private void registerArrayCopy(Map<Long, ForeignCallDescriptor> descMap, Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine, boolean uninit) {
-        registerArraycopyDescriptor(descMap, kind, false, false, uninit, routine);
-        registerArraycopyDescriptor(descMap, kind, true, false, uninit, alignedRoutine);
-        registerArraycopyDescriptor(descMap, kind, false, true, uninit, disjointRoutine);
-        registerArraycopyDescriptor(descMap, kind, true, true, uninit, alignedDisjointRoutine);
+    private void registerArrayCopy(Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine, boolean uninit) {
+        /*
+         * Sometimes the same function is used for multiple cases so share them when that's the case
+         * but only within the same Kind. For instance short and char are the same copy routines but
+         * they kill different memory so they still have to be distinct.
+         */
+        Map<Long, ForeignCallDescriptor> descMap = new HashMap<>();
+        registerArraycopyDescriptor(descMap, kind, false, false, uninit, false, routine);
+        registerArraycopyDescriptor(descMap, kind, true, false, uninit, false, alignedRoutine);
+        registerArraycopyDescriptor(descMap, kind, false, true, uninit, false, disjointRoutine);
+        registerArraycopyDescriptor(descMap, kind, true, true, uninit, false, alignedDisjointRoutine);
+
+        if (kind == Kind.Object && !uninit) {
+            objectArraycopyDescriptorsKillAny[0][0] = buildDescriptor(kind, false, false, uninit, true, routine);
+            objectArraycopyDescriptorsKillAny[1][0] = buildDescriptor(kind, true, false, uninit, true, alignedRoutine);
+            objectArraycopyDescriptorsKillAny[0][1] = buildDescriptor(kind, false, true, uninit, true, disjointRoutine);
+            objectArraycopyDescriptorsKillAny[1][1] = buildDescriptor(kind, true, true, uninit, true, alignedDisjointRoutine);
+        }
     }
 
     public void initialize(HotSpotProviders providers, HotSpotVMConfig c) {
@@ -205,19 +230,16 @@
 
         linkForeignCall(providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any());
 
-        // sometimes the same function is used for different kinds of arraycopy so check for
-        // duplicates using a map.
-        Map<Long, ForeignCallDescriptor> descMap = new HashMap<>();
-        registerArrayCopy(descMap, Kind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
-        registerArrayCopy(descMap, Kind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
-        registerArrayCopy(descMap, Kind.Char, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy);
-        registerArrayCopy(descMap, Kind.Short, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy);
-        registerArrayCopy(descMap, Kind.Int, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy);
-        registerArrayCopy(descMap, Kind.Float, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy);
-        registerArrayCopy(descMap, Kind.Long, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
-        registerArrayCopy(descMap, Kind.Double, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
-        registerArrayCopy(descMap, Kind.Object, c.oopArraycopy, c.oopAlignedArraycopy, c.oopDisjointArraycopy, c.oopAlignedDisjointArraycopy);
-        registerArrayCopy(descMap, Kind.Object, c.oopArraycopyUninit, c.oopAlignedArraycopyUninit, c.oopDisjointArraycopyUninit, c.oopAlignedDisjointArraycopyUninit, true);
+        registerArrayCopy(Kind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Char, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Short, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Int, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Float, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Long, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Double, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Object, c.oopArraycopy, c.oopAlignedArraycopy, c.oopDisjointArraycopy, c.oopAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Object, c.oopArraycopyUninit, c.oopAlignedArraycopyUninit, c.oopDisjointArraycopyUninit, c.oopAlignedDisjointArraycopyUninit, true);
 
         registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit);
         registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Thu May 28 17:44:05 2015 +0200
@@ -22,23 +22,14 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.hotspot.meta.HotSpotMethodHandleAccessProvider.*;
-
-import java.lang.invoke.*;
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.MethodIdMap.Receiver;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.phases.*;
-import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin;
 import com.oracle.graal.replacements.nodes.*;
@@ -48,12 +39,10 @@
  */
 final class HotSpotInvocationPlugins extends InvocationPlugins {
     final HotSpotVMConfig config;
-    final MethodHandleAccessProvider methodHandleAccess;
 
-    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess, MethodHandleAccessProvider methodHandleAccess) {
+    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess) {
         super(metaAccess);
         this.config = config;
-        this.methodHandleAccess = methodHandleAccess;
     }
 
     @Override
@@ -74,68 +63,6 @@
         super.register(plugin, declaringClass, name, argumentTypes);
     }
 
-    private ResolvedJavaType methodHandleClass;
-    private final Map<IntrinsicMethod, InvocationPlugin> methodHandlePlugins = new EnumMap<>(IntrinsicMethod.class);
-
-    @Override
-    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
-        if (methodHandleClass == null) {
-            methodHandleClass = plugins.getMetaAccess().lookupJavaType(MethodHandle.class);
-        }
-        if (method.getDeclaringClass().equals(methodHandleClass)) {
-            HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
-            int intrinsicId = hsMethod.intrinsicId();
-            if (intrinsicId != 0) {
-                /*
-                 * The methods of MethodHandle that need substitution are signature-polymorphic,
-                 * i.e., the VM replicates them for every signature that they are actually used for.
-                 */
-                IntrinsicMethod intrinsicMethod = getMethodHandleIntrinsic(intrinsicId);
-                if (intrinsicMethod != null) {
-                    InvocationPlugin plugin = methodHandlePlugins.get(intrinsicMethod);
-                    if (plugin == null) {
-                        plugin = new InvocationPlugin() {
-                            public boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode... argsIncludingReceiver) {
-                                InvokeKind invokeKind = b.getInvokeKind();
-                                if (invokeKind != InvokeKind.Static) {
-                                    receiver.get();
-                                }
-                                JavaType invokeReturnType = b.getInvokeReturnType();
-                                InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, targetMethod,
-                                                b.bci(), invokeReturnType, argsIncludingReceiver);
-                                if (invoke == null) {
-                                    MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, targetMethod, b.bci(), invokeReturnType, argsIncludingReceiver);
-                                    if (invokeReturnType.getKind() == Kind.Void) {
-                                        b.add(methodHandleNode);
-                                    } else {
-                                        b.addPush(methodHandleNode);
-                                    }
-                                } else {
-                                    CallTargetNode callTarget = invoke.callTarget();
-                                    NodeInputList<ValueNode> argumentsList = callTarget.arguments();
-                                    ValueNode[] args = argumentsList.toArray(new ValueNode[argumentsList.size()]);
-                                    for (ValueNode arg : args) {
-                                        b.recursiveAppend(arg);
-                                    }
-                                    b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), args);
-                                }
-                                return true;
-                            }
-
-                            public boolean isSignaturePolymorphic() {
-                                return true;
-                            }
-                        };
-                        methodHandlePlugins.put(intrinsicMethod, plugin);
-                    }
-                    return plugin;
-                }
-            }
-
-        }
-        return super.lookupInvocation(method);
-    }
-
     @Override
     public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
         for (Node node : newNodes) {
@@ -154,7 +81,10 @@
                         if (isClass(c)) {
                             // This will be handled later by LoadJavaMirrorWithKlassPhase
                         } else {
-                            throw new AssertionError("illegal constant node in AOT: " + node);
+                            // Tolerate uses in unused FrameStates
+                            if (node.usages().filter((n) -> !(n instanceof FrameState) || n.hasUsages()).isNotEmpty()) {
+                                throw new AssertionError("illegal constant node in AOT: " + node);
+                            }
                         }
                     }
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotJavaType.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotJavaType.java	Thu May 28 17:44:05 2015 +0200
@@ -23,14 +23,11 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.*;
 
 /**
  * Common base class for all HotSpot {@link JavaType} implementations.
  */
-public abstract class HotSpotJavaType extends CompilerObject implements JavaType {
-
-    private static final long serialVersionUID = -4252886265301910771L;
+public abstract class HotSpotJavaType implements JavaType {
 
     private final String name;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java	Thu May 28 17:44:05 2015 +0200
@@ -25,7 +25,6 @@
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.nodes.*;
 
@@ -41,7 +40,7 @@
     static final ThreadLocal<Boolean> FieldReadEnabledInImmutableCode = new ThreadLocal<>();
 
     public boolean apply(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) {
-        if (!ImmutableCode.getValue() || b.parsingReplacement()) {
+        if (!ImmutableCode.getValue() || b.parsingIntrinsic()) {
             if (receiver.isConstant()) {
                 JavaConstant asJavaConstant = receiver.asJavaConstant();
                 return tryReadField(b, field, asJavaConstant);
@@ -64,19 +63,7 @@
     }
 
     public boolean apply(GraphBuilderContext b, ResolvedJavaField staticField) {
-        if (!ImmutableCode.getValue() || b.parsingReplacement()) {
-            // Javac does not allow use of "$assertionsDisabled" for a field name but
-            // Eclipse does in which case a suffix is added to the generated field.
-            if (b.parsingReplacement() && staticField.isSynthetic() && staticField.getName().startsWith("$assertionsDisabled")) {
-                // For methods called indirectly from intrinsics, we (silently) disable
-                // assertions so that the parser won't see calls to the AssertionError
-                // constructor (all Invokes must be removed from intrinsics - see
-                // HotSpotInlineInvokePlugin.notifyOfNoninlinedInvoke). Direct use of
-                // assertions in intrinsics is forbidden.
-                assert b.getMethod().getAnnotation(MethodSubstitution.class) == null : "cannot use assertions in " + b.getMethod().format("%H.%n(%p)");
-                b.addPush(ConstantNode.forBoolean(true));
-                return true;
-            }
+        if (!ImmutableCode.getValue() || b.parsingIntrinsic()) {
             return tryReadField(b, staticField, null);
         }
         return false;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java	Thu May 28 17:44:05 2015 +0200
@@ -40,7 +40,7 @@
     }
 
     public boolean apply(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) {
-        if (b.parsingReplacement()) {
+        if (b.parsingIntrinsic()) {
             ResolvedJavaType arrayType = StampTool.typeOrNull(array);
             /*
              * There are cases where the array does not have a known type yet, i.e., the type is
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstantImpl.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstantImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -30,8 +30,6 @@
 
 public final class HotSpotMetaspaceConstantImpl extends PrimitiveConstant implements HotSpotMetaspaceConstant, VMConstant, HotSpotProxified {
 
-    private static final long serialVersionUID = 1003463314013122983L;
-
     static HotSpotMetaspaceConstantImpl forMetaspaceObject(Kind kind, long primitive, Object metaspaceObject, boolean compressed) {
         return new HotSpotMetaspaceConstantImpl(kind, primitive, metaspaceObject, compressed);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethod.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethod.java	Thu May 28 17:44:05 2015 +0200
@@ -28,11 +28,9 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.*;
 
-public abstract class HotSpotMethod extends CompilerObject implements JavaMethod, Formattable {
+public abstract class HotSpotMethod implements JavaMethod, Formattable {
 
-    private static final long serialVersionUID = 7167491397941960839L;
     protected String name;
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Thu May 28 17:44:05 2015 +0200
@@ -39,9 +39,7 @@
 /**
  * Access to a HotSpot MethodData structure (defined in methodData.hpp).
  */
-public final class HotSpotMethodData extends CompilerObject {
-
-    private static final long serialVersionUID = -8873133496591225071L;
+public final class HotSpotMethodData {
 
     private static final HotSpotVMConfig config = runtime().getConfig();
     private static final HotSpotMethodDataAccessor NO_DATA_NO_EXCEPTION_ACCESSOR = new NoMethodData(TriState.FALSE);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodUnresolved.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodUnresolved.java	Thu May 28 17:44:05 2015 +0200
@@ -29,7 +29,6 @@
  */
 public final class HotSpotMethodUnresolved extends HotSpotMethod {
 
-    private static final long serialVersionUID = 5610263481791970079L;
     private final Signature signature;
     protected JavaType holder;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -37,8 +37,6 @@
  */
 public final class HotSpotObjectConstantImpl extends AbstractValue implements HotSpotObjectConstant, HotSpotProxified {
 
-    private static final long serialVersionUID = 3592151693708093496L;
-
     static JavaConstant forObject(Object object) {
         return forObject(object, false);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotParameterPlugin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotParameterPlugin.java	Thu May 28 17:44:05 2015 +0200
@@ -38,7 +38,7 @@
     }
 
     public FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp) {
-        if (b.parsingReplacement()) {
+        if (b.parsingIntrinsic()) {
             ResolvedJavaType type = StampTool.typeOrNull(stamp);
             if (wordTypes.isWord(type)) {
                 return new ParameterNode(index, wordTypes.getWordStamp(type));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java	Thu May 28 17:44:05 2015 +0200
@@ -27,9 +27,8 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 
-public final class HotSpotProfilingInfo extends CompilerObject implements ProfilingInfo, HotSpotProxified {
+public final class HotSpotProfilingInfo implements ProfilingInfo, HotSpotProxified {
 
-    private static final long serialVersionUID = -8307682725047864875L;
     private static final DebugMetric metricInsufficentSpace = Debug.metric("InsufficientSpaceForProfilingData");
 
     private final HotSpotMethodData methodData;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -36,9 +36,8 @@
 /**
  * Represents a field in a HotSpot type.
  */
-public class HotSpotResolvedJavaFieldImpl extends CompilerObject implements HotSpotResolvedJavaField, HotSpotProxified {
+public class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotProxified {
 
-    private static final long serialVersionUID = 7692985878836955683L;
     private final HotSpotResolvedObjectTypeImpl holder;
     private final String name;
     private JavaType type;
@@ -54,11 +53,15 @@
         HotSpotResolvedJavaField inner;
 
         public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) {
-            super(false);
             this.inner = inner;
         }
 
         @Override
+        public boolean isImmutable() {
+            return false;
+        }
+
+        @Override
         public boolean equals(Object obj) {
             if (this == obj) {
                 return true;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -36,7 +36,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -44,8 +43,6 @@
  */
 public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified, MethodIdHolder {
 
-    private static final long serialVersionUID = -5486975070147586588L;
-
     /**
      * Reference to metaspace Method object.
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java	Thu May 28 17:44:05 2015 +0200
@@ -28,8 +28,6 @@
 
 public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType {
 
-    private static final long serialVersionUID = -6410840212023428347L;
-
     /**
      * Gets the Graal mirror for a {@link Class} object.
      *
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectTypeImpl.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectTypeImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -42,8 +42,6 @@
  */
 public final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, HotSpotProxified {
 
-    private static final long serialVersionUID = 3481514353553840471L;
-
     /**
      * The Java class this type represents.
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java	Thu May 28 17:44:05 2015 +0200
@@ -38,7 +38,6 @@
  */
 public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType implements HotSpotProxified {
 
-    private static final long serialVersionUID = -6208552348908071473L;
     private final Kind kind;
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Thu May 28 17:44:05 2015 +0200
@@ -31,9 +31,8 @@
 /**
  * Represents a method signature.
  */
-public class HotSpotSignature extends CompilerObject implements Signature {
+public class HotSpotSignature implements Signature {
 
-    private static final long serialVersionUID = -2890917956072366116L;
     private final List<String> parameters = new ArrayList<>();
     private final String returnType;
     private final String originalString;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Thu May 28 17:44:05 2015 +0200
@@ -119,7 +119,7 @@
      * for equality.
      */
     private boolean appendGraphEncoderTest(PhaseSuite<HighTierContext> suite) {
-        suite.appendPhase(new BasePhase<HighTierContext>() {
+        suite.appendPhase(new BasePhase<HighTierContext>("VerifyEncodingDecoding") {
             @Override
             protected void run(StructuredGraph graph, HighTierContext context) {
                 EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, runtime.getTarget().arch);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java	Thu May 28 17:44:05 2015 +0200
@@ -30,7 +30,6 @@
  */
 public class HotSpotUnresolvedJavaType extends HotSpotJavaType {
 
-    private static final long serialVersionUID = -2320936267633521314L;
     private final HotSpotGraalRuntimeProvider runtime;
 
     public HotSpotUnresolvedJavaType(String name, HotSpotGraalRuntimeProvider runtime) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,9 +35,10 @@
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
+import com.oracle.graal.nodes.memory.HeapAccess.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.word.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,8 +28,8 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,8 +27,8 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Thu May 28 17:44:05 2015 +0200
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Jumps to the exception handler specified by {@link #address}. This node is specific for the
+ * {@link ExceptionHandlerStub} and should not be used elswhere.
+ */
+@NodeInfo
+public final class JumpToExceptionHandlerNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<JumpToExceptionHandlerNode> TYPE = NodeClass.create(JumpToExceptionHandlerNode.class);
+    @Input ValueNode address;
+
+    public JumpToExceptionHandlerNode(ValueNode address) {
+        super(TYPE, StampFactory.forVoid());
+        this.address = address;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        ((HotSpotNodeLIRBuilder) gen).emitJumpToExceptionHandler(address);
+    }
+
+    @NodeIntrinsic
+    public static native void jumpToExceptionHandler(Word address);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ResolvedMethodHandleCallTargetNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import static sun.misc.Version.*;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * A call target that replaces itself in the graph when being lowered by restoring the original
- * {@link MethodHandle} invocation target. Prior to
- * https://bugs.openjdk.java.net/browse/JDK-8072008, this is required for when a
- * {@link MethodHandle} call is resolved to a constant target but the target was not inlined. In
- * that case, the original invocation must be restored with all of its original arguments. Why?
- * HotSpot linkage for {@link MethodHandle} intrinsics (see
- * {@code MethodHandles::generate_method_handle_dispatch}) expects certain implicit arguments to be
- * on the stack such as the MemberName suffix argument for a call to one of the MethodHandle.linkTo*
- * methods. An {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle}
- * invocation drops these arguments which means the interpreter won't find them.
- */
-@NodeInfo
-public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable {
-
-    public static final NodeClass<ResolvedMethodHandleCallTargetNode> TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class);
-
-    /**
-     * Creates a call target for an invocation on a direct target derived by resolving a constant
-     * {@link MethodHandle}.
-     */
-    public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
-                    ValueNode[] originalArguments, JavaType originalReturnType) {
-        if (jdkMajorVersion() >= 1 && jdkMinorVersion() >= 8 && jdkMicroVersion() >= 0 && jdkUpdateVersion() >= 60) {
-            // https://bugs.openjdk.java.net/browse/JDK-8072008 is targeted for 8u60
-            return new MethodCallTargetNode(invokeKind, targetMethod, arguments, returnType);
-        }
-        return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnType, originalTargetMethod, originalArguments, originalReturnType);
-    }
-
-    protected final ResolvedJavaMethod originalTargetMethod;
-    protected final JavaType originalReturnType;
-    @Input NodeInputList<ValueNode> originalArguments;
-
-    protected ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
-                    ValueNode[] originalArguments, JavaType originalReturnType) {
-        super(TYPE, invokeKind, targetMethod, arguments, returnType);
-        this.originalTargetMethod = originalTargetMethod;
-        this.originalReturnType = originalReturnType;
-        this.originalArguments = new NodeInputList<>(this, originalArguments);
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
-        MethodCallTargetNode replacement = graph().add(
-                        new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnType));
-
-        // Replace myself...
-        this.replaceAndDelete(replacement);
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        throw GraalInternalError.shouldNotReachHere("should have replaced itself");
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Thu May 28 17:44:05 2015 +0200
@@ -29,7 +29,7 @@
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/KlassPointerStamp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/KlassPointerStamp.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,6 +58,11 @@
     }
 
     @Override
+    protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) {
+        return new KlassPointerStamp(newNonNull, newAlwaysNull, encoding);
+    }
+
+    @Override
     public boolean isCompatible(Stamp otherStamp) {
         if (this == otherStamp) {
             return true;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MetaspacePointerStamp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MetaspacePointerStamp.java	Thu May 28 17:44:05 2015 +0200
@@ -39,28 +39,6 @@
     }
 
     @Override
-    public Stamp meet(Stamp other) {
-        assert isCompatible(other);
-        return this;
-    }
-
-    @Override
-    public Stamp improveWith(Stamp other) {
-        return this;
-    }
-
-    @Override
-    public Stamp join(Stamp other) {
-        assert isCompatible(other);
-        return this;
-    }
-
-    @Override
-    public Stamp unrestricted() {
-        return this;
-    }
-
-    @Override
     public Stamp empty() {
         // there is no empty pointer stamp
         return this;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MethodPointerStamp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MethodPointerStamp.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,6 +47,18 @@
     }
 
     @Override
+    protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) {
+        if (newNonNull) {
+            assert !newAlwaysNull;
+            return METHOD_NON_NULL;
+        } else if (newAlwaysNull) {
+            return METHOD_ALWAYS_NULL;
+        } else {
+            return METHOD;
+        }
+    }
+
+    @Override
     public boolean isCompatible(Stamp otherStamp) {
         if (this == otherStamp) {
             return true;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -35,6 +35,7 @@
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,11 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
+import com.oracle.graal.nodes.memory.HeapAccess.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,9 +32,10 @@
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
+import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java	Thu May 28 17:44:05 2015 +0200
@@ -31,7 +31,6 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.word.*;
@@ -39,25 +38,8 @@
 /**
  * Substitutions for {@link CRC32}.
  */
-@ClassSubstitution(value = CRC32.class, defaultGuard = CRC32Substitutions.Guard.class)
 public class CRC32Substitutions {
 
-    public static class Guard implements SubstitutionGuard {
-
-        @SuppressWarnings("unused") private HotSpotVMConfig config;
-
-        public Guard(HotSpotVMConfig config) {
-            this.config = config;
-        }
-
-        public boolean execute() {
-            /*
-             * Disabled until MethodSubstitutions are compiled like snipppets.
-             */
-            return false; // return config.useCRC32Intrinsics;
-        }
-    }
-
     /**
      * Gets the address of {@code StubRoutines::x86::_crc_table} in {@code stubRoutines_x86.hpp}.
      */
@@ -66,7 +48,6 @@
         return runtime().getConfig().crcTableAddress;
     }
 
-    @MethodSubstitution(isStatic = true)
     static int update(int crc, int b) {
         int c = ~crc;
         int index = (b ^ c) & 0xFF;
@@ -76,13 +57,11 @@
         return ~result;
     }
 
-    @MethodSubstitution(isStatic = true)
     static int updateBytes(int crc, byte[] buf, int off, int len) {
         Word bufAddr = Word.unsigned(GetObjectAddressNode.get(buf) + arrayBaseOffset(Kind.Byte) + off);
         return updateBytes(UPDATE_BYTES_CRC32, crc, bufAddr, len);
     }
 
-    @MethodSubstitution(isStatic = true, optional = true)
     static int updateByteBuffer(int crc, long addr, int off, int len) {
         Word bufAddr = Word.unsigned(addr).add(off);
         return updateBytes(UPDATE_BYTES_CRC32, crc, bufAddr, len);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -75,7 +76,7 @@
             }
             if (clazz instanceof GetClassNode) {
                 GetClassNode getClass = (GetClassNode) clazz;
-                return new LoadHubNode(KlassPointerStamp.klass(), getClass.getObject(), null);
+                return new LoadHubNode(KlassPointerStamp.klassNonNull(), getClass.getObject(), null);
             }
             if (clazz instanceof HubGetClassNode) {
                 // replace _klass._java_mirror._klass -> _klass
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java	Thu May 28 17:44:05 2015 +0200
@@ -48,6 +48,7 @@
     public static boolean isInterface(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
         if (klass.isNull()) {
+            // Class for primitive type
             return false;
         } else {
             int accessFlags = klass.readInt(klassAccessFlagsOffset(), KLASS_ACCESS_FLAGS_LOCATION);
@@ -58,6 +59,7 @@
     public static boolean isArray(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
         if (klass.isNull()) {
+            // Class for primitive type
             return false;
         } else {
             return klassIsArray(klass);
@@ -85,6 +87,8 @@
                     }
                 }
             }
+        } else {
+            // Class for primitive type
         }
         return null;
     }
@@ -99,6 +103,8 @@
             if (klassIsArray(klass)) {
                 return PiNode.asNonNullClass(klass.readObject(arrayKlassComponentMirrorOffset(), ARRAY_KLASS_COMPONENT_MIRROR));
             }
+        } else {
+            // Class for primitive type
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Thu May 28 17:44:05 2015 +0200
@@ -825,6 +825,11 @@
 
     public static final LocationIdentity OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION = NamedLocationIdentity.immutable("ObjArrayKlass::_element_klass");
 
+    @Fold
+    public static int arrayClassElementOffset() {
+        return config().arrayClassElementOffset;
+    }
+
     public static final LocationIdentity PRIMARY_SUPERS_LOCATION = NamedLocationIdentity.immutable("PrimarySupers");
 
     public static final LocationIdentity METASPACE_ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("MetaspaceArrayLength");
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Thu May 28 17:44:05 2015 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import java.util.zip.*;
-
 import sun.misc.*;
 import sun.reflect.*;
 
@@ -43,7 +41,6 @@
         replacements.registerSubstitutions(System.class, SystemSubstitutions.class);
         replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class);
         replacements.registerSubstitutions(Unsafe.class, UnsafeSubstitutions.class);
-        replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class);
         replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class);
         replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,272 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.replacements;
-
-import java.lang.invoke.*;
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
-import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * Node for invocation methods defined on the class {@link MethodHandle}.
- */
-@NodeInfo
-public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable {
-    public static final NodeClass<MethodHandleNode> TYPE = NodeClass.create(MethodHandleNode.class);
-
-    protected final IntrinsicMethod intrinsicMethod;
-
-    public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
-        super(TYPE, invokeKind, targetMethod, bci, returnType, arguments);
-        this.intrinsicMethod = intrinsicMethod;
-    }
-
-    /**
-     * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an
-     * invocation on another method with possibly transformed arguments.
-     *
-     * @param assumptions object for recording any speculations made during the transformation
-     * @param methodHandleAccess objects for accessing the implementation internals of a
-     *            {@link MethodHandle}
-     * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed
-     * @param bci the BCI of the original {@link MethodHandle} call
-     * @param returnType return type of the original {@link MethodHandle} call
-     * @param arguments arguments to the original {@link MethodHandle} call
-     * @return a more direct invocation derived from the {@link MethodHandle} call or null
-     */
-    public static InvokeNode tryResolveTargetInvoke(Assumptions assumptions, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod original, int bci,
-                    JavaType returnType, ValueNode... arguments) {
-        switch (intrinsicMethod) {
-            case INVOKE_BASIC:
-                return getInvokeBasicTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
-            case LINK_TO_STATIC:
-            case LINK_TO_SPECIAL:
-            case LINK_TO_VIRTUAL:
-            case LINK_TO_INTERFACE:
-                return getLinkToTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    @Override
-    public void simplify(SimplifierTool tool) {
-        MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess();
-        ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]);
-        InvokeNode invoke = tryResolveTargetInvoke(graph().getAssumptions(), methodHandleAccess, intrinsicMethod, targetMethod, bci, returnType, argumentsArray);
-        if (invoke != null) {
-            assert invoke.graph() == null;
-            invoke = graph().addOrUniqueWithInputs(invoke);
-            invoke.setStateAfter(stateAfter());
-            FixedNode currentNext = next();
-            replaceAtUsages(invoke);
-            GraphUtil.removeFixedWithUnusedInputs(this);
-            graph().addBeforeFixed(currentNext, invoke);
-        }
-    }
-
-    /**
-     * Get the receiver of a MethodHandle.invokeBasic call.
-     *
-     * @return the receiver argument node
-     */
-    private static ValueNode getReceiver(ValueNode[] arguments) {
-        return arguments[0];
-    }
-
-    /**
-     * Get the MemberName argument of a MethodHandle.linkTo* call.
-     *
-     * @return the MemberName argument node (which is the last argument)
-     */
-    private static ValueNode getMemberName(ValueNode[] arguments) {
-        return arguments[arguments.length - 1];
-    }
-
-    /**
-     * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC }
-     * method) to get the target {@link InvokeNode} if the method handle receiver is constant.
-     *
-     * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
-     */
-    private static InvokeNode getInvokeBasicTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
-                    JavaType returnType, ValueNode[] arguments) {
-        ValueNode methodHandleNode = getReceiver(arguments);
-        if (methodHandleNode.isConstant()) {
-            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original);
-        }
-        return null;
-    }
-
-    /**
-     * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC},
-     * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and
-     * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if
-     * the member name argument is constant.
-     *
-     * @return invoke node for the member name target
-     */
-    private static InvokeNode getLinkToTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
-                    JavaType returnType, ValueNode[] arguments) {
-        ValueNode memberNameNode = getMemberName(arguments);
-        if (memberNameNode.isConstant()) {
-            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original);
-        }
-        return null;
-    }
-
-    /**
-     * Helper function to get the {@link InvokeNode} for the targetMethod of a
-     * java.lang.invoke.MemberName.
-     *
-     * @param target the target, already loaded from the member name node
-     * @return invoke node for the member name target
-     */
-    private static InvokeNode getTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, int bci, JavaType returnType, ValueNode[] arguments, ResolvedJavaMethod target,
-                    ResolvedJavaMethod original) {
-        if (target == null) {
-            return null;
-        }
-
-        // In lambda forms we erase signature types to avoid resolving issues
-        // involving class loaders. When we optimize a method handle invoke
-        // to a direct call we must cast the receiver and arguments to its
-        // actual types.
-        Signature signature = target.getSignature();
-        final boolean isStatic = target.isStatic();
-        final int receiverSkip = isStatic ? 0 : 1;
-
-        // Cast receiver to its type.
-        if (!isStatic) {
-            JavaType receiverType = target.getDeclaringClass();
-            maybeCastArgument(arguments, 0, receiverType);
-        }
-
-        // Cast reference arguments to its type.
-        for (int index = 0; index < signature.getParameterCount(false); index++) {
-            JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass());
-            maybeCastArgument(arguments, receiverSkip + index, parameterType);
-        }
-
-        if (target.canBeStaticallyBound()) {
-            return createTargetInvokeNode(intrinsicMethod, target, original, bci, returnType, arguments);
-        }
-
-        // Try to get the most accurate receiver type
-        if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
-            ValueNode receiver = getReceiver(arguments);
-            ResolvedJavaType receiverType = StampTool.typeOrNull(receiver.stamp());
-            if (receiverType != null) {
-                AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.findUniqueConcreteMethod(target);
-                if (concreteMethod != null) {
-                    assumptions.record(concreteMethod);
-                    return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
-                }
-            }
-        } else {
-            AssumptionResult<ResolvedJavaMethod> concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
-            if (concreteMethod != null) {
-                assumptions.record(concreteMethod);
-                return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Inserts a node to cast the argument at index to the given type if the given type is more
-     * concrete than the argument type.
-     *
-     * @param index of the argument to be cast
-     * @param type the type the argument should be cast to
-     */
-    private static void maybeCastArgument(ValueNode[] arguments, int index, JavaType type) {
-        if (type instanceof ResolvedJavaType) {
-            ResolvedJavaType targetType = (ResolvedJavaType) type;
-            if (!targetType.isPrimitive()) {
-                ValueNode argument = arguments[index];
-                ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
-                if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
-                    PiNode piNode = new PiNode(argument, StampFactory.declared(targetType));
-                    arguments[index] = piNode;
-                }
-            }
-        }
-    }
-
-    /**
-     * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
-     * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}.
-     *
-     * @return invoke node for the member name target
-     */
-    private static InvokeNode createTargetInvokeNode(IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, JavaType returnType, ValueNode[] arguments) {
-        InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special;
-        JavaType targetReturnType = target.getSignature().getReturnType(null);
-
-        // MethodHandleLinkTo* nodes have a trailing MemberName argument which
-        // needs to be popped.
-        ValueNode[] targetArguments;
-        switch (intrinsicMethod) {
-            case INVOKE_BASIC:
-                targetArguments = arguments;
-                break;
-            case LINK_TO_STATIC:
-            case LINK_TO_SPECIAL:
-            case LINK_TO_VIRTUAL:
-            case LINK_TO_INTERFACE:
-                targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-
-        MethodCallTargetNode callTarget = ResolvedMethodHandleCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnType, original, arguments, returnType);
-
-        // The call target can have a different return type than the invoker,
-        // e.g. the target returns an Object but the invoker void. In this case
-        // we need to use the stamp of the invoker. Note: always using the
-        // invoker's stamp would be wrong because it's a less concrete type
-        // (usually java.lang.Object).
-        if (returnType.getKind() == Kind.Void) {
-            return new InvokeNode(callTarget, bci, StampFactory.forVoid());
-        } else {
-            return new InvokeNode(callTarget, bci);
-        }
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Thu May 28 17:44:05 2015 +0200
@@ -157,8 +157,7 @@
     public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
 
     @Snippet
-    public static Object allocateInstanceDynamic(Class<?> type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
-                    @SuppressWarnings("unused") @ConstantParameter String typeContext) {
+    public static Object allocateInstanceDynamic(Class<?> type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) {
         KlassPointer hub = ClassGetHubNode.readClass(type);
         if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) {
             if (probability(FAST_PATH_PROBABILITY, isInstanceKlassFullyInitialized(hub))) {
@@ -202,13 +201,13 @@
         Word top = readTlabTop(thread);
         Word end = readTlabEnd(thread);
         Word newTop = top.add(allocationSize);
-        if ((skipNegativeCheck || belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
+        if (probability(FREQUENT_PROBABILITY, skipNegativeCheck || belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB() &&
+                        probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
             writeTlabTop(thread, newTop);
             emitPrefetchAllocate(newTop, true);
             newarray_loopInit.inc();
             result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, true);
         } else {
-            newarray_stub.inc();
             result = newArray(HotSpotBackend.NEW_ARRAY, hub, length);
         }
         profileAllocation("array", allocationSize, typeContext);
@@ -234,7 +233,7 @@
     @Snippet
     public static Object allocateArrayDynamic(Class<?> elementType, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) {
         Word hub = loadWordFromObject(elementType, arrayKlassOffset(), CLASS_ARRAY_KLASS_LOCATION);
-        if (hub.equal(Word.zero()) || !belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) {
+        if (probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, hub.equal(Word.zero()) || !belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH))) {
             return dynamicNewArrayStub(DYNAMIC_NEW_ARRAY, elementType, length);
         }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu May 28 17:44:05 2015 +0200
@@ -56,14 +56,14 @@
                     final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(method);
                     final Replacements replacements = tool.getReplacements();
                     StructuredGraph snippetGraph = null;
-                    try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) {
+                    try (Scope s = Debug.scope("ArrayCloneSnippet", snippetMethod)) {
                         snippetGraph = replacements.getSnippet(snippetMethod, null);
                     } catch (Throwable e) {
                         throw Debug.handle(e);
                     }
 
                     assert snippetGraph != null : "ObjectCloneSnippets should be installed";
-                    return lowerReplacement(snippetGraph.copy(), tool);
+                    return lowerReplacement((StructuredGraph) snippetGraph.copy(), tool);
                 }
                 assert false : "unhandled array type " + type.getComponentType().getKind();
             } else {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeLoadSnippets.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeLoadSnippets.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,8 +27,8 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.HeapAccess.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Thu May 28 17:44:05 2015 +0200
@@ -38,8 +38,8 @@
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.HeapAccess.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java	Thu May 28 17:44:05 2015 +0200
@@ -23,12 +23,11 @@
 //JaCoCo Exclude
 package com.oracle.graal.hotspot.replacements.arraycopy;
 
-import static com.oracle.graal.api.meta.LocationIdentity.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -36,20 +35,24 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.runtime.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
+public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, MemoryAccess, Canonicalizable {
 
     public static final NodeClass<ArrayCopyCallNode> TYPE = NodeClass.create(ArrayCopyCallNode.class);
-    @Input ValueNode src;
-    @Input ValueNode srcPos;
-    @Input ValueNode dest;
-    @Input ValueNode destPos;
-    @Input ValueNode length;
+    @Input protected ValueNode src;
+    @Input protected ValueNode srcPos;
+    @Input protected ValueNode dest;
+    @Input protected ValueNode destPos;
+    @Input protected ValueNode length;
 
-    protected Kind elementKind;
+    @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess;
+
+    protected final Kind elementKind;
+    protected final LocationIdentity locationIdentity;
 
     /**
      * Aligned means that the offset of the copy is heap word aligned.
@@ -62,16 +65,16 @@
 
     public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind,
                     boolean aligned, boolean disjoint, boolean uninitialized) {
-        this(src, srcPos, dest, destPos, length, elementKind, aligned, disjoint, uninitialized, runtime);
+        this(runtime, src, srcPos, dest, destPos, length, elementKind, null, aligned, disjoint, uninitialized);
     }
 
     public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind,
                     boolean disjoint) {
-        this(src, srcPos, dest, destPos, length, elementKind, false, disjoint, false, runtime);
+        this(runtime, src, srcPos, dest, destPos, length, elementKind, null, false, disjoint, false);
     }
 
-    protected ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean aligned, boolean disjoint, boolean uninitialized,
-                    HotSpotGraalRuntimeProvider runtime) {
+    protected ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind,
+                    LocationIdentity locationIdentity, boolean aligned, boolean disjoint, boolean uninitialized) {
         super(TYPE, StampFactory.forVoid());
         assert elementKind != null;
         this.src = src;
@@ -80,6 +83,7 @@
         this.destPos = destPos;
         this.length = length;
         this.elementKind = elementKind;
+        this.locationIdentity = (locationIdentity != null ? locationIdentity : NamedLocationIdentity.getArrayLocation(elementKind));
         this.aligned = aligned;
         this.disjoint = disjoint;
         this.uninitialized = uninitialized;
@@ -121,7 +125,8 @@
     public void lower(LoweringTool tool) {
         if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
             updateAlignedDisjoint();
-            ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint(), isUninitialized());
+            ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint(), isUninitialized(),
+                            locationIdentity.equals(LocationIdentity.any()));
             StructuredGraph graph = graph();
             ValueNode srcAddr = computeBase(getSource(), getSourcePosition());
             ValueNode destAddr = computeBase(getDestination(), getDestinationPosition());
@@ -132,24 +137,38 @@
             ForeignCallNode call = graph.add(new ForeignCallNode(Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len));
             call.setStateAfter(stateAfter());
             graph.replaceFixedWithFixed(this, call);
+        }
+    }
 
-        }
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    public void setLastLocationAccess(MemoryNode lla) {
+        updateUsagesInterface(lastLocationAccess, lla);
+        lastLocationAccess = lla;
     }
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        if (elementKind != null) {
-            return NamedLocationIdentity.getArrayLocation(elementKind);
-        }
-        return any();
+        return locationIdentity;
     }
 
     @NodeIntrinsic
     private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind, @ConstantNodeParameter boolean aligned,
                     @ConstantNodeParameter boolean disjoint, @ConstantNodeParameter boolean uninitialized);
 
-    public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind, boolean aligned, boolean disjoint) {
-        arraycopy(src, srcPos, dest, destPos, length, elementKind, aligned, disjoint, false);
+    @NodeIntrinsic
+    private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind,
+                    @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter boolean aligned, @ConstantNodeParameter boolean disjoint,
+                    @ConstantNodeParameter boolean uninitialized);
+
+    public static void arraycopyObjectKillsAny(Object src, int srcPos, Object dest, int destPos, int length) {
+        arraycopy(src, srcPos, dest, destPos, length, Kind.Object, LocationIdentity.any(), false, false, false);
+    }
+
+    public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind) {
+        arraycopy(src, srcPos, dest, destPos, length, elementKind, false, false, false);
     }
 
     public static void disjointArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind) {
@@ -194,4 +213,15 @@
             }
         }
     }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (getLength().isConstant() && getLength().asConstant().isDefaultForKind()) {
+            if (lastLocationAccess != null) {
+                replaceAtUsages(InputType.Memory, lastLocationAccess.asNode());
+            }
+            return null;
+        }
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Thu May 28 17:44:05 2015 +0200
@@ -22,19 +22,13 @@
  */
 package com.oracle.graal.hotspot.replacements.arraycopy;
 
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @NodeInfo
@@ -42,101 +36,26 @@
 
     public static final NodeClass<ArrayCopyNode> TYPE = NodeClass.create(ArrayCopyNode.class);
 
-    public ArrayCopyNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
-        super(TYPE, invokeKind, targetMethod, bci, returnType, src, srcPos, dst, dstPos, length);
-    }
-
-    private StructuredGraph selectSnippet(LoweringTool tool, final Replacements replacements) {
-        ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp());
-        ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp());
+    private Kind elementKind;
 
-        if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) {
-            return null;
-        }
-        if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) {
-            return null;
-        }
-        if (!isExact()) {
-            return null;
-        }
-        Kind componentKind = srcType.getComponentType().getKind();
-        final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind, shouldUnroll(), isExact()));
-        try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) {
-            return replacements.getSnippet(snippetMethod, null, null);
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-    }
-
-    private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) {
-        ParameterNode lengthParam = snippetGraph.getParameter(4);
-        if (lengthParam != null) {
-            snippetGraph.replaceFloating(lengthParam, ConstantNode.forInt(length, snippetGraph));
-        }
-        // the canonicalization before loop unrolling is needed to propagate the length into
-        // additions, etc.
-        PhaseContext context = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.getStampProvider());
-        new CanonicalizerPhase().apply(snippetGraph, context);
-        new LoopFullUnrollPhase(new CanonicalizerPhase()).apply(snippetGraph, context);
-        new CanonicalizerPhase().apply(snippetGraph, context);
+    public ArrayCopyNode(int bci, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
+        super(TYPE, src, srcPos, dst, dstPos, length, null, bci);
+        elementKind = ArrayCopySnippets.Templates.selectComponentKind(this);
     }
 
     @Override
-    protected StructuredGraph getLoweredSnippetGraph(final LoweringTool tool) {
-        final Replacements replacements = tool.getReplacements();
-        StructuredGraph snippetGraph = selectSnippet(tool, replacements);
-        if (snippetGraph == null) {
-            ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp());
-            ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp());
-            ResolvedJavaType srcComponentType = srcType == null ? null : srcType.getComponentType();
-            ResolvedJavaType destComponentType = destType == null ? null : destType.getComponentType();
-            ResolvedJavaMethod snippetMethod = null;
-            if (srcComponentType != null && destComponentType != null && !srcComponentType.isPrimitive() && !destComponentType.isPrimitive()) {
-                snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.checkcastArraycopySnippet);
-            } else {
-                snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet);
-            }
-            snippetGraph = null;
-            try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) {
-                snippetGraph = replacements.getSnippet(snippetMethod, getTargetMethod(), null).copy();
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-            replaceSnippetInvokes(snippetGraph);
-        } else {
-            assert snippetGraph != null : "ArrayCopySnippets should be installed";
-            snippetGraph = snippetGraph.copy();
-            if (shouldUnroll()) {
-                final StructuredGraph copy = snippetGraph;
-                try (Scope s = Debug.scope("ArrayCopySnippetSpecialization", snippetGraph.method())) {
-                    unrollFixedLengthLoop(copy, getLength().asJavaConstant().asInt(), tool);
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
-                }
-            }
+    public LocationIdentity getLocationIdentity() {
+        if (elementKind == null) {
+            elementKind = ArrayCopySnippets.Templates.selectComponentKind(this);
         }
-        return lowerReplacement(snippetGraph, tool);
+        if (elementKind != null) {
+            return NamedLocationIdentity.getArrayLocation(elementKind);
+        }
+        return any();
     }
 
-    private boolean shouldUnroll() {
-        return getLength().isConstant() && getLength().asJavaConstant().asInt() <= GraalOptions.MaximumEscapeAnalysisArrayLength.getValue();
-    }
-
-    /*
-     * Returns true if this copy doesn't require store checks. Trivially true for primitive arrays.
-     */
-    private boolean isExact() {
-        ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp());
-        if (srcType.getComponentType().getKind().isPrimitive() || getSource() == getDestination()) {
-            return true;
-        }
-
-        ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp());
-        if (StampTool.isExactType(getDestination().stamp())) {
-            if (destType != null && destType.isAssignableFrom(srcType)) {
-                return true;
-            }
-        }
-        return false;
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.replacements.arraycopy;
+
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.nodes.*;
+
+@NodeInfo
+public final class ArrayCopySlowPathNode extends BasicArrayCopyNode {
+
+    public static final NodeClass<ArrayCopySlowPathNode> TYPE = NodeClass.create(ArrayCopySlowPathNode.class);
+
+    private final SnippetTemplate.SnippetInfo snippet;
+
+    public ArrayCopySlowPathNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, SnippetTemplate.SnippetInfo snippet) {
+        super(TYPE, src, srcPos, dest, destPos, length, elementKind, BytecodeFrame.INVALID_FRAMESTATE_BCI);
+        assert StampTool.isPointerNonNull(src) && StampTool.isPointerNonNull(dest) : "must have been null checked";
+        this.snippet = snippet;
+    }
+
+    @NodeIntrinsic
+    public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantNodeParameter Kind elementKind,
+                    @ConstantNodeParameter SnippetTemplate.SnippetInfo snippet);
+
+    public SnippetTemplate.SnippetInfo getSnippet() {
+        return snippet;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        if (elementKind != null) {
+            return NamedLocationIdentity.getArrayLocation(elementKind);
+        }
+        return any();
+    }
+
+    public void setBci(int bci) {
+        this.bci = bci;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,74 +30,33 @@
 import java.lang.reflect.*;
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.SnippetTemplate.Arguments;
+import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
+import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
 
 public class ArrayCopySnippets implements Snippets {
 
-    private static final EnumMap<Kind, Method> arraycopyMethods = new EnumMap<>(Kind.class);
-    private static final EnumMap<Kind, Method> arraycopyCalls = new EnumMap<>(Kind.class);
-
-    public static final Method checkcastArraycopySnippet;
-    public static final Method genericArraycopySnippet;
-
-    private static void addArraycopySnippetMethod(Kind kind, Class<?> arrayClass) throws NoSuchMethodException {
-        arraycopyMethods.put(kind, ArrayCopySnippets.class.getDeclaredMethod("arraycopy", arrayClass, int.class, arrayClass, int.class, int.class));
-        if (CallArrayCopy.getValue()) {
-            if (kind == Kind.Object) {
-                arraycopyCalls.put(kind, ArrayCopySnippets.class.getDeclaredMethod("objectArraycopyUnchecked", arrayClass, int.class, arrayClass, int.class, int.class));
-            } else {
-                arraycopyCalls.put(kind, ArrayCopySnippets.class.getDeclaredMethod(kind + "Arraycopy", arrayClass, int.class, arrayClass, int.class, int.class));
-            }
-        }
-    }
-
-    static {
-        try {
-            addArraycopySnippetMethod(Kind.Byte, byte[].class);
-            addArraycopySnippetMethod(Kind.Boolean, boolean[].class);
-            addArraycopySnippetMethod(Kind.Char, char[].class);
-            addArraycopySnippetMethod(Kind.Short, short[].class);
-            addArraycopySnippetMethod(Kind.Int, int[].class);
-            addArraycopySnippetMethod(Kind.Long, long[].class);
-            addArraycopySnippetMethod(Kind.Float, float[].class);
-            addArraycopySnippetMethod(Kind.Double, double[].class);
-            addArraycopySnippetMethod(Kind.Object, Object[].class);
-            checkcastArraycopySnippet = ArrayCopySnippets.class.getDeclaredMethod("checkcastArraycopy", Object[].class, int.class, Object[].class, int.class, int.class);
-            genericArraycopySnippet = ArrayCopySnippets.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class);
-        } catch (SecurityException | NoSuchMethodException e) {
-            throw new GraalInternalError(e);
-        }
-    }
-
-    public static Method getSnippetForKind(Kind kind, boolean shouldUnroll, boolean exact) {
-        Method m = null;
-        if (!shouldUnroll && exact) {
-            // use hotspot stubs
-            m = arraycopyCalls.get(kind);
-            if (m != null) {
-                return m;
-            }
-        }
-        // use snippets
-        return arraycopyMethods.get(kind);
-    }
-
-    private static void checkedCopy(Object src, int srcPos, Object dest, int destPos, int length, Kind baseKind) {
-        Object nonNullSrc = guardingNonNull(src);
-        Object nonNullDest = guardingNonNull(dest);
-        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
-        UnsafeArrayCopyNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, baseKind);
-    }
-
     private static int checkArrayType(KlassPointer hub) {
         int layoutHelper = readLayoutHelper(hub);
         if (probability(SLOW_PATH_PROBABILITY, layoutHelper >= 0)) {
@@ -131,90 +90,119 @@
     }
 
     @Snippet
-    public static void arraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
-        byteCounter.inc();
-        checkedCopy(src, srcPos, dest, destPos, length, Kind.Byte);
-    }
-
-    @Snippet
-    public static void arraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) {
-        booleanCounter.inc();
-        checkedCopy(src, srcPos, dest, destPos, length, Kind.Boolean);
-    }
-
-    @Snippet
-    public static void arraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) {
-        charCounter.inc();
-        checkedCopy(src, srcPos, dest, destPos, length, Kind.Char);
-    }
-
-    @Snippet
-    public static void arraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) {
-        shortCounter.inc();
-        checkedCopy(src, srcPos, dest, destPos, length, Kind.Short);
-    }
-
-    @Snippet
-    public static void arraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) {
-        intCounter.inc();
-        checkedCopy(src, srcPos, dest, destPos, length, Kind.Int);
-    }
-
-    @Snippet
-    public static void arraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) {
-        floatCounter.inc();
-        checkedCopy(src, srcPos, dest, destPos, length, Kind.Float);
+    public static void arraycopyZeroLengthIntrinsic(Object src, int srcPos, Object dest, int destPos, int length) {
+        Object nonNullSrc = guardingNonNull(src);
+        Object nonNullDest = guardingNonNull(dest);
+        KlassPointer srcHub = loadHub(nonNullSrc);
+        KlassPointer destHub = loadHub(nonNullDest);
+        checkArrayType(srcHub);
+        checkArrayType(destHub);
+        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
+        zeroLengthStaticCounter.inc();
     }
 
     @Snippet
-    public static void arraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) {
-        longCounter.inc();
-        checkedCopy(src, srcPos, dest, destPos, length, Kind.Long);
-    }
-
-    @Snippet
-    public static void arraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) {
-        doubleCounter.inc();
-        checkedCopy(src, srcPos, dest, destPos, length, Kind.Double);
-    }
-
-    @Snippet
-    public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) {
-        objectCounter.inc();
-        checkedCopy(src, srcPos, dest, destPos, length, Kind.Object);
-    }
-
-    @Snippet
-    public static void checkcastArraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) {
-        objectCheckcastCounter.inc();
+    public static void arraycopyExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Kind elementKind, @ConstantParameter SnippetCounter counter) {
         Object nonNullSrc = guardingNonNull(src);
         Object nonNullDest = guardingNonNull(dest);
         checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
-        if (probability(SLOW_PATH_PROBABILITY, nonNullSrc == nonNullDest)) {
-            // no storecheck required.
-            ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, Kind.Object, false, false);
+        counter.inc();
+        ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind);
+        if (length == 0) {
+            zeroLengthDynamicCounter.inc();
         } else {
-            KlassPointer destElemKlass = loadHub(nonNullDest);
-            checkcastArraycopyHelper(srcPos, destPos, length, nonNullSrc, nonNullDest, destElemKlass);
+            nonZeroLengthDynamicCounter.inc();
         }
     }
 
-    private static void checkcastArraycopyHelper(int srcPos, int destPos, int length, Object nonNullSrc, Object nonNullDest, KlassPointer destElemKlass) {
-        Word superCheckOffset = Word.signed(destElemKlass.readInt(superCheckOffsetOffset(), KLASS_SUPER_CHECK_OFFSET_LOCATION));
-        int copiedElements = CheckcastArrayCopyCallNode.checkcastArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, superCheckOffset, destElemKlass, false);
-        if (copiedElements != 0) {
-            // the checkcast stub doesn't throw the ArrayStoreException, but returns the number of
-            // copied elements (xor'd with -1).
-            copiedElements ^= -1;
-            System.arraycopy(nonNullSrc, srcPos + copiedElements, nonNullDest, destPos + copiedElements, length - copiedElements);
+    /**
+     * This intrinsic is useful for the case where we know something statically about one of the
+     * inputs but not the other.
+     */
+    @Snippet
+    public static void arraycopyPredictedExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Kind elementKind, @ConstantParameter SnippetCounter counter) {
+        Object nonNullSrc = guardingNonNull(src);
+        Object nonNullDest = guardingNonNull(dest);
+        KlassPointer srcHub = loadHub(nonNullSrc);
+        KlassPointer destHub = loadHub(nonNullDest);
+        if (probability(SLOW_PATH_PROBABILITY, srcHub != destHub)) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
+        counter.inc();
+        ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind);
+        if (length == 0) {
+            zeroLengthDynamicCounter.inc();
         } else {
-            // Capture an after state for this path.
-            ArrayCopyStateNode.captureState();
+            nonZeroLengthDynamicCounter.inc();
         }
     }
 
     @Snippet
-    public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) {
+    public static void arraycopyPredictedObjectWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, KlassPointer objectArrayKlass, @ConstantParameter SnippetCounter counter) {
+        if (length > 0) {
+            KlassPointer srcHub = loadHub(nonNullSrc);
+            KlassPointer destHub = loadHub(nonNullDest);
+            if (probability(FAST_PATH_PROBABILITY, srcHub == destHub || destHub == objectArrayKlass)) {
+                counter.inc();
+                predictedObjectArrayCopyFastPathCounter.inc();
+                ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length);
+            } else {
+                predictedObjectArrayCopySlowPathCounter.inc();
+                System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length);
+            }
+        }
+    }
+
+    /**
+     * This is the basic template for the full arraycopy checks, including a check that the
+     * underlying type is really an array type.
+     */
+    @Snippet
+    public static void arraycopySlowPathIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Kind elementKind, @ConstantParameter SnippetInfo slowPath) {
+        Object nonNullSrc = guardingNonNull(src);
+        Object nonNullDest = guardingNonNull(dest);
+        KlassPointer srcHub = loadHub(nonNullSrc);
+        KlassPointer destHub = loadHub(nonNullDest);
+        checkArrayType(srcHub);
+        checkArrayType(destHub);
+        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
+        if (length == 0) {
+            zeroLengthDynamicCounter.inc();
+        } else {
+            nonZeroLengthDynamicCounter.inc();
+        }
+        ArrayCopySlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind, slowPath);
+    }
+
+    @Snippet
+    public static void checkcastArraycopyWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length) {
+        if (length > 0) {
+            KlassPointer destKlass = loadHub(nonNullDest);
+            KlassPointer srcKlass = loadHub(nonNullSrc);
+            if (probability(SLOW_PATH_PROBABILITY, srcKlass == destKlass)) {
+                // no storecheck required.
+                objectCheckcastSameTypeCounter.inc();
+                ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length);
+            } else {
+                KlassPointer destElemKlass = destKlass.readKlassPointer(arrayClassElementOffset(), OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION);
+                Word superCheckOffset = Word.signed(destElemKlass.readInt(superCheckOffsetOffset(), KLASS_SUPER_CHECK_OFFSET_LOCATION));
+                objectCheckcastCounter.inc();
+                int copiedElements = CheckcastArrayCopyCallNode.checkcastArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, superCheckOffset, destElemKlass, false);
+                if (copiedElements != 0) {
+                    /*
+                     * the checkcast stub doesn't throw the ArrayStoreException, but returns the
+                     * number of copied elements (xor'd with -1).
+                     */
+                    copiedElements ^= -1;
+                    System.arraycopy(nonNullSrc, srcPos + copiedElements, nonNullDest, destPos + copiedElements, length - copiedElements);
+                }
+            }
+        }
+    }
+
+    @Snippet
+    public static void arraycopyGeneric(Object src, int srcPos, Object dest, int destPos, int length) {
         Object nonNullSrc = guardingNonNull(src);
         Object nonNullDest = guardingNonNull(dest);
         KlassPointer srcHub = loadHub(nonNullSrc);
@@ -225,102 +213,326 @@
             checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
             if (probability(FAST_PATH_PROBABILITY, isObjectArray)) {
                 genericObjectExactCallCounter.inc();
-                UnsafeArrayCopyNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, Kind.Object);
+                ArrayCopyCallNode.disjointArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, Kind.Object);
             } else {
                 genericPrimitiveCallCounter.inc();
                 UnsafeArrayCopyNode.arraycopyPrimitive(nonNullSrc, srcPos, nonNullDest, destPos, length, layoutHelper);
             }
         } else {
-            genericObjectCallCounter.inc();
+            SystemArraycopyCounter.inc();
             System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length);
         }
     }
 
-    @NodeIntrinsic(ForeignCallNode.class)
-    public static native void callArraycopy(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word src, Word dest, Word len);
-
-    private static void callArraycopyTemplate(SnippetCounter counter, Kind kind, boolean aligned, boolean disjoint, Object src, int srcPos, Object dest, int destPos, int length) {
-        counter.inc();
-        Object nonNullSrc = guardingNonNull(src);
-        Object nonNullDest = guardingNonNull(dest);
-        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
-        ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, kind, aligned, disjoint);
-    }
-
-    @Snippet
-    public static void objectArraycopyUnchecked(Object[] src, int srcPos, Object[] dest, int destPos, int length) {
-        callArraycopyTemplate(objectCallCounter, Kind.Object, false, false, src, srcPos, dest, destPos, length);
-    }
-
-    @Snippet
-    public static void byteArraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
-        callArraycopyTemplate(byteCallCounter, Kind.Byte, false, false, src, srcPos, dest, destPos, length);
-    }
-
-    @Snippet
-    public static void booleanArraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) {
-        callArraycopyTemplate(booleanCallCounter, Kind.Boolean, false, false, src, srcPos, dest, destPos, length);
+    @Fold
+    private static LocationIdentity getArrayLocation(Kind kind) {
+        return NamedLocationIdentity.getArrayLocation(kind);
     }
 
     @Snippet
-    public static void charArraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) {
-        callArraycopyTemplate(charCallCounter, Kind.Char, false, false, src, srcPos, dest, destPos, length);
-    }
-
-    @Snippet
-    public static void shortArraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) {
-        callArraycopyTemplate(shortCallCounter, Kind.Short, false, false, src, srcPos, dest, destPos, length);
-    }
-
-    @Snippet
-    public static void intArraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) {
-        callArraycopyTemplate(intCallCounter, Kind.Int, false, false, src, srcPos, dest, destPos, length);
-    }
-
-    @Snippet
-    public static void floatArraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) {
-        callArraycopyTemplate(floatCallCounter, Kind.Float, false, false, src, srcPos, dest, destPos, length);
-    }
-
-    @Snippet
-    public static void longArraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) {
-        callArraycopyTemplate(longCallCounter, Kind.Long, false, false, src, srcPos, dest, destPos, length);
-    }
-
-    @Snippet
-    public static void doubleArraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) {
-        callArraycopyTemplate(doubleCallCounter, Kind.Double, false, false, src, srcPos, dest, destPos, length);
+    public static void arraycopyUnrolledWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, @ConstantParameter int length, @ConstantParameter Kind elementKind) {
+        final int scale = arrayIndexScale(elementKind);
+        int arrayBaseOffset = arrayBaseOffset(elementKind);
+        LocationIdentity arrayLocation = getArrayLocation(elementKind);
+        if (nonNullSrc == nonNullDest && srcPos < destPos) { // bad aliased case
+            long start = (long) (length - 1) * scale;
+            long i = start;
+            ExplodeLoopNode.explodeLoop();
+            for (int iteration = 0; iteration < length; iteration++) {
+                if (i >= 0) {
+                    Object a = UnsafeLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation);
+                    DirectObjectStoreNode.storeObject(nonNullDest, arrayBaseOffset, i + (long) destPos * scale, a, arrayLocation, elementKind);
+                    i -= scale;
+                }
+            }
+        } else {
+            long end = (long) length * scale;
+            long i = 0;
+            ExplodeLoopNode.explodeLoop();
+            for (int iteration = 0; iteration < length; iteration++) {
+                if (i < end) {
+                    Object a = UnsafeLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation);
+                    DirectObjectStoreNode.storeObject(nonNullDest, arrayBaseOffset, i + (long) destPos * scale, a, arrayLocation, elementKind);
+                    i += scale;
+                }
+            }
+        }
     }
 
     private static final SnippetCounter.Group checkCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy checkInputs") : null;
     private static final SnippetCounter checkSuccessCounter = new SnippetCounter(checkCounters, "checkSuccess", "checkSuccess");
-    private static final SnippetCounter checkNPECounter = new SnippetCounter(checkCounters, "checkNPE", "checkNPE");
     private static final SnippetCounter checkAIOOBECounter = new SnippetCounter(checkCounters, "checkAIOOBE", "checkAIOOBE");
 
     private static final SnippetCounter.Group counters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy") : null;
-    private static final SnippetCounter byteCounter = new SnippetCounter(counters, "byte[]", "arraycopy for byte[] arrays");
-    private static final SnippetCounter charCounter = new SnippetCounter(counters, "char[]", "arraycopy for char[] arrays");
-    private static final SnippetCounter shortCounter = new SnippetCounter(counters, "short[]", "arraycopy for short[] arrays");
-    private static final SnippetCounter intCounter = new SnippetCounter(counters, "int[]", "arraycopy for int[] arrays");
-    private static final SnippetCounter booleanCounter = new SnippetCounter(counters, "boolean[]", "arraycopy for boolean[] arrays");
-    private static final SnippetCounter longCounter = new SnippetCounter(counters, "long[]", "arraycopy for long[] arrays");
-    private static final SnippetCounter objectCounter = new SnippetCounter(counters, "Object[]", "arraycopy for Object[] arrays");
+
     private static final SnippetCounter objectCheckcastCounter = new SnippetCounter(counters, "Object[]", "arraycopy for non-exact Object[] arrays");
-    private static final SnippetCounter floatCounter = new SnippetCounter(counters, "float[]", "arraycopy for float[] arrays");
-    private static final SnippetCounter doubleCounter = new SnippetCounter(counters, "double[]", "arraycopy for double[] arrays");
+    private static final SnippetCounter objectCheckcastSameTypeCounter = new SnippetCounter(counters, "Object[]", "arraycopy call for src.klass == dest.klass Object[] arrays");
+    private static final SnippetCounter predictedObjectArrayCopySlowPathCounter = new SnippetCounter(counters, "Object[]", "used System.arraycopy slow path for predicted Object[] arrays");
+    private static final SnippetCounter predictedObjectArrayCopyFastPathCounter = new SnippetCounter(counters, "Object[]", "used oop_arraycopy for predicted Object[] arrays");
+
+    private static final EnumMap<Kind, SnippetCounter> arraycopyCallCounters = new EnumMap<>(Kind.class);
+    private static final EnumMap<Kind, SnippetCounter> arraycopyCounters = new EnumMap<>(Kind.class);
 
-    private static final SnippetCounter objectCallCounter = new SnippetCounter(counters, "Object[]", "arraycopy call for Object[] arrays");
+    static void createArraycopyCounter(Kind kind) {
+        arraycopyCallCounters.put(kind, new SnippetCounter(counters, kind + "[]", "arraycopy call for " + kind + "[] arrays"));
+        arraycopyCounters.put(kind, new SnippetCounter(counters, kind + "[]", "inline arraycopy for " + kind + "[] arrays"));
+    }
 
-    private static final SnippetCounter booleanCallCounter = new SnippetCounter(counters, "boolean[]", "arraycopy call for boolean[] arrays");
-    private static final SnippetCounter byteCallCounter = new SnippetCounter(counters, "byte[]", "arraycopy call for byte[] arrays");
-    private static final SnippetCounter charCallCounter = new SnippetCounter(counters, "char[]", "arraycopy call for char[] arrays");
-    private static final SnippetCounter doubleCallCounter = new SnippetCounter(counters, "double[]", "arraycopy call for double[] arrays");
-    private static final SnippetCounter floatCallCounter = new SnippetCounter(counters, "float[]", "arraycopy call for float[] arrays");
-    private static final SnippetCounter intCallCounter = new SnippetCounter(counters, "int[]", "arraycopy call for int[] arrays");
-    private static final SnippetCounter longCallCounter = new SnippetCounter(counters, "long[]", "arraycopy call for long[] arrays");
-    private static final SnippetCounter shortCallCounter = new SnippetCounter(counters, "short[]", "arraycopy call for short[] arrays");
+    static {
+        createArraycopyCounter(Kind.Byte);
+        createArraycopyCounter(Kind.Boolean);
+        createArraycopyCounter(Kind.Char);
+        createArraycopyCounter(Kind.Short);
+        createArraycopyCounter(Kind.Int);
+        createArraycopyCounter(Kind.Long);
+        createArraycopyCounter(Kind.Float);
+        createArraycopyCounter(Kind.Double);
+        createArraycopyCounter(Kind.Object);
+    }
 
     private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays");
     private static final SnippetCounter genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays");
-    private static final SnippetCounter genericObjectCallCounter = new SnippetCounter(counters, "genericObject", "call to the generic, native arraycopy method");
+    private static final SnippetCounter SystemArraycopyCounter = new SnippetCounter(counters, "genericObject", "call to System.arraycopy");
+
+    private static final SnippetCounter.Group lengthCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy 0-length checks") : null;
+
+    private static final SnippetCounter zeroLengthStaticCounter = new SnippetCounter(lengthCounters, "0-lengthcopy static", "arraycopy where the length is statically 0");
+    private static final SnippetCounter zeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "0-lengthcopy dynamically", "arraycopy where the length is dynamically 0");
+    private static final SnippetCounter nonZeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "non-0-lengthcopy dynamically", "arraycopy where the length is dynamically not zero");
+
+    public static class Templates extends SnippetTemplate.AbstractTemplates {
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        private ResolvedJavaMethod originalArraycopy() throws GraalInternalError {
+            if (originalArraycopy == null) {
+                Method method;
+                try {
+                    method = System.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class);
+                } catch (NoSuchMethodException | SecurityException e) {
+                    throw new GraalInternalError(e);
+                }
+                originalArraycopy = providers.getMetaAccess().lookupJavaMethod(method);
+            }
+            return originalArraycopy;
+        }
+
+        private ResolvedJavaMethod originalArraycopy;
+
+        private final SnippetInfo checkcastArraycopyWorkSnippet = snippet("checkcastArraycopyWork");
+        private final SnippetInfo arraycopyGenericSnippet = snippet("arraycopyGeneric");
+
+        private final SnippetInfo arraycopySlowPathIntrinsicSnippet = snippet("arraycopySlowPathIntrinsic");
+        private final SnippetInfo arraycopyExactIntrinsicSnippet = snippet("arraycopyExactIntrinsic");
+        private final SnippetInfo arraycopyZeroLengthIntrinsicSnippet = snippet("arraycopyZeroLengthIntrinsic");
+        private final SnippetInfo arraycopyPredictedExactIntrinsicSnippet = snippet("arraycopyPredictedExactIntrinsic");
+        private final SnippetInfo arraycopyPredictedObjectWorkSnippet = snippet("arraycopyPredictedObjectWork");
+
+        private final SnippetInfo arraycopyUnrolledWorkSnippet = snippet("arraycopyUnrolledWork");
+
+        protected SnippetInfo snippet(String methodName) {
+            SnippetInfo info = snippet(ArrayCopySnippets.class, methodName, LocationIdentity.any());
+            info.setOriginalMethod(originalArraycopy());
+            return info;
+        }
+
+        public static Kind selectComponentKind(BasicArrayCopyNode arraycopy) {
+            return selectComponentKind(arraycopy, true);
+        }
+
+        public static Kind selectComponentKind(BasicArrayCopyNode arraycopy, boolean exact) {
+            ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp());
+            ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp());
+
+            if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) {
+                if (!exact) {
+                    Kind component = getComponentKind(srcType);
+                    if (component != null) {
+                        return component;
+                    }
+                    return getComponentKind(destType);
+                }
+                return null;
+            }
+            if (exact) {
+                if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) {
+                    return null;
+                }
+                if (!arraycopy.isExact()) {
+                    return null;
+                }
+            }
+            return srcType.getComponentType().getKind();
+        }
+
+        private static Kind getComponentKind(ResolvedJavaType type) {
+            if (type != null && type.isArray()) {
+                return type.getComponentType().getKind();
+            }
+            return null;
+        }
+
+        private static boolean shouldUnroll(ValueNode length) {
+            return length.isConstant() && length.asJavaConstant().asInt() <= 8 && length.asJavaConstant().asInt() != 0;
+        }
+
+        private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) {
+            ParameterNode lengthParam = snippetGraph.getParameter(4);
+            if (lengthParam != null) {
+                snippetGraph.replaceFloating(lengthParam, ConstantNode.forInt(length, snippetGraph));
+            }
+            // the canonicalization before loop unrolling is needed to propagate the length into
+            // additions, etc.
+            PhaseContext context = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.getStampProvider());
+            new CanonicalizerPhase().apply(snippetGraph, context);
+            new LoopFullUnrollPhase(new CanonicalizerPhase()).apply(snippetGraph, context);
+            new CanonicalizerPhase().apply(snippetGraph, context);
+        }
+
+        void unrollSnippet(final LoweringTool tool, StructuredGraph snippetGraph, ArrayCopyNode arraycopy) {
+            if (shouldUnroll(arraycopy.getLength())) {
+                final StructuredGraph copy = snippetGraph;
+                try (Scope s = Debug.scope("ArrayCopySnippetSpecialization", snippetGraph.method())) {
+                    unrollFixedLengthLoop(copy, arraycopy.getLength().asJavaConstant().asInt(), tool);
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+            }
+        }
+
+        public void lower(ArrayCopyNode arraycopy, LoweringTool tool) {
+            Kind componentKind = selectComponentKind(arraycopy);
+            SnippetInfo snippetInfo = null;
+            SnippetInfo slowPathSnippetInfo = null;
+
+            if (arraycopy.getLength().isConstant() && arraycopy.getLength().asJavaConstant().asLong() == 0) {
+                snippetInfo = arraycopyZeroLengthIntrinsicSnippet;
+            } else if (arraycopy.isExact()) {
+                snippetInfo = arraycopyExactIntrinsicSnippet;
+                if (shouldUnroll(arraycopy.getLength())) {
+                    snippetInfo = arraycopySlowPathIntrinsicSnippet;
+                    slowPathSnippetInfo = arraycopyUnrolledWorkSnippet;
+                }
+            } else {
+                if (componentKind == Kind.Object) {
+                    ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp());
+                    ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp());
+                    ResolvedJavaType srcComponentType = srcType == null ? null : srcType.getComponentType();
+                    ResolvedJavaType destComponentType = destType == null ? null : destType.getComponentType();
+                    if (srcComponentType != null && destComponentType != null && !srcComponentType.isPrimitive() && !destComponentType.isPrimitive()) {
+                        snippetInfo = arraycopySlowPathIntrinsicSnippet;
+                        slowPathSnippetInfo = checkcastArraycopyWorkSnippet;
+                        /*
+                         * Because this snippet has to use Sysytem.arraycopy as a slow path, we must
+                         * pretend to kill any() so clear the componentKind.
+                         */
+                        componentKind = null;
+                    }
+                }
+                if (componentKind == null && snippetInfo == null) {
+                    Kind predictedKind = selectComponentKind(arraycopy, false);
+                    if (predictedKind != null) {
+                        /*
+                         * At least one array is of a known type requiring no store checks, so
+                         * assume the other is of the same type. Generally this is working around
+                         * deficiencies in our propation of type information.
+                         */
+                        componentKind = predictedKind;
+                        if (predictedKind == Kind.Object) {
+                            snippetInfo = arraycopySlowPathIntrinsicSnippet;
+                            slowPathSnippetInfo = arraycopyPredictedObjectWorkSnippet;
+                            componentKind = null;
+                        } else {
+                            snippetInfo = arraycopyPredictedExactIntrinsicSnippet;
+                        }
+                    }
+                }
+                if (snippetInfo == null) {
+                    snippetInfo = arraycopyGenericSnippet;
+                }
+            }
+            Arguments args = new Arguments(snippetInfo, arraycopy.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("src", arraycopy.getSource());
+            args.add("srcPos", arraycopy.getSourcePosition());
+            args.add("dest", arraycopy.getDestination());
+            args.add("destPos", arraycopy.getDestinationPosition());
+            args.add("length", arraycopy.getLength());
+            if (snippetInfo == arraycopySlowPathIntrinsicSnippet) {
+                args.addConst("elementKind", componentKind != null ? componentKind : Kind.Illegal);
+                args.addConst("slowPath", slowPathSnippetInfo);
+            } else if (snippetInfo == arraycopyExactIntrinsicSnippet || snippetInfo == arraycopyPredictedExactIntrinsicSnippet) {
+                assert componentKind != null;
+                args.addConst("elementKind", componentKind);
+                args.addConst("counter", arraycopyCallCounters.get(componentKind));
+            }
+            instantiate(args, arraycopy);
+        }
+
+        public void lower(ArrayCopySlowPathNode arraycopy, LoweringTool tool) {
+            StructuredGraph graph = arraycopy.graph();
+            if (!graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                // Can't be lowered yet
+                return;
+            }
+            SnippetInfo snippetInfo = arraycopy.getSnippet();
+            Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("nonNullSrc", arraycopy.getSource());
+            args.add("srcPos", arraycopy.getSourcePosition());
+            args.add("nonNullDest", arraycopy.getDestination());
+            args.add("destPos", arraycopy.getDestinationPosition());
+            if (snippetInfo == arraycopyUnrolledWorkSnippet) {
+                args.addConst("length", arraycopy.getLength().asJavaConstant().asInt());
+                args.addConst("elementKind", arraycopy.getElementKind());
+            } else {
+                args.add("length", arraycopy.getLength());
+            }
+            if (snippetInfo == arraycopyPredictedObjectWorkSnippet) {
+                HotSpotResolvedObjectType arrayKlass = (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(Object[].class);
+                ValueNode objectArrayKlass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), arrayKlass.klass(), tool.getMetaAccess(), arraycopy.graph());
+                args.add("objectArrayKlass", objectArrayKlass);
+                args.addConst("counter", arraycopyCallCounters.get(Kind.Object));
+            }
+            instantiate(args, arraycopy);
+        }
+
+        /**
+         * Instantiate the snippet template and fix up the FrameState of any Invokes of
+         * System.arraycopy and propagate the captured bci in the ArrayCopySlowPathNode.
+         *
+         * @param args
+         * @param arraycopy
+         */
+        private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) {
+            StructuredGraph graph = arraycopy.graph();
+            SnippetTemplate template = template(args);
+            Map<Node, Node> replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args);
+            for (Node originalNode : replacements.keySet()) {
+                if (originalNode instanceof Invoke) {
+                    Invoke invoke = (Invoke) replacements.get(originalNode);
+                    assert invoke.asNode().graph() == graph;
+                    CallTargetNode call = invoke.callTarget();
+
+                    if (!call.targetMethod().equals(originalArraycopy)) {
+                        throw new GraalInternalError("unexpected invoke %s in snippet", call.targetMethod());
+                    }
+                    // Here we need to fix the bci of the invoke
+                    InvokeNode newInvoke = graph.add(new InvokeNode(invoke.callTarget(), arraycopy.getBci()));
+                    if (arraycopy.stateDuring() != null) {
+                        newInvoke.setStateDuring(arraycopy.stateDuring());
+                    } else {
+                        assert arraycopy.stateAfter() != null;
+                        newInvoke.setStateAfter(arraycopy.stateAfter());
+                    }
+                    graph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke);
+                } else if (originalNode instanceof ArrayCopySlowPathNode) {
+                    ArrayCopySlowPathNode slowPath = (ArrayCopySlowPathNode) replacements.get(originalNode);
+                    assert arraycopy.stateAfter() != null;
+                    slowPath.setStateAfter(arraycopy.stateAfter());
+                    slowPath.setBci(arraycopy.getBci());
+                }
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyStateNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * 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.
- */
-//JaCoCo Exclude
-package com.oracle.graal.hotspot.replacements.arraycopy;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * A dummy node whose only purpose is to capture a final {@link FrameState} when lowering complex
- * arraycopy snippets.
- */
-
-@NodeInfo
-public final class ArrayCopyStateNode extends AbstractStateSplit implements Lowerable {
-
-    public static final NodeClass<ArrayCopyStateNode> TYPE = NodeClass.create(ArrayCopyStateNode.class);
-
-    protected ArrayCopyStateNode() {
-        super(TYPE, StampFactory.forKind(Kind.Void));
-
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
-            graph().removeFixed(this);
-        }
-    }
-
-    @NodeIntrinsic
-    public static native void captureState();
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,7 +24,6 @@
 package com.oracle.graal.hotspot.replacements.arraycopy;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
@@ -34,8 +33,8 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.runtime.*;
 import com.oracle.graal.word.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Value})
@@ -107,11 +106,10 @@
             ValueNode srcAddr = computeBase(getSource(), getSourcePosition());
             ValueNode destAddr = computeBase(getDestination(), getDestinationPosition());
             ValueNode len = getLength();
-            if (len.stamp().getStackKind() != Kind.Long) {
-                len = IntegerConvertNode.convert(len, StampFactory.forKind(Kind.Long), graph());
+            if (len.stamp().getStackKind() != runtime.getTarget().wordKind) {
+                len = IntegerConvertNode.convert(len, StampFactory.forKind(runtime.getTarget().wordKind), graph());
             }
-            ForeignCallNode call = graph.add(new ForeignCallNode(Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len, superCheckOffset,
-                            destElemKlass));
+            ForeignCallNode call = graph.add(new ForeignCallNode(runtime.getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len, superCheckOffset, destElemKlass));
             call.setStateAfter(stateAfter());
             graph.replaceFixedWithFixed(this, call);
         }
@@ -119,7 +117,11 @@
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return NamedLocationIdentity.getArrayLocation(Kind.Object);
+        /*
+         * Because of restrictions that the memory graph of snippets matches the original node,
+         * pretend that we kill any.
+         */
+        return LocationIdentity.any();
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java	Thu May 28 17:44:05 2015 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
+import static com.oracle.graal.hotspot.nodes.JumpToExceptionHandlerNode.*;
 import static com.oracle.graal.hotspot.nodes.PatchReturnAddressNode.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
@@ -32,7 +33,6 @@
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.replacements.*;
@@ -40,10 +40,10 @@
 import com.oracle.graal.word.*;
 
 /**
- * Stub called by the {@linkplain MarkId#EXCEPTION_HANDLER_ENTRY exception handler entry point} in a
- * compiled method. This entry point is used when returning to a method to handle an exception
- * thrown by a callee. It is not used for routing implicit exceptions. Therefore, it does not need
- * to save any registers as HotSpot uses a caller save convention.
+ * Stub called by the {@linkplain HotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception handler
+ * entry point} in a compiled method. This entry point is used when returning to a method to handle
+ * an exception thrown by a callee. It is not used for routing implicit exceptions. Therefore, it
+ * does not need to save any registers as HotSpot uses a caller save convention.
  * <p>
  * The descriptor for a call to this stub is {@link HotSpotBackend#EXCEPTION_HANDLER}.
  */
@@ -96,7 +96,7 @@
         }
 
         // patch the return address so that this stub returns to the exception handler
-        patchReturnAddress(handlerPc);
+        jumpToExceptionHandler(handlerPc);
     }
 
     static void checkNoExceptionInThread(Word thread, boolean enabled) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Thu May 28 17:44:05 2015 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
+import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*;
+
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.meta.*;
@@ -94,8 +96,8 @@
 
         assert SnippetGraphUnderConstruction.get() == null;
         SnippetGraphUnderConstruction.set(graph);
-        ReplacementContext initialReplacementContext = new ReplacementContext(method, method);
-        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph);
+        IntrinsicContext initialIntrinsicContext = new IntrinsicContext(method, method, INLINE_AFTER_PARSING);
+        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialIntrinsicContext).apply(graph);
         SnippetGraphUnderConstruction.set(null);
 
         graph.setGuardsStage(GuardsStage.FLOATING_GUARDS);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Thu May 28 17:44:05 2015 +0200
@@ -35,7 +35,6 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.asm.*;
@@ -194,9 +193,11 @@
                     HotSpotRuntimeStub installedCode = new HotSpotRuntimeStub(stub);
                     HotSpotCompiledCode hsCompResult = new HotSpotCompiledRuntimeStub(stub, compResult);
 
-                    CodeInstallResult result = runtime().getCompilerToVM().installCode(hsCompResult, installedCode, null);
-                    if (result != CodeInstallResult.OK) {
-                        throw new GraalInternalError("Error installing stub %s: %s", Stub.this, result);
+                    HotSpotGraalRuntime runtime = runtime();
+                    int result = runtime.getCompilerToVM().installCode(hsCompResult, installedCode, null);
+                    HotSpotVMConfig config = runtime.getConfig();
+                    if (result != config.codeInstallResultOk) {
+                        throw new GraalInternalError("Error installing stub %s: %s", Stub.this, config.getCodeInstallResultDescription(result));
                     }
                     ((HotSpotCodeCacheProvider) codeCache).logOrDump(installedCode, compResult);
                     code = installedCode;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/KlassPointer.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/KlassPointer.java	Thu May 28 17:44:05 2015 +0200
@@ -44,8 +44,8 @@
     public static native KlassPointer fromWord(Pointer pointer);
 
     @HotSpotOperation(opcode = READ_KLASS_POINTER)
-    public native KlassPointer readKlassPointer(int secondarySuperCacheOffset, LocationIdentity secondarySuperCacheLocation);
+    public native KlassPointer readKlassPointer(int offset, LocationIdentity locationIdentity);
 
     @Operation(opcode = Opcode.WRITE_POINTER)
-    public native void writeKlassPointer(int secondarySuperCacheOffset, KlassPointer t, LocationIdentity secondarySuperCacheLocation);
+    public native void writeKlassPointer(int offset, KlassPointer t, LocationIdentity locationIdentity);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/MetaspacePointer.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/MetaspacePointer.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,8 +25,8 @@
 import static com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.HeapAccess.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.HeapAccess.*;
 import com.oracle.graal.word.*;
 import com.oracle.graal.word.Word.Opcode;
 import com.oracle.graal.word.Word.Operation;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1257 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.java;
-
-import static com.oracle.graal.api.code.TypeCheckHints.*;
-import static com.oracle.graal.api.meta.DeoptimizationReason.*;
-import static com.oracle.graal.bytecode.Bytecodes.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.bytecode.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.options.*;
-import com.oracle.graal.phases.*;
-
-public abstract class AbstractBytecodeParser {
-
-    public static class Options {
-        // @formatter:off
-        @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug)
-        public static final OptionValue<Integer> TraceBytecodeParserLevel = new OptionValue<>(0);
-
-        @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert)
-        public static final StableOptionValue<Boolean> InlineDuringParsing = new StableOptionValue<>(false);
-
-        @Option(help = "Inlines intrinsic methods during bytecode parsing.", type = OptionType.Expert)
-        public static final StableOptionValue<Boolean> InlineIntrinsicsDuringParsing = new StableOptionValue<>(true);
-
-        @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug)
-        public static final StableOptionValue<Boolean> TraceInlineDuringParsing = new StableOptionValue<>(false);
-
-        @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug)
-        public static final StableOptionValue<Boolean> TraceParserPlugins = new StableOptionValue<>(false);
-
-        @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug)
-        public static final StableOptionValue<Integer> InlineDuringParsingMaxDepth = new StableOptionValue<>(10);
-
-        @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug)
-        public static final StableOptionValue<Boolean> DumpDuringGraphBuilding = new StableOptionValue<>(false);
-
-        @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)
-        public static final OptionValue<Integer> MaximumLoopExplosionCount = new OptionValue<>(10000);
-
-        @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)
-        public static final OptionValue<Boolean> FailedLoopExplosionIsFatal = new OptionValue<>(false);
-
-        // @formatter:on
-    }
-
-    /**
-     * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the
-     * bytecode instructions as they are parsed.
-     */
-    public static final int TRACELEVEL_INSTRUCTIONS = 1;
-
-    /**
-     * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the
-     * frame state before each bytecode instruction as it is parsed.
-     */
-    public static final int TRACELEVEL_STATE = 2;
-
-    protected HIRFrameStateBuilder frameState;
-    protected BciBlock currentBlock;
-
-    protected final BytecodeStream stream;
-    protected final GraphBuilderConfiguration graphBuilderConfig;
-    protected final ResolvedJavaMethod method;
-    protected final ProfilingInfo profilingInfo;
-    protected final OptimisticOptimizations optimisticOpts;
-    protected final ConstantPool constantPool;
-    protected final MetaAccessProvider metaAccess;
-
-    protected final ReplacementContext replacementContext;
-
-    /**
-     * Meters the number of actual bytecodes parsed.
-     */
-    public static final DebugMetric BytecodesParsed = Debug.metric("BytecodesParsed");
-
-    public AbstractBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
-                    ReplacementContext replacementContext) {
-        this.graphBuilderConfig = graphBuilderConfig;
-        this.optimisticOpts = optimisticOpts;
-        this.metaAccess = metaAccess;
-        this.stream = new BytecodeStream(method.getCode());
-        this.profilingInfo = (graphBuilderConfig.getUseProfiling() ? method.getProfilingInfo() : null);
-        this.constantPool = method.getConstantPool();
-        this.method = method;
-        this.replacementContext = replacementContext;
-        assert metaAccess != null;
-    }
-
-    public void setCurrentFrameState(HIRFrameStateBuilder frameState) {
-        this.frameState = frameState;
-    }
-
-    protected final BytecodeStream getStream() {
-        return stream;
-    }
-
-    public int bci() {
-        return stream.currentBCI();
-    }
-
-    public void loadLocal(int index, Kind kind) {
-        frameState.push(kind, frameState.loadLocal(index));
-    }
-
-    public void storeLocal(Kind kind, int index) {
-        ValueNode value;
-        if (kind == Kind.Object) {
-            value = frameState.xpop();
-            // astore and astore_<n> may be used to store a returnAddress (jsr)
-            assert parsingReplacement() || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind();
-        } else {
-            value = frameState.pop(kind);
-        }
-        frameState.storeLocal(index, value, kind);
-    }
-
-    /**
-     * @param type the unresolved type of the constant
-     */
-    protected abstract void handleUnresolvedLoadConstant(JavaType type);
-
-    /**
-     * @param type the unresolved type of the type check
-     * @param object the object value whose type is being checked against {@code type}
-     */
-    protected abstract void handleUnresolvedCheckCast(JavaType type, ValueNode object);
-
-    /**
-     * @param type the unresolved type of the type check
-     * @param object the object value whose type is being checked against {@code type}
-     */
-    protected abstract void handleUnresolvedInstanceOf(JavaType type, ValueNode object);
-
-    /**
-     * @param type the type being instantiated
-     */
-    protected abstract void handleUnresolvedNewInstance(JavaType type);
-
-    /**
-     * @param type the type of the array being instantiated
-     * @param length the length of the array
-     */
-    protected abstract void handleUnresolvedNewObjectArray(JavaType type, ValueNode length);
-
-    /**
-     * @param type the type being instantiated
-     * @param dims the dimensions for the multi-array
-     */
-    protected abstract void handleUnresolvedNewMultiArray(JavaType type, List<ValueNode> dims);
-
-    /**
-     * @param field the unresolved field
-     * @param receiver the object containing the field or {@code null} if {@code field} is static
-     */
-    protected abstract void handleUnresolvedLoadField(JavaField field, ValueNode receiver);
-
-    /**
-     * @param field the unresolved field
-     * @param value the value being stored to the field
-     * @param receiver the object containing the field or {@code null} if {@code field} is static
-     */
-    protected abstract void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver);
-
-    /**
-     * @param type
-     */
-    protected abstract void handleUnresolvedExceptionType(JavaType type);
-
-    // protected abstract void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind);
-
-    // protected abstract DispatchBeginNode handleException(ValueNode exceptionObject, int bci);
-
-    private void genLoadConstant(int cpi, int opcode) {
-        Object con = lookupConstant(cpi, opcode);
-
-        if (con instanceof JavaType) {
-            // this is a load of class constant which might be unresolved
-            JavaType type = (JavaType) con;
-            if (type instanceof ResolvedJavaType) {
-                frameState.push(Kind.Object, appendConstant(((ResolvedJavaType) type).getJavaClass()));
-            } else {
-                handleUnresolvedLoadConstant(type);
-            }
-        } else if (con instanceof JavaConstant) {
-            JavaConstant constant = (JavaConstant) con;
-            frameState.push(constant.getKind().getStackKind(), appendConstant(constant));
-        } else {
-            throw new Error("lookupConstant returned an object of incorrect type");
-        }
-    }
-
-    protected abstract ValueNode genLoadIndexed(ValueNode index, ValueNode array, Kind kind);
-
-    private void genLoadIndexed(Kind kind) {
-        ValueNode index = frameState.ipop();
-        ValueNode array = emitExplicitExceptions(frameState.apop(), index);
-        if (!tryLoadIndexedPlugin(kind, index, array)) {
-            frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind)));
-        }
-    }
-
-    protected abstract void traceWithContext(String format, Object... args);
-
-    protected boolean tryLoadIndexedPlugin(Kind kind, ValueNode index, ValueNode array) {
-        LoadIndexedPlugin loadIndexedPlugin = graphBuilderConfig.getPlugins().getLoadIndexedPlugin();
-        if (loadIndexedPlugin != null && loadIndexedPlugin.apply((GraphBuilderContext) this, array, index, kind)) {
-            if (TraceParserPlugins.getValue()) {
-                traceWithContext("used load indexed plugin");
-            }
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    protected abstract void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value);
-
-    private void genStoreIndexed(Kind kind) {
-        ValueNode value = frameState.pop(kind.getStackKind());
-        ValueNode index = frameState.ipop();
-        ValueNode array = emitExplicitExceptions(frameState.apop(), index);
-        genStoreIndexed(array, index, kind, value);
-    }
-
-    private void stackOp(int opcode) {
-        switch (opcode) {
-            case DUP_X1: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                frameState.xpush(w1);
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                break;
-            }
-            case DUP_X2: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                ValueNode w3 = frameState.xpop();
-                frameState.xpush(w1);
-                frameState.xpush(w3);
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                break;
-            }
-            case DUP2: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                break;
-            }
-            case DUP2_X1: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                ValueNode w3 = frameState.xpop();
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                frameState.xpush(w3);
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                break;
-            }
-            case DUP2_X2: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                ValueNode w3 = frameState.xpop();
-                ValueNode w4 = frameState.xpop();
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                frameState.xpush(w4);
-                frameState.xpush(w3);
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                break;
-            }
-            case SWAP: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                frameState.xpush(w1);
-                frameState.xpush(w2);
-                break;
-            }
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    protected abstract ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genFloatAdd(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
-
-    protected abstract ValueNode genFloatSub(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
-
-    protected abstract ValueNode genFloatMul(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
-
-    protected abstract ValueNode genFloatDiv(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
-
-    protected abstract ValueNode genFloatRem(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
-
-    private void genArithmeticOp(Kind result, int opcode) {
-        ValueNode y = frameState.pop(result);
-        ValueNode x = frameState.pop(result);
-        boolean isStrictFP = method.isStrict();
-        ValueNode v;
-        switch (opcode) {
-            case IADD:
-            case LADD:
-                v = genIntegerAdd(result, x, y);
-                break;
-            case FADD:
-            case DADD:
-                v = genFloatAdd(result, x, y, isStrictFP);
-                break;
-            case ISUB:
-            case LSUB:
-                v = genIntegerSub(result, x, y);
-                break;
-            case FSUB:
-            case DSUB:
-                v = genFloatSub(result, x, y, isStrictFP);
-                break;
-            case IMUL:
-            case LMUL:
-                v = genIntegerMul(result, x, y);
-                break;
-            case FMUL:
-            case DMUL:
-                v = genFloatMul(result, x, y, isStrictFP);
-                break;
-            case FDIV:
-            case DDIV:
-                v = genFloatDiv(result, x, y, isStrictFP);
-                break;
-            case FREM:
-            case DREM:
-                v = genFloatRem(result, x, y, isStrictFP);
-                break;
-            default:
-                throw new GraalInternalError("should not reach");
-        }
-        frameState.push(result, append(v));
-    }
-
-    protected abstract ValueNode genIntegerDiv(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genIntegerRem(Kind kind, ValueNode x, ValueNode y);
-
-    private void genIntegerDivOp(Kind result, int opcode) {
-        ValueNode y = frameState.pop(result);
-        ValueNode x = frameState.pop(result);
-        ValueNode v;
-        switch (opcode) {
-            case IDIV:
-            case LDIV:
-                v = genIntegerDiv(result, x, y);
-                break;
-            case IREM:
-            case LREM:
-                v = genIntegerRem(result, x, y);
-                break;
-            default:
-                throw new GraalInternalError("should not reach");
-        }
-        frameState.push(result, append(v));
-    }
-
-    protected abstract ValueNode genNegateOp(ValueNode x);
-
-    private void genNegateOp(Kind kind) {
-        frameState.push(kind, append(genNegateOp(frameState.pop(kind))));
-    }
-
-    protected abstract ValueNode genLeftShift(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genRightShift(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genUnsignedRightShift(Kind kind, ValueNode x, ValueNode y);
-
-    private void genShiftOp(Kind kind, int opcode) {
-        ValueNode s = frameState.ipop();
-        ValueNode x = frameState.pop(kind);
-        ValueNode v;
-        switch (opcode) {
-            case ISHL:
-            case LSHL:
-                v = genLeftShift(kind, x, s);
-                break;
-            case ISHR:
-            case LSHR:
-                v = genRightShift(kind, x, s);
-                break;
-            case IUSHR:
-            case LUSHR:
-                v = genUnsignedRightShift(kind, x, s);
-                break;
-            default:
-                throw new GraalInternalError("should not reach");
-        }
-        frameState.push(kind, append(v));
-    }
-
-    protected abstract ValueNode genAnd(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genOr(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genXor(Kind kind, ValueNode x, ValueNode y);
-
-    private void genLogicOp(Kind kind, int opcode) {
-        ValueNode y = frameState.pop(kind);
-        ValueNode x = frameState.pop(kind);
-        ValueNode v;
-        switch (opcode) {
-            case IAND:
-            case LAND:
-                v = genAnd(kind, x, y);
-                break;
-            case IOR:
-            case LOR:
-                v = genOr(kind, x, y);
-                break;
-            case IXOR:
-            case LXOR:
-                v = genXor(kind, x, y);
-                break;
-            default:
-                throw new GraalInternalError("should not reach");
-        }
-        frameState.push(kind, append(v));
-    }
-
-    protected abstract ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess);
-
-    private void genCompareOp(Kind kind, boolean isUnorderedLess) {
-        ValueNode y = frameState.pop(kind);
-        ValueNode x = frameState.pop(kind);
-        frameState.ipush(append(genNormalizeCompare(x, y, isUnorderedLess)));
-    }
-
-    protected abstract ValueNode genFloatConvert(FloatConvert op, ValueNode input);
-
-    private void genFloatConvert(FloatConvert op, Kind from, Kind to) {
-        ValueNode input = frameState.pop(from.getStackKind());
-        frameState.push(to.getStackKind(), append(genFloatConvert(op, input)));
-    }
-
-    protected abstract ValueNode genNarrow(ValueNode input, int bitCount);
-
-    protected abstract ValueNode genSignExtend(ValueNode input, int bitCount);
-
-    protected abstract ValueNode genZeroExtend(ValueNode input, int bitCount);
-
-    private void genSignExtend(Kind from, Kind to) {
-        ValueNode input = frameState.pop(from.getStackKind());
-        if (from != from.getStackKind()) {
-            input = append(genNarrow(input, from.getBitCount()));
-        }
-        frameState.push(to.getStackKind(), append(genSignExtend(input, to.getBitCount())));
-    }
-
-    private void genZeroExtend(Kind from, Kind to) {
-        ValueNode input = frameState.pop(from.getStackKind());
-        if (from != from.getStackKind()) {
-            input = append(genNarrow(input, from.getBitCount()));
-        }
-        frameState.push(to.getStackKind(), append(genZeroExtend(input, to.getBitCount())));
-    }
-
-    private void genNarrow(Kind from, Kind to) {
-        ValueNode input = frameState.pop(from.getStackKind());
-        frameState.push(to.getStackKind(), append(genNarrow(input, to.getBitCount())));
-    }
-
-    private void genIncrement() {
-        int index = getStream().readLocalIndex();
-        int delta = getStream().readIncrement();
-        ValueNode x = frameState.loadLocal(index);
-        ValueNode y = appendConstant(JavaConstant.forInt(delta));
-        frameState.storeLocal(index, append(genIntegerAdd(Kind.Int, x, y)));
-    }
-
-    protected abstract void genGoto();
-
-    protected abstract ValueNode genObjectEquals(ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genIntegerEquals(ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genIntegerLessThan(ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genUnique(ValueNode x);
-
-    protected abstract void genIf(ValueNode x, Condition cond, ValueNode y);
-
-    private void genIfZero(Condition cond) {
-        ValueNode y = appendConstant(JavaConstant.INT_0);
-        ValueNode x = frameState.ipop();
-        genIf(x, cond, y);
-    }
-
-    private void genIfNull(Condition cond) {
-        ValueNode y = appendConstant(JavaConstant.NULL_POINTER);
-        ValueNode x = frameState.apop();
-        genIf(x, cond, y);
-    }
-
-    private void genIfSame(Kind kind, Condition cond) {
-        ValueNode y = frameState.pop(kind);
-        ValueNode x = frameState.pop(kind);
-        genIf(x, cond, y);
-    }
-
-    protected abstract void genThrow();
-
-    protected JavaType lookupType(int cpi, int bytecode) {
-        maybeEagerlyResolve(cpi, bytecode);
-        JavaType result = constantPool.lookupType(cpi, bytecode);
-        assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType;
-        return result;
-    }
-
-    private JavaMethod lookupMethod(int cpi, int opcode) {
-        maybeEagerlyResolve(cpi, opcode);
-        JavaMethod result = constantPool.lookupMethod(cpi, opcode);
-        /*
-         * In general, one cannot assume that the declaring class being initialized is useful, since
-         * the actual concrete receiver may be a different class (except for static calls). Also,
-         * interfaces are initialized only under special circumstances, so that this assertion would
-         * often fail for interface calls.
-         */
-        assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result;
-        return result;
-    }
-
-    private JavaField lookupField(int cpi, int opcode) {
-        maybeEagerlyResolve(cpi, opcode);
-        JavaField result = constantPool.lookupField(cpi, opcode);
-        assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
-        return result;
-    }
-
-    private Object lookupConstant(int cpi, int opcode) {
-        maybeEagerlyResolve(cpi, opcode);
-        Object result = constantPool.lookupConstant(cpi);
-        assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result;
-        return result;
-    }
-
-    private void maybeEagerlyResolve(int cpi, int bytecode) {
-        if (graphBuilderConfig.eagerResolving() || replacementContext instanceof IntrinsicContext) {
-            constantPool.loadReferencedType(cpi, bytecode);
-        }
-    }
-
-    private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) {
-        if (parsingReplacement() || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
-            return null;
-        } else {
-            return profilingInfo.getTypeProfile(bci());
-        }
-    }
-
-    protected abstract ValueNode createCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck);
-
-    private void genCheckCast() {
-        int cpi = getStream().readCPI();
-        JavaType type = lookupType(cpi, CHECKCAST);
-        ValueNode object = frameState.apop();
-        if (type instanceof ResolvedJavaType) {
-            ResolvedJavaType resolvedType = (ResolvedJavaType) type;
-            JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
-            TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin();
-            if (typeCheckPlugin == null || !typeCheckPlugin.checkCast((GraphBuilderContext) this, object, resolvedType, profile)) {
-                ValueNode checkCastNode = append(createCheckCast(resolvedType, object, profile, false));
-                frameState.apush(checkCastNode);
-            }
-        } else {
-            handleUnresolvedCheckCast(type, object);
-        }
-    }
-
-    protected abstract ValueNode createInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck);
-
-    protected abstract ValueNode genConditional(ValueNode x);
-
-    private void genInstanceOf() {
-        int cpi = getStream().readCPI();
-        JavaType type = lookupType(cpi, INSTANCEOF);
-        ValueNode object = frameState.apop();
-        if (type instanceof ResolvedJavaType) {
-            ResolvedJavaType resolvedType = (ResolvedJavaType) type;
-            JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
-            TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin();
-            if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf((GraphBuilderContext) this, object, resolvedType, profile)) {
-                ValueNode instanceOfNode = createInstanceOf(resolvedType, object, profile);
-                frameState.ipush(append(genConditional(genUnique(instanceOfNode))));
-            }
-        } else {
-            handleUnresolvedInstanceOf(type, object);
-        }
-    }
-
-    protected abstract ValueNode createNewInstance(ResolvedJavaType type, boolean fillContents);
-
-    void genNewInstance(int cpi) {
-        JavaType type = lookupType(cpi, NEW);
-        if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
-            ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes();
-            if (skippedExceptionTypes != null) {
-                for (ResolvedJavaType exceptionType : skippedExceptionTypes) {
-                    if (exceptionType.isAssignableFrom((ResolvedJavaType) type)) {
-                        append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter));
-                        return;
-                    }
-                }
-            }
-            frameState.apush(append(createNewInstance((ResolvedJavaType) type, true)));
-        } else {
-            handleUnresolvedNewInstance(type);
-        }
-    }
-
-    /**
-     * Gets the kind of array elements for the array type code that appears in a
-     * {@link Bytecodes#NEWARRAY} bytecode.
-     *
-     * @param code the array type code
-     * @return the kind from the array type code
-     */
-    public static Class<?> arrayTypeCodeToClass(int code) {
-        // Checkstyle: stop
-        switch (code) {
-            case 4:
-                return boolean.class;
-            case 5:
-                return char.class;
-            case 6:
-                return float.class;
-            case 7:
-                return double.class;
-            case 8:
-                return byte.class;
-            case 9:
-                return short.class;
-            case 10:
-                return int.class;
-            case 11:
-                return long.class;
-            default:
-                throw new IllegalArgumentException("unknown array type code: " + code);
-        }
-        // Checkstyle: resume
-    }
-
-    private void genNewPrimitiveArray(int typeCode) {
-        Class<?> clazz = arrayTypeCodeToClass(typeCode);
-        ResolvedJavaType elementType = metaAccess.lookupJavaType(clazz);
-        frameState.apush(append(createNewArray(elementType, frameState.ipop(), true)));
-    }
-
-    private void genNewObjectArray(int cpi) {
-        JavaType type = lookupType(cpi, ANEWARRAY);
-        ValueNode length = frameState.ipop();
-        if (type instanceof ResolvedJavaType) {
-            frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true)));
-        } else {
-            handleUnresolvedNewObjectArray(type, length);
-        }
-
-    }
-
-    protected abstract ValueNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents);
-
-    private void genNewMultiArray(int cpi) {
-        JavaType type = lookupType(cpi, MULTIANEWARRAY);
-        int rank = getStream().readUByte(bci() + 3);
-        List<ValueNode> dims = new ArrayList<>(Collections.nCopies(rank, null));
-        for (int i = rank - 1; i >= 0; i--) {
-            dims.set(i, frameState.ipop());
-        }
-        if (type instanceof ResolvedJavaType) {
-            frameState.apush(append(createNewMultiArray((ResolvedJavaType) type, dims)));
-        } else {
-            handleUnresolvedNewMultiArray(type, dims);
-        }
-    }
-
-    protected abstract ValueNode createNewMultiArray(ResolvedJavaType type, List<ValueNode> dims);
-
-    protected abstract ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field);
-
-    private void genGetField(JavaField field) {
-        Kind kind = field.getKind();
-        ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
-        if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
-            if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) {
-                appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
-            }
-        } else {
-            handleUnresolvedLoadField(field, receiver);
-        }
-    }
-
-    /**
-     * Emits control flow to null check a receiver if it's stamp does not indicate it is
-     * {@linkplain StampTool#isPointerNonNull always non-null}.
-     *
-     * @return the receiver with a stamp indicating non-nullness
-     */
-    protected abstract ValueNode emitExplicitNullCheck(ValueNode receiver);
-
-    /**
-     * Emits control flow to check an array index is within bounds of an array's length.
-     *
-     * @param index the index to check
-     * @param length the length of the array being indexed
-     */
-    protected abstract void emitExplicitBoundsCheck(ValueNode index, ValueNode length);
-
-    private static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions");
-
-    protected abstract ValueNode genArrayLength(ValueNode x);
-
-    /**
-     * @param receiver the receiver of an object based operation
-     * @param index the index of an array based operation that is to be tested for out of bounds.
-     *            This is null for a non-array operation.
-     * @return the receiver value possibly modified to have a tighter stamp
-     */
-    protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) {
-        assert receiver != null;
-        if (graphBuilderConfig.omitAllExceptionEdges() || profilingInfo == null ||
-                        (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) {
-            return receiver;
-        }
-
-        ValueNode nonNullReceiver = emitExplicitNullCheck(receiver);
-        if (index != null) {
-            ValueNode length = append(genArrayLength(nonNullReceiver));
-            emitExplicitBoundsCheck(index, length);
-        }
-        EXPLICIT_EXCEPTIONS.increment();
-        return nonNullReceiver;
-    }
-
-    protected abstract void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value);
-
-    private void genPutField(JavaField field) {
-        ValueNode value = frameState.pop(field.getKind().getStackKind());
-        ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
-        if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            genStoreField(receiver, (ResolvedJavaField) field, value);
-        } else {
-            handleUnresolvedStoreField(field, value, receiver);
-        }
-    }
-
-    private void genGetStatic(JavaField field) {
-        Kind kind = field.getKind();
-        if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
-            if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field)) {
-                appendOptimizedLoadField(kind, genLoadField(null, (ResolvedJavaField) field));
-            }
-        } else {
-            handleUnresolvedLoadField(field, null);
-        }
-    }
-
-    public boolean tryLoadFieldPlugin(JavaField field, LoadFieldPlugin loadFieldPlugin) {
-        return loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field);
-    }
-
-    private void genPutStatic(JavaField field) {
-        ValueNode value = frameState.pop(field.getKind().getStackKind());
-        if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            genStoreField(null, (ResolvedJavaField) field, value);
-        } else {
-            handleUnresolvedStoreField(field, value, null);
-        }
-    }
-
-    protected void appendOptimizedLoadField(Kind kind, ValueNode load) {
-        // append the load to the instruction
-        ValueNode optimized = append(load);
-        frameState.push(kind.getStackKind(), optimized);
-    }
-
-    protected abstract void genInvokeStatic(JavaMethod target);
-
-    protected abstract void genInvokeInterface(JavaMethod target);
-
-    protected abstract void genInvokeDynamic(JavaMethod target);
-
-    protected abstract void genInvokeVirtual(JavaMethod target);
-
-    protected abstract void genInvokeSpecial(JavaMethod target);
-
-    protected abstract void genReturn(ValueNode x, Kind kind);
-
-    protected abstract void genMonitorEnter(ValueNode x, int bci);
-
-    protected abstract void genMonitorExit(ValueNode x, ValueNode returnValue, int bci);
-
-    protected abstract void genJsr(int dest);
-
-    protected abstract void genRet(int localIndex);
-
-    private double[] switchProbability(int numberOfCases, int bci) {
-        double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci));
-        if (prob != null) {
-            assert prob.length == numberOfCases;
-        } else {
-            Debug.log("Missing probability (switch) in %s at bci %d", method, bci);
-            prob = new double[numberOfCases];
-            for (int i = 0; i < numberOfCases; i++) {
-                prob[i] = 1.0d / numberOfCases;
-            }
-        }
-        assert allPositive(prob);
-        return prob;
-    }
-
-    private static boolean allPositive(double[] a) {
-        for (double d : a) {
-            if (d < 0) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Helper function that sums up the probabilities of all keys that lead to a specific successor.
-     *
-     * @return an array of size successorCount with the accumulated probability for each successor.
-     */
-    public static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) {
-        double[] probability = new double[successorCount];
-        for (int i = 0; i < keySuccessors.length; i++) {
-            probability[keySuccessors[i]] += keyProbabilities[i];
-        }
-        return probability;
-    }
-
-    private void genSwitch(BytecodeSwitch bs) {
-        int bci = bci();
-        ValueNode value = frameState.ipop();
-
-        int nofCases = bs.numberOfCases();
-        double[] keyProbabilities = switchProbability(nofCases + 1, bci);
-
-        Map<Integer, SuccessorInfo> bciToBlockSuccessorIndex = new HashMap<>();
-        for (int i = 0; i < currentBlock.getSuccessorCount(); i++) {
-            assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci);
-            if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) {
-                bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i));
-            }
-        }
-
-        ArrayList<BciBlock> actualSuccessors = new ArrayList<>();
-        int[] keys = new int[nofCases];
-        int[] keySuccessors = new int[nofCases + 1];
-        int deoptSuccessorIndex = -1;
-        int nextSuccessorIndex = 0;
-        boolean constantValue = value.isConstant();
-        for (int i = 0; i < nofCases + 1; i++) {
-            if (i < nofCases) {
-                keys[i] = bs.keyAt(i);
-            }
-
-            if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) {
-                if (deoptSuccessorIndex < 0) {
-                    deoptSuccessorIndex = nextSuccessorIndex++;
-                    actualSuccessors.add(null);
-                }
-                keySuccessors[i] = deoptSuccessorIndex;
-            } else {
-                int targetBci = i >= nofCases ? bs.defaultTarget() : bs.targetAt(i);
-                SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci);
-                if (info.actualIndex < 0) {
-                    info.actualIndex = nextSuccessorIndex++;
-                    actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex));
-                }
-                keySuccessors[i] = info.actualIndex;
-            }
-        }
-
-        genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors);
-
-    }
-
-    protected abstract void genIntegerSwitch(ValueNode value, ArrayList<BciBlock> actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors);
-
-    private static class SuccessorInfo {
-
-        int blockIndex;
-        int actualIndex;
-
-        public SuccessorInfo(int blockSuccessorIndex) {
-            this.blockIndex = blockSuccessorIndex;
-            actualIndex = -1;
-        }
-    }
-
-    protected abstract ValueNode appendConstant(JavaConstant constant);
-
-    protected abstract <T extends ValueNode> T append(T v);
-
-    protected boolean isNeverExecutedCode(double probability) {
-        return probability == 0 && optimisticOpts.removeNeverExecutedCode();
-    }
-
-    protected double branchProbability() {
-        if (profilingInfo == null) {
-            return 0.5;
-        }
-        assert assertAtIfBytecode();
-        double probability = profilingInfo.getBranchTakenProbability(bci());
-        if (probability < 0) {
-            assert probability == -1 : "invalid probability";
-            Debug.log("missing probability in %s at bci %d", method, bci());
-            probability = 0.5;
-        }
-
-        if (!optimisticOpts.removeNeverExecutedCode()) {
-            if (probability == 0) {
-                probability = 0.0000001;
-            } else if (probability == 1) {
-                probability = 0.999999;
-            }
-        }
-        return probability;
-    }
-
-    private boolean assertAtIfBytecode() {
-        int bytecode = stream.currentBC();
-        switch (bytecode) {
-            case IFEQ:
-            case IFNE:
-            case IFLT:
-            case IFGE:
-            case IFGT:
-            case IFLE:
-            case IF_ICMPEQ:
-            case IF_ICMPNE:
-            case IF_ICMPLT:
-            case IF_ICMPGE:
-            case IF_ICMPGT:
-            case IF_ICMPLE:
-            case IF_ACMPEQ:
-            case IF_ACMPNE:
-            case IFNULL:
-            case IFNONNULL:
-                return true;
-        }
-        assert false : String.format("%x is not an if bytecode", bytecode);
-        return true;
-    }
-
-    protected abstract void iterateBytecodesForBlock(BciBlock block);
-
-    public final void processBytecode(int bci, int opcode) {
-        int cpi;
-
-        // Checkstyle: stop
-        // @formatter:off
-        switch (opcode) {
-            case NOP            : /* nothing to do */ break;
-            case ACONST_NULL    : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break;
-            case ICONST_M1      : // fall through
-            case ICONST_0       : // fall through
-            case ICONST_1       : // fall through
-            case ICONST_2       : // fall through
-            case ICONST_3       : // fall through
-            case ICONST_4       : // fall through
-            case ICONST_5       : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break;
-            case LCONST_0       : // fall through
-            case LCONST_1       : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break;
-            case FCONST_0       : // fall through
-            case FCONST_1       : // fall through
-            case FCONST_2       : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break;
-            case DCONST_0       : // fall through
-            case DCONST_1       : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break;
-            case BIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break;
-            case SIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break;
-            case LDC            : // fall through
-            case LDC_W          : // fall through
-            case LDC2_W         : genLoadConstant(stream.readCPI(), opcode); break;
-            case ILOAD          : loadLocal(stream.readLocalIndex(), Kind.Int); break;
-            case LLOAD          : loadLocal(stream.readLocalIndex(), Kind.Long); break;
-            case FLOAD          : loadLocal(stream.readLocalIndex(), Kind.Float); break;
-            case DLOAD          : loadLocal(stream.readLocalIndex(), Kind.Double); break;
-            case ALOAD          : loadLocal(stream.readLocalIndex(), Kind.Object); break;
-            case ILOAD_0        : // fall through
-            case ILOAD_1        : // fall through
-            case ILOAD_2        : // fall through
-            case ILOAD_3        : loadLocal(opcode - ILOAD_0, Kind.Int); break;
-            case LLOAD_0        : // fall through
-            case LLOAD_1        : // fall through
-            case LLOAD_2        : // fall through
-            case LLOAD_3        : loadLocal(opcode - LLOAD_0, Kind.Long); break;
-            case FLOAD_0        : // fall through
-            case FLOAD_1        : // fall through
-            case FLOAD_2        : // fall through
-            case FLOAD_3        : loadLocal(opcode - FLOAD_0, Kind.Float); break;
-            case DLOAD_0        : // fall through
-            case DLOAD_1        : // fall through
-            case DLOAD_2        : // fall through
-            case DLOAD_3        : loadLocal(opcode - DLOAD_0, Kind.Double); break;
-            case ALOAD_0        : // fall through
-            case ALOAD_1        : // fall through
-            case ALOAD_2        : // fall through
-            case ALOAD_3        : loadLocal(opcode - ALOAD_0, Kind.Object); break;
-            case IALOAD         : genLoadIndexed(Kind.Int   ); break;
-            case LALOAD         : genLoadIndexed(Kind.Long  ); break;
-            case FALOAD         : genLoadIndexed(Kind.Float ); break;
-            case DALOAD         : genLoadIndexed(Kind.Double); break;
-            case AALOAD         : genLoadIndexed(Kind.Object); break;
-            case BALOAD         : genLoadIndexed(Kind.Byte  ); break;
-            case CALOAD         : genLoadIndexed(Kind.Char  ); break;
-            case SALOAD         : genLoadIndexed(Kind.Short ); break;
-            case ISTORE         : storeLocal(Kind.Int, stream.readLocalIndex()); break;
-            case LSTORE         : storeLocal(Kind.Long, stream.readLocalIndex()); break;
-            case FSTORE         : storeLocal(Kind.Float, stream.readLocalIndex()); break;
-            case DSTORE         : storeLocal(Kind.Double, stream.readLocalIndex()); break;
-            case ASTORE         : storeLocal(Kind.Object, stream.readLocalIndex()); break;
-            case ISTORE_0       : // fall through
-            case ISTORE_1       : // fall through
-            case ISTORE_2       : // fall through
-            case ISTORE_3       : storeLocal(Kind.Int, opcode - ISTORE_0); break;
-            case LSTORE_0       : // fall through
-            case LSTORE_1       : // fall through
-            case LSTORE_2       : // fall through
-            case LSTORE_3       : storeLocal(Kind.Long, opcode - LSTORE_0); break;
-            case FSTORE_0       : // fall through
-            case FSTORE_1       : // fall through
-            case FSTORE_2       : // fall through
-            case FSTORE_3       : storeLocal(Kind.Float, opcode - FSTORE_0); break;
-            case DSTORE_0       : // fall through
-            case DSTORE_1       : // fall through
-            case DSTORE_2       : // fall through
-            case DSTORE_3       : storeLocal(Kind.Double, opcode - DSTORE_0); break;
-            case ASTORE_0       : // fall through
-            case ASTORE_1       : // fall through
-            case ASTORE_2       : // fall through
-            case ASTORE_3       : storeLocal(Kind.Object, opcode - ASTORE_0); break;
-            case IASTORE        : genStoreIndexed(Kind.Int   ); break;
-            case LASTORE        : genStoreIndexed(Kind.Long  ); break;
-            case FASTORE        : genStoreIndexed(Kind.Float ); break;
-            case DASTORE        : genStoreIndexed(Kind.Double); break;
-            case AASTORE        : genStoreIndexed(Kind.Object); break;
-            case BASTORE        : genStoreIndexed(Kind.Byte  ); break;
-            case CASTORE        : genStoreIndexed(Kind.Char  ); break;
-            case SASTORE        : genStoreIndexed(Kind.Short ); break;
-            case POP            : frameState.xpop(); break;
-            case POP2           : frameState.xpop(); frameState.xpop(); break;
-            case DUP            : frameState.xpush(frameState.xpeek()); break;
-            case DUP_X1         : // fall through
-            case DUP_X2         : // fall through
-            case DUP2           : // fall through
-            case DUP2_X1        : // fall through
-            case DUP2_X2        : // fall through
-            case SWAP           : stackOp(opcode); break;
-            case IADD           : // fall through
-            case ISUB           : // fall through
-            case IMUL           : genArithmeticOp(Kind.Int, opcode); break;
-            case IDIV           : // fall through
-            case IREM           : genIntegerDivOp(Kind.Int, opcode); break;
-            case LADD           : // fall through
-            case LSUB           : // fall through
-            case LMUL           : genArithmeticOp(Kind.Long, opcode); break;
-            case LDIV           : // fall through
-            case LREM           : genIntegerDivOp(Kind.Long, opcode); break;
-            case FADD           : // fall through
-            case FSUB           : // fall through
-            case FMUL           : // fall through
-            case FDIV           : // fall through
-            case FREM           : genArithmeticOp(Kind.Float, opcode); break;
-            case DADD           : // fall through
-            case DSUB           : // fall through
-            case DMUL           : // fall through
-            case DDIV           : // fall through
-            case DREM           : genArithmeticOp(Kind.Double, opcode); break;
-            case INEG           : genNegateOp(Kind.Int); break;
-            case LNEG           : genNegateOp(Kind.Long); break;
-            case FNEG           : genNegateOp(Kind.Float); break;
-            case DNEG           : genNegateOp(Kind.Double); break;
-            case ISHL           : // fall through
-            case ISHR           : // fall through
-            case IUSHR          : genShiftOp(Kind.Int, opcode); break;
-            case IAND           : // fall through
-            case IOR            : // fall through
-            case IXOR           : genLogicOp(Kind.Int, opcode); break;
-            case LSHL           : // fall through
-            case LSHR           : // fall through
-            case LUSHR          : genShiftOp(Kind.Long, opcode); break;
-            case LAND           : // fall through
-            case LOR            : // fall through
-            case LXOR           : genLogicOp(Kind.Long, opcode); break;
-            case IINC           : genIncrement(); break;
-            case I2F            : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break;
-            case I2D            : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break;
-            case L2F            : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break;
-            case L2D            : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break;
-            case F2I            : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break;
-            case F2L            : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break;
-            case F2D            : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break;
-            case D2I            : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break;
-            case D2L            : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break;
-            case D2F            : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break;
-            case L2I            : genNarrow(Kind.Long, Kind.Int); break;
-            case I2L            : genSignExtend(Kind.Int, Kind.Long); break;
-            case I2B            : genSignExtend(Kind.Byte, Kind.Int); break;
-            case I2S            : genSignExtend(Kind.Short, Kind.Int); break;
-            case I2C            : genZeroExtend(Kind.Char, Kind.Int); break;
-            case LCMP           : genCompareOp(Kind.Long, false); break;
-            case FCMPL          : genCompareOp(Kind.Float, true); break;
-            case FCMPG          : genCompareOp(Kind.Float, false); break;
-            case DCMPL          : genCompareOp(Kind.Double, true); break;
-            case DCMPG          : genCompareOp(Kind.Double, false); break;
-            case IFEQ           : genIfZero(Condition.EQ); break;
-            case IFNE           : genIfZero(Condition.NE); break;
-            case IFLT           : genIfZero(Condition.LT); break;
-            case IFGE           : genIfZero(Condition.GE); break;
-            case IFGT           : genIfZero(Condition.GT); break;
-            case IFLE           : genIfZero(Condition.LE); break;
-            case IF_ICMPEQ      : genIfSame(Kind.Int, Condition.EQ); break;
-            case IF_ICMPNE      : genIfSame(Kind.Int, Condition.NE); break;
-            case IF_ICMPLT      : genIfSame(Kind.Int, Condition.LT); break;
-            case IF_ICMPGE      : genIfSame(Kind.Int, Condition.GE); break;
-            case IF_ICMPGT      : genIfSame(Kind.Int, Condition.GT); break;
-            case IF_ICMPLE      : genIfSame(Kind.Int, Condition.LE); break;
-            case IF_ACMPEQ      : genIfSame(Kind.Object, Condition.EQ); break;
-            case IF_ACMPNE      : genIfSame(Kind.Object, Condition.NE); break;
-            case GOTO           : genGoto(); break;
-            case JSR            : genJsr(stream.readBranchDest()); break;
-            case RET            : genRet(stream.readLocalIndex()); break;
-            case TABLESWITCH    : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break;
-            case LOOKUPSWITCH   : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break;
-            case IRETURN        : genReturn(frameState.ipop(), Kind.Int); break;
-            case LRETURN        : genReturn(frameState.lpop(), Kind.Long); break;
-            case FRETURN        : genReturn(frameState.fpop(), Kind.Float); break;
-            case DRETURN        : genReturn(frameState.dpop(), Kind.Double); break;
-            case ARETURN        : genReturn(frameState.apop(), Kind.Object); break;
-            case RETURN         : genReturn(null, Kind.Void); break;
-            case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break;
-            case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break;
-            case GETFIELD       : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break;
-            case PUTFIELD       : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break;
-            case INVOKEVIRTUAL  : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break;
-            case INVOKESPECIAL  : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break;
-            case INVOKESTATIC   : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break;
-            case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break;
-            case INVOKEDYNAMIC  : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break;
-            case NEW            : genNewInstance(stream.readCPI()); break;
-            case NEWARRAY       : genNewPrimitiveArray(stream.readLocalIndex()); break;
-            case ANEWARRAY      : genNewObjectArray(stream.readCPI()); break;
-            case ARRAYLENGTH    : genArrayLength(); break;
-            case ATHROW         : genThrow(); break;
-            case CHECKCAST      : genCheckCast(); break;
-            case INSTANCEOF     : genInstanceOf(); break;
-            case MONITORENTER   : genMonitorEnter(frameState.apop(), stream.nextBCI()); break;
-            case MONITOREXIT    : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break;
-            case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break;
-            case IFNULL         : genIfNull(Condition.EQ); break;
-            case IFNONNULL      : genIfNull(Condition.NE); break;
-            case GOTO_W         : genGoto(); break;
-            case JSR_W          : genJsr(stream.readBranchDest()); break;
-            case BREAKPOINT:
-                throw new BailoutException("concurrent setting of breakpoint");
-            default:
-                throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci);
-        }
-        // @formatter:on
-        // Checkstyle: resume
-    }
-
-    private void genArrayLength() {
-        frameState.ipush(append(genArrayLength(frameState.apop())));
-    }
-
-    public ResolvedJavaMethod getMethod() {
-        return method;
-    }
-
-    public HIRFrameStateBuilder getFrameState() {
-        return frameState;
-    }
-
-    protected boolean traceInstruction(int bci, int opcode, boolean blockStart) {
-        if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) {
-            traceInstructionHelper(bci, opcode, blockStart);
-        }
-        return true;
-    }
-
-    private void traceInstructionHelper(int bci, int opcode, boolean blockStart) {
-        StringBuilder sb = new StringBuilder(40);
-        sb.append(blockStart ? '+' : '|');
-        if (bci < 10) {
-            sb.append("  ");
-        } else if (bci < 100) {
-            sb.append(' ');
-        }
-        sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode));
-        for (int i = bci + 1; i < stream.nextBCI(); ++i) {
-            sb.append(' ').append(stream.readUByte(i));
-        }
-        if (!currentBlock.getJsrScope().isEmpty()) {
-            sb.append(' ').append(currentBlock.getJsrScope());
-        }
-        Debug.log("%s", sb);
-    }
-
-    public boolean parsingReplacement() {
-        return replacementContext != null;
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,451 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.java;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
-
-public abstract class AbstractFrameStateBuilder<T extends KindProvider, S extends AbstractFrameStateBuilder<T, S>> {
-
-    protected final ResolvedJavaMethod method;
-    protected int stackSize;
-    protected final T[] locals;
-    protected final T[] stack;
-    protected T[] lockedObjects;
-
-    protected final BytecodeParser parser;
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    protected boolean rethrowException;
-
-    public AbstractFrameStateBuilder(ResolvedJavaMethod method, BytecodeParser parser) {
-        this.method = method;
-        this.parser = parser;
-        this.locals = allocateArray(method.getMaxLocals());
-        this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
-        this.lockedObjects = allocateArray(0);
-    }
-
-    protected AbstractFrameStateBuilder(S other) {
-        this.method = other.method;
-        this.parser = other.parser;
-        this.stackSize = other.stackSize;
-        this.locals = other.locals.clone();
-        this.stack = other.stack.clone();
-        this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
-        this.rethrowException = other.rethrowException;
-
-        assert locals.length == method.getMaxLocals();
-        assert stack.length == Math.max(1, method.getMaxStackSize());
-    }
-
-    public abstract S copy();
-
-    protected abstract T[] allocateArray(int length);
-
-    public abstract boolean isCompatibleWith(S other);
-
-    public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
-        /*
-         * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
-         * remove it for normal compilations, but not for OSR compilations - otherwise dead object
-         * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
-         * Kind.Illegal, because the conflicting branch might not have been parsed.
-         */
-        if (liveness == null) {
-            return;
-        }
-        if (liveIn) {
-            for (int i = 0; i < locals.length; i++) {
-                if (!liveness.localIsLiveIn(block, i)) {
-                    locals[i] = null;
-                }
-            }
-        } else {
-            for (int i = 0; i < locals.length; i++) {
-                if (!liveness.localIsLiveOut(block, i)) {
-                    locals[i] = null;
-                }
-            }
-        }
-    }
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    public boolean rethrowException() {
-        return rethrowException;
-    }
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    public void setRethrowException(boolean b) {
-        rethrowException = b;
-    }
-
-    /**
-     * Returns the size of the local variables.
-     *
-     * @return the size of the local variables
-     */
-    public int localsSize() {
-        return locals.length;
-    }
-
-    /**
-     * Gets the current size (height) of the stack.
-     */
-    public int stackSize() {
-        return stackSize;
-    }
-
-    /**
-     * @return the current lock depth
-     */
-    public int lockDepth() {
-        return lockedObjects.length;
-    }
-
-    /**
-     * Gets the value in the local variables at the specified index, without any sanity checking.
-     *
-     * @param i the index into the locals
-     * @return the instruction that produced the value for the specified local
-     */
-    public T localAt(int i) {
-        return locals[i];
-    }
-
-    /**
-     * Get the value on the stack at the specified stack index.
-     *
-     * @param i the index into the stack, with {@code 0} being the bottom of the stack
-     * @return the instruction at the specified position in the stack
-     */
-    public T stackAt(int i) {
-        return stack[i];
-    }
-
-    /**
-     * Gets the value in the lock at the specified index, without any sanity checking.
-     *
-     * @param i the index into the lock
-     * @return the instruction that produced the value for the specified lock
-     */
-    public T lockAt(int i) {
-        return lockedObjects[i];
-    }
-
-    public void storeLock(int i, T lock) {
-        lockedObjects[i] = lock;
-    }
-
-    /**
-     * Loads the local variable at the specified index, checking that the returned value is non-null
-     * and that two-stack values are properly handled.
-     *
-     * @param i the index of the local variable to load
-     * @return the instruction that produced the specified local
-     */
-    public T loadLocal(int i) {
-        T x = locals[i];
-        assert x != null : i;
-        assert parser.parsingReplacement() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
-        assert parser.parsingReplacement() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
-        return x;
-    }
-
-    public void storeLocal(int i, T x) {
-        storeLocal(i, x, x == null ? null : x.getKind());
-    }
-
-    /**
-     * Stores a given local variable at the specified index. If the value occupies two slots, then
-     * the next local variable index is also overwritten.
-     *
-     * @param i the index at which to store
-     * @param x the instruction which produces the value for the local
-     */
-    public void storeLocal(int i, T x, Kind kind) {
-        assert x == null || parser.parsingReplacement() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
-        locals[i] = x;
-        if (x != null) {
-            if (kind.needsTwoSlots() && !parser.parsingReplacement()) {
-                // if this is a double word, then kill i+1
-                locals[i + 1] = null;
-            }
-            if (i > 0 && !parser.parsingReplacement()) {
-                T p = locals[i - 1];
-                if (p != null && p.getKind().needsTwoSlots()) {
-                    // if there was a double word at i - 1, then kill it
-                    locals[i - 1] = null;
-                }
-            }
-        }
-    }
-
-    public void storeStack(int i, T x) {
-        assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values";
-        stack[i] = x;
-    }
-
-    /**
-     * Pushes an instruction onto the stack with the expected type.
-     *
-     * @param kind the type expected for this instruction
-     * @param x the instruction to push onto the stack
-     */
-    public void push(Kind kind, T x) {
-        assert kind != Kind.Void && kind != Kind.Illegal : kind + ":" + x;
-        xpush(assertKind(kind, x));
-        if (kind.needsTwoSlots()) {
-            xpush(null);
-        }
-    }
-
-    /**
-     * Pushes a value onto the stack without checking the type.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void xpush(T x) {
-        assert parser.parsingReplacement() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
-        stack[stackSize++] = x;
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an int.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void ipush(T x) {
-        xpush(assertInt(x));
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a float.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void fpush(T x) {
-        xpush(assertFloat(x));
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an object.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void apush(T x) {
-        xpush(assertObject(x));
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a long.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void lpush(T x) {
-        xpush(assertLong(x));
-        xpush(null);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a double.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void dpush(T x) {
-        xpush(assertDouble(x));
-        xpush(null);
-    }
-
-    public void pushReturn(Kind kind, T x) {
-        if (kind != Kind.Void) {
-            push(kind.getStackKind(), x);
-        }
-    }
-
-    /**
-     * Pops an instruction off the stack with the expected type.
-     *
-     * @param kind the expected type
-     * @return the instruction on the top of the stack
-     */
-    public T pop(Kind kind) {
-        assert kind != Kind.Void;
-        if (kind.needsTwoSlots()) {
-            xpop();
-        }
-        return assertKind(kind, xpop());
-    }
-
-    /**
-     * Pops a value off of the stack without checking the type.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T xpop() {
-        T result = stack[--stackSize];
-        return result;
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is an int.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T ipop() {
-        return assertInt(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a float.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T fpop() {
-        return assertFloat(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is an object.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T apop() {
-        return assertObject(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a long.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T lpop() {
-        assertHigh(xpop());
-        return assertLong(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a double.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T dpop() {
-        assertHigh(xpop());
-        return assertDouble(xpop());
-    }
-
-    /**
-     * Pop the specified number of slots off of this stack and return them as an array of
-     * instructions.
-     *
-     * @return an array containing the arguments off of the stack
-     */
-    public T[] popArguments(int argSize) {
-        T[] result = allocateArray(argSize);
-        int newStackSize = stackSize;
-        for (int i = argSize - 1; i >= 0; i--) {
-            newStackSize--;
-            if (stack[newStackSize] == null) {
-                /* Two-slot value. */
-                newStackSize--;
-                assert stack[newStackSize].getKind().needsTwoSlots();
-            } else {
-                assert parser.parsingReplacement() || (stack[newStackSize].getKind().getSlotCount() == 1);
-            }
-            result[i] = stack[newStackSize];
-        }
-        stackSize = newStackSize;
-        return result;
-    }
-
-    /**
-     * Peeks an element from the operand stack.
-     *
-     * @param argumentNumber The number of the argument, relative from the top of the stack (0 =
-     *            top). Long and double arguments only count as one argument, i.e., null-slots are
-     *            ignored.
-     * @return The peeked argument.
-     */
-    public T peek(int argumentNumber) {
-        int idx = stackSize() - 1;
-        for (int i = 0; i < argumentNumber; i++) {
-            if (stackAt(idx) == null) {
-                idx--;
-                assert stackAt(idx).getKind().needsTwoSlots();
-            }
-            idx--;
-        }
-        return stackAt(idx);
-    }
-
-    /**
-     * Clears all values on this stack.
-     */
-    public void clearStack() {
-        stackSize = 0;
-    }
-
-    private T assertKind(Kind kind, T x) {
-        assert x != null && (parser.parsingReplacement() || x.getKind() == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind());
-        return x;
-    }
-
-    private T assertLong(T x) {
-        assert x != null && (x.getKind() == Kind.Long);
-        return x;
-    }
-
-    private T assertInt(T x) {
-        assert x != null && (x.getKind() == Kind.Int);
-        return x;
-    }
-
-    private T assertFloat(T x) {
-        assert x != null && (x.getKind() == Kind.Float);
-        return x;
-    }
-
-    private T assertObject(T x) {
-        assert x != null && (parser.parsingReplacement() || (x.getKind() == Kind.Object));
-        return x;
-    }
-
-    private T assertDouble(T x) {
-        assert x != null && (x.getKind() == Kind.Double);
-        return x;
-    }
-
-    private void assertHigh(T x) {
-        assert x == null;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,1036 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import static com.oracle.graal.graph.iterators.NodePredicates.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graphbuilderconf.IntrinsicContext.SideEffectsState;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.util.*;
+
+public final class FrameStateBuilder implements SideEffectsState {
+
+    static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
+    static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
+
+    protected final BytecodeParser parser;
+    protected final ResolvedJavaMethod method;
+    protected int stackSize;
+    protected final ValueNode[] locals;
+    protected final ValueNode[] stack;
+    protected ValueNode[] lockedObjects;
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    protected boolean rethrowException;
+
+    private MonitorIdNode[] monitorIds;
+    private final StructuredGraph graph;
+    private FrameState outerFrameState;
+
+    /**
+     * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more
+     * than one when the current block contains no side-effects but merging predecessor blocks do.
+     */
+    protected List<StateSplit> sideEffects;
+
+    /**
+     * Creates a new frame state builder for the given method and the given target graph.
+     *
+     * @param method the method whose frame is simulated
+     * @param graph the target graph of Graal nodes created by the builder
+     */
+    public FrameStateBuilder(BytecodeParser parser, ResolvedJavaMethod method, StructuredGraph graph) {
+        this.parser = parser;
+        this.method = method;
+        this.locals = allocateArray(method.getMaxLocals());
+        this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
+        this.lockedObjects = allocateArray(0);
+
+        assert graph != null;
+
+        this.monitorIds = EMPTY_MONITOR_ARRAY;
+        this.graph = graph;
+    }
+
+    public void initializeFromArgumentsArray(ValueNode[] arguments) {
+
+        int javaIndex = 0;
+        int index = 0;
+        if (!method.isStatic()) {
+            // set the receiver
+            locals[javaIndex] = arguments[index];
+            javaIndex = 1;
+            index = 1;
+        }
+        Signature sig = method.getSignature();
+        int max = sig.getParameterCount(false);
+        for (int i = 0; i < max; i++) {
+            Kind kind = sig.getParameterKind(i);
+            locals[javaIndex] = arguments[index];
+            javaIndex += kind.getSlotCount();
+            index++;
+        }
+    }
+
+    public void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) {
+
+        int javaIndex = 0;
+        int index = 0;
+        if (!method.isStatic()) {
+            // add the receiver
+            FloatingNode receiver = null;
+            Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass());
+            if (parameterPlugin != null) {
+                receiver = parameterPlugin.interceptParameter(parser, index, receiverStamp);
+            }
+            if (receiver == null) {
+                receiver = new ParameterNode(javaIndex, receiverStamp);
+            }
+            locals[javaIndex] = graph.unique(receiver);
+            javaIndex = 1;
+            index = 1;
+        }
+        Signature sig = method.getSignature();
+        int max = sig.getParameterCount(false);
+        ResolvedJavaType accessingClass = method.getDeclaringClass();
+        for (int i = 0; i < max; i++) {
+            JavaType type = sig.getParameterType(i, accessingClass);
+            if (eagerResolve) {
+                type = type.resolve(accessingClass);
+            }
+            Kind kind = type.getKind();
+            Stamp stamp;
+            if (kind == Kind.Object && type instanceof ResolvedJavaType) {
+                stamp = StampFactory.declared((ResolvedJavaType) type);
+            } else {
+                stamp = StampFactory.forKind(kind);
+            }
+            FloatingNode param = null;
+            if (parameterPlugin != null) {
+                param = parameterPlugin.interceptParameter(parser, index, stamp);
+            }
+            if (param == null) {
+                param = new ParameterNode(index, stamp);
+            }
+            locals[javaIndex] = graph.unique(param);
+            javaIndex += kind.getSlotCount();
+            index++;
+        }
+    }
+
+    private FrameStateBuilder(FrameStateBuilder other) {
+        this.parser = other.parser;
+        this.method = other.method;
+        this.stackSize = other.stackSize;
+        this.locals = other.locals.clone();
+        this.stack = other.stack.clone();
+        this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
+        this.rethrowException = other.rethrowException;
+
+        assert locals.length == method.getMaxLocals();
+        assert stack.length == Math.max(1, method.getMaxStackSize());
+
+        assert other.graph != null;
+        graph = other.graph;
+        monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone();
+
+        assert locals.length == method.getMaxLocals();
+        assert stack.length == Math.max(1, method.getMaxStackSize());
+        assert lockedObjects.length == monitorIds.length;
+    }
+
+    private static ValueNode[] allocateArray(int length) {
+        return length == 0 ? EMPTY_ARRAY : new ValueNode[length];
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[locals: [");
+        for (int i = 0; i < locals.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString(Verbosity.Id));
+        }
+        sb.append("] stack: [");
+        for (int i = 0; i < stackSize; i++) {
+            sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id));
+        }
+        sb.append("] locks: [");
+        for (int i = 0; i < lockedObjects.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id));
+        }
+        sb.append("]");
+        if (rethrowException) {
+            sb.append(" rethrowException");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public FrameState create(int bci, StateSplit forStateSplit) {
+        if (parser.parsingIntrinsic()) {
+            return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit);
+        }
+
+        // Skip intrinsic frames
+        return create(bci, parser.getNonIntrinsicAncestor(), false, (ValueNode[]) null);
+    }
+
+    /**
+     * @param pushedValues if non-null, values to {@link #push(Kind, ValueNode)} to the stack before
+     *            creating the {@link FrameState}
+     */
+    public FrameState create(int bci, BytecodeParser parent, boolean duringCall, ValueNode... pushedValues) {
+        if (outerFrameState == null && parent != null) {
+            outerFrameState = parent.getFrameStateBuilder().create(parent.bci(), null);
+        }
+        if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
+            FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0));
+            return newFrameState;
+        }
+        if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        if (pushedValues != null) {
+            int stackSizeToRestore = stackSize;
+            for (ValueNode arg : pushedValues) {
+                push(arg.getKind(), arg);
+            }
+            FrameState res = graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
+            stackSize = stackSizeToRestore;
+            return res;
+        } else {
+            return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
+        }
+    }
+
+    public BytecodePosition createBytecodePosition(int bci) {
+        BytecodeParser parent = parser.getParent();
+        if (HideSubstitutionStates.getValue()) {
+            if (parser.parsingIntrinsic()) {
+                // Attribute to the method being replaced
+                return new BytecodePosition(parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1);
+            }
+            // Skip intrinsic frames
+            parent = parser.getNonIntrinsicAncestor();
+        }
+        return create(null, bci, parent);
+    }
+
+    private BytecodePosition create(BytecodePosition o, int bci, BytecodeParser parent) {
+        BytecodePosition outer = o;
+        if (outer == null && parent != null) {
+            outer = parent.getFrameStateBuilder().createBytecodePosition(parent.bci());
+        }
+        if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
+            return FrameState.toBytecodePosition(outerFrameState);
+        }
+        if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+        return new BytecodePosition(outer, method, bci);
+    }
+
+    public FrameStateBuilder copy() {
+        return new FrameStateBuilder(this);
+    }
+
+    public boolean isCompatibleWith(FrameStateBuilder other) {
+        assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
+        assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds";
+
+        if (stackSize() != other.stackSize()) {
+            return false;
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode x = stackAt(i);
+            ValueNode y = other.stackAt(i);
+            if (x != y && (x == null || x.isDeleted() || y == null || y.isDeleted() || x.getKind() != y.getKind())) {
+                return false;
+            }
+        }
+        if (lockedObjects.length != other.lockedObjects.length) {
+            return false;
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) {
+                throw new BailoutException("unbalanced monitors");
+            }
+        }
+        return true;
+    }
+
+    public void merge(AbstractMergeNode block, FrameStateBuilder other) {
+        assert isCompatibleWith(other);
+
+        for (int i = 0; i < localsSize(); i++) {
+            ValueNode curLocal = localAt(i);
+            ValueNode mergedLocal = merge(curLocal, other.localAt(i), block);
+            if (curLocal != mergedLocal) {
+                storeLocal(i, mergedLocal);
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode curStack = stackAt(i);
+            ValueNode mergedStack = merge(curStack, other.stackAt(i), block);
+            if (curStack != mergedStack) {
+                storeStack(i, mergedStack);
+            }
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block);
+            assert monitorIds[i] == other.monitorIds[i];
+        }
+
+        if (sideEffects == null) {
+            sideEffects = other.sideEffects;
+        } else {
+            if (other.sideEffects != null) {
+                sideEffects.addAll(other.sideEffects);
+            }
+        }
+    }
+
+    private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
+        if (currentValue == null || currentValue.isDeleted()) {
+            return null;
+        } else if (block.isPhiAtMerge(currentValue)) {
+            if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
+                propagateDelete((ValuePhiNode) currentValue);
+                return null;
+            }
+            ((PhiNode) currentValue).addInput(otherValue);
+            return currentValue;
+        } else if (currentValue != otherValue) {
+            assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue);
+            if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
+                return null;
+            }
+            return createValuePhi(currentValue, otherValue, block);
+        } else {
+            return currentValue;
+        }
+    }
+
+    private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
+        ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block));
+        for (int i = 0; i < block.phiPredecessorCount(); i++) {
+            phi.addInput(currentValue);
+        }
+        phi.addInput(otherValue);
+        assert phi.valueCount() == block.phiPredecessorCount() + 1;
+        return phi;
+    }
+
+    private void propagateDelete(FloatingNode node) {
+        assert node instanceof ValuePhiNode || node instanceof ProxyNode;
+        if (node.isDeleted()) {
+            return;
+        }
+        // Collect all phi functions that use this phi so that we can delete them recursively (after
+        // we delete ourselves to avoid circles).
+        List<FloatingNode> propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(ValuePhiNode.class).or(ProxyNode.class)).snapshot();
+
+        // Remove the phi function from all FrameStates where it is used and then delete it.
+        assert node.usages().filter(isNotA(FrameState.class).nor(ValuePhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states";
+        node.replaceAtUsages(null);
+        node.safeDelete();
+
+        for (FloatingNode phiUsage : propagateUsages) {
+            propagateDelete(phiUsage);
+        }
+    }
+
+    public void insertLoopPhis(LocalLiveness liveness, int loopId, LoopBeginNode loopBegin, boolean forcePhis) {
+        for (int i = 0; i < localsSize(); i++) {
+            boolean changedInLoop = liveness.localIsChangedInLoop(loopId, i);
+            if (changedInLoop || forcePhis) {
+                storeLocal(i, createLoopPhi(loopBegin, localAt(i), !changedInLoop));
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            storeStack(i, createLoopPhi(loopBegin, stackAt(i), false));
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i], false);
+        }
+    }
+
+    public void insertLoopProxies(LoopExitNode loopExit, FrameStateBuilder loopEntryState) {
+        for (int i = 0; i < localsSize(); i++) {
+            ValueNode value = localAt(i);
+            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
+                Debug.log(" inserting proxy for %s", value);
+                storeLocal(i, ProxyNode.forValue(value, loopExit, graph));
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode value = stackAt(i);
+            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
+                Debug.log(" inserting proxy for %s", value);
+                storeStack(i, ProxyNode.forValue(value, loopExit, graph));
+            }
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            ValueNode value = lockedObjects[i];
+            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
+                Debug.log(" inserting proxy for %s", value);
+                lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph);
+            }
+        }
+    }
+
+    public void insertProxies(AbstractBeginNode begin) {
+        for (int i = 0; i < localsSize(); i++) {
+            ValueNode value = localAt(i);
+            if (value != null) {
+                Debug.log(" inserting proxy for %s", value);
+                storeLocal(i, ProxyNode.forValue(value, begin, graph));
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode value = stackAt(i);
+            if (value != null) {
+                Debug.log(" inserting proxy for %s", value);
+                storeStack(i, ProxyNode.forValue(value, begin, graph));
+            }
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            ValueNode value = lockedObjects[i];
+            if (value != null) {
+                Debug.log(" inserting proxy for %s", value);
+                lockedObjects[i] = ProxyNode.forValue(value, begin, graph);
+            }
+        }
+    }
+
+    private ValuePhiNode createLoopPhi(AbstractMergeNode block, ValueNode value, boolean stampFromValue) {
+        if (value == null) {
+            return null;
+        }
+        assert !block.isPhiAtMerge(value) : "phi function for this block already created";
+
+        ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(stampFromValue ? value.stamp() : value.stamp().unrestricted(), block));
+        phi.addInput(value);
+        return phi;
+    }
+
+    /**
+     * Adds a locked monitor to this frame state.
+     *
+     * @param object the object whose monitor will be locked.
+     */
+    public void pushLock(ValueNode object, MonitorIdNode monitorId) {
+        assert object.isAlive() && object.getKind() == Kind.Object : "unexpected value: " + object;
+        lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1);
+        monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1);
+        lockedObjects[lockedObjects.length - 1] = object;
+        monitorIds[monitorIds.length - 1] = monitorId;
+        assert lockedObjects.length == monitorIds.length;
+    }
+
+    /**
+     * Removes a locked monitor from this frame state.
+     *
+     * @return the object whose monitor was removed from the locks list.
+     */
+    public ValueNode popLock() {
+        try {
+            return lockedObjects[lockedObjects.length - 1];
+        } finally {
+            lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1);
+            monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1);
+            assert lockedObjects.length == monitorIds.length;
+        }
+    }
+
+    public MonitorIdNode peekMonitorId() {
+        return monitorIds[monitorIds.length - 1];
+    }
+
+    /**
+     * @return the current lock depth
+     */
+    public int lockDepth() {
+        assert lockedObjects.length == monitorIds.length;
+        return lockedObjects.length;
+    }
+
+    public boolean contains(ValueNode value) {
+        for (int i = 0; i < localsSize(); i++) {
+            if (localAt(i) == value) {
+                return true;
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            if (stackAt(i) == value) {
+                return true;
+            }
+        }
+        assert lockedObjects.length == monitorIds.length;
+        for (int i = 0; i < lockedObjects.length; i++) {
+            if (lockedObjects[i] == value || monitorIds[i] == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
+        /*
+         * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
+         * remove it for normal compilations, but not for OSR compilations - otherwise dead object
+         * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
+         * Kind.Illegal, because the conflicting branch might not have been parsed.
+         */
+        if (!parser.graphBuilderConfig.clearNonLiveLocals()) {
+            return;
+        }
+        if (liveIn) {
+            for (int i = 0; i < locals.length; i++) {
+                if (!liveness.localIsLiveIn(block, i)) {
+                    locals[i] = null;
+                }
+            }
+        } else {
+            for (int i = 0; i < locals.length; i++) {
+                if (!liveness.localIsLiveOut(block, i)) {
+                    locals[i] = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    public boolean rethrowException() {
+        return rethrowException;
+    }
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    public void setRethrowException(boolean b) {
+        rethrowException = b;
+    }
+
+    /**
+     * Returns the size of the local variables.
+     *
+     * @return the size of the local variables
+     */
+    public int localsSize() {
+        return locals.length;
+    }
+
+    /**
+     * Gets the current size (height) of the stack.
+     */
+    public int stackSize() {
+        return stackSize;
+    }
+
+    /**
+     * Gets the value in the local variables at the specified index, without any sanity checking.
+     *
+     * @param i the index into the locals
+     * @return the instruction that produced the value for the specified local
+     */
+    public ValueNode localAt(int i) {
+        return locals[i];
+    }
+
+    /**
+     * Get the value on the stack at the specified stack index.
+     *
+     * @param i the index into the stack, with {@code 0} being the bottom of the stack
+     * @return the instruction at the specified position in the stack
+     */
+    public ValueNode stackAt(int i) {
+        return stack[i];
+    }
+
+    /**
+     * Gets the value in the lock at the specified index, without any sanity checking.
+     *
+     * @param i the index into the lock
+     * @return the instruction that produced the value for the specified lock
+     */
+    public ValueNode lockAt(int i) {
+        return lockedObjects[i];
+    }
+
+    public void storeLock(int i, ValueNode lock) {
+        lockedObjects[i] = lock;
+    }
+
+    /**
+     * Loads the local variable at the specified index, checking that the returned value is non-null
+     * and that two-stack values are properly handled.
+     *
+     * @param i the index of the local variable to load
+     * @return the instruction that produced the specified local
+     */
+    public ValueNode loadLocal(int i) {
+        ValueNode x = locals[i];
+        assert assertLoadLocal(i, x);
+        return x;
+    }
+
+    private boolean assertLoadLocal(int i, ValueNode x) {
+        assert x != null : i;
+        assert parser.parsingIntrinsic() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
+        assert parser.parsingIntrinsic() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
+        return true;
+    }
+
+    public void storeLocal(int i, ValueNode x) {
+        storeLocal(i, x, x == null ? null : x.getKind());
+    }
+
+    /**
+     * Stores a given local variable at the specified index. If the value occupies two slots, then
+     * the next local variable index is also overwritten.
+     *
+     * @param i the index at which to store
+     * @param x the instruction which produces the value for the local
+     */
+    public void storeLocal(int i, ValueNode x, Kind kind) {
+        assert assertStoreLocal(x);
+        locals[i] = x;
+        if (x != null) {
+            if (kind.needsTwoSlots() && !parser.parsingIntrinsic()) {
+                // if this is a double word, then kill i+1
+                locals[i + 1] = null;
+            }
+            if (i > 0 && !parser.parsingIntrinsic()) {
+                ValueNode p = locals[i - 1];
+                if (p != null && p.getKind().needsTwoSlots()) {
+                    // if there was a double word at i - 1, then kill it
+                    locals[i - 1] = null;
+                }
+            }
+        }
+    }
+
+    private boolean assertStoreLocal(ValueNode x) {
+        assert x == null || parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
+        return true;
+    }
+
+    public void storeStack(int i, ValueNode x) {
+        assert assertStoreStack(i, x);
+        stack[i] = x;
+    }
+
+    private boolean assertStoreStack(int i, ValueNode x) {
+        assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values";
+        return true;
+    }
+
+    /**
+     * Pushes an instruction onto the stack with the expected type.
+     *
+     * @param kind the type expected for this instruction
+     * @param x the instruction to push onto the stack
+     */
+    public void push(Kind kind, ValueNode x) {
+        assert assertPush(kind, x);
+        xpush(x);
+        if (kind.needsTwoSlots()) {
+            xpush(null);
+        }
+    }
+
+    private boolean assertPush(Kind kind, ValueNode x) {
+        assert parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
+        assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind);
+        return true;
+    }
+
+    /**
+     * Pushes a value onto the stack without checking the type.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void xpush(ValueNode x) {
+        assert assertXpush(x);
+        stack[stackSize++] = x;
+    }
+
+    private boolean assertXpush(ValueNode x) {
+        assert parser.parsingIntrinsic() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
+        return true;
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is an int.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void ipush(ValueNode x) {
+        assert assertInt(x);
+        xpush(x);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a float.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void fpush(ValueNode x) {
+        assert assertFloat(x);
+        xpush(x);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is an object.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void apush(ValueNode x) {
+        assert assertObject(x);
+        xpush(x);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a long.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void lpush(ValueNode x) {
+        assert assertLong(x);
+        xpush(x);
+        xpush(null);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a double.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void dpush(ValueNode x) {
+        assert assertDouble(x);
+        xpush(x);
+        xpush(null);
+    }
+
+    public void pushReturn(Kind kind, ValueNode x) {
+        if (kind != Kind.Void) {
+            push(kind.getStackKind(), x);
+        }
+    }
+
+    /**
+     * Pops an instruction off the stack with the expected type.
+     *
+     * @param kind the expected type
+     * @return the instruction on the top of the stack
+     */
+    public ValueNode pop(Kind kind) {
+        if (kind.needsTwoSlots()) {
+            xpop();
+        }
+        assert assertPop(kind);
+        return xpop();
+    }
+
+    private boolean assertPop(Kind kind) {
+        assert kind != Kind.Void;
+        ValueNode x = xpeek();
+        assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind);
+        return true;
+    }
+
+    /**
+     * Pops a value off of the stack without checking the type.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode xpop() {
+        return stack[--stackSize];
+    }
+
+    public ValueNode xpeek() {
+        return stack[stackSize - 1];
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is an int.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode ipop() {
+        assert assertIntPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a float.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode fpop() {
+        assert assertFloatPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is an object.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode apop() {
+        assert assertObjectPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a long.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode lpop() {
+        assert assertHighPeek();
+        xpop();
+        assert assertLongPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a double.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode dpop() {
+        assert assertHighPeek();
+        xpop();
+        assert assertDoublePeek();
+        return xpop();
+    }
+
+    /**
+     * Pop the specified number of slots off of this stack and return them as an array of
+     * instructions.
+     *
+     * @return an array containing the arguments off of the stack
+     */
+    public ValueNode[] popArguments(int argSize) {
+        ValueNode[] result = allocateArray(argSize);
+        int newStackSize = stackSize;
+        for (int i = argSize - 1; i >= 0; i--) {
+            newStackSize--;
+            if (stack[newStackSize] == null) {
+                /* Two-slot value. */
+                newStackSize--;
+                assert stack[newStackSize].getKind().needsTwoSlots();
+            } else {
+                assert parser.parsingIntrinsic() || (stack[newStackSize].getKind().getSlotCount() == 1);
+            }
+            result[i] = stack[newStackSize];
+        }
+        stackSize = newStackSize;
+        return result;
+    }
+
+    /**
+     * Peeks an element from the operand stack.
+     *
+     * @param argumentNumber The number of the argument, relative from the top of the stack (0 =
+     *            top). Long and double arguments only count as one argument, i.e., null-slots are
+     *            ignored.
+     * @return The peeked argument.
+     */
+    public ValueNode peek(int argumentNumber) {
+        int idx = stackSize() - 1;
+        for (int i = 0; i < argumentNumber; i++) {
+            if (stackAt(idx) == null) {
+                idx--;
+                assert stackAt(idx).getKind().needsTwoSlots();
+            }
+            idx--;
+        }
+        return stackAt(idx);
+    }
+
+    /**
+     * Clears all values on this stack.
+     */
+    public void clearStack() {
+        stackSize = 0;
+    }
+
+    private boolean assertLongPeek() {
+        return assertLong(xpeek());
+    }
+
+    private static boolean assertLong(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Long);
+        return true;
+    }
+
+    private boolean assertIntPeek() {
+        return assertInt(xpeek());
+    }
+
+    private static boolean assertInt(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Int);
+        return true;
+    }
+
+    private boolean assertFloatPeek() {
+        return assertFloat(xpeek());
+    }
+
+    private static boolean assertFloat(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Float);
+        return true;
+    }
+
+    private boolean assertObjectPeek() {
+        return assertObject(xpeek());
+    }
+
+    private boolean assertObject(ValueNode x) {
+        assert x != null && (parser.parsingIntrinsic() || (x.getKind() == Kind.Object));
+        return true;
+    }
+
+    private boolean assertDoublePeek() {
+        return assertDouble(xpeek());
+    }
+
+    private static boolean assertDouble(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Double);
+        return true;
+    }
+
+    private boolean assertHighPeek() {
+        assert xpeek() == null;
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = hashCode(locals, locals.length);
+        result *= 13;
+        result += hashCode(stack, this.stackSize);
+        return result;
+    }
+
+    private static int hashCode(Object[] a, int length) {
+        int result = 1;
+        for (int i = 0; i < length; ++i) {
+            Object element = a[i];
+            result = 31 * result + (element == null ? 0 : System.identityHashCode(element));
+        }
+        return result;
+    }
+
+    private static boolean equals(ValueNode[] a, ValueNode[] b, int length) {
+        for (int i = 0; i < length; ++i) {
+            if (a[i] != b[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean equals(Object otherObject) {
+        if (otherObject instanceof FrameStateBuilder) {
+            FrameStateBuilder other = (FrameStateBuilder) otherObject;
+            if (!other.method.equals(method)) {
+                return false;
+            }
+            if (other.stackSize != stackSize) {
+                return false;
+            }
+            if (other.parser != parser) {
+                return false;
+            }
+            if (other.rethrowException != rethrowException) {
+                return false;
+            }
+            if (other.graph != graph) {
+                return false;
+            }
+            if (other.locals.length != locals.length) {
+                return false;
+            }
+            return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) &&
+                            equals(other.monitorIds, monitorIds, monitorIds.length);
+        }
+        return false;
+    }
+
+    public void replace(ValueNode oldValue, ValueNode newValue) {
+        for (int i = 0; i < locals.length; i++) {
+            if (locals[i] == oldValue) {
+                locals[i] = newValue;
+            }
+        }
+        for (int i = 0; i < stackSize; i++) {
+            if (stack[i] == oldValue) {
+                stack[i] = newValue;
+            }
+        }
+    }
+
+    @Override
+    public boolean isAfterSideEffect() {
+        return sideEffects != null;
+    }
+
+    @Override
+    public Iterable<StateSplit> sideEffects() {
+        return sideEffects;
+    }
+
+    @Override
+    public void addSideEffect(StateSplit sideEffect) {
+        assert sideEffect != null;
+        assert sideEffect.hasSideEffect();
+        if (sideEffects == null) {
+            sideEffects = new ArrayList<>(4);
+        }
+        sideEffects.add(sideEffect);
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -22,13 +22,15 @@
  */
 package com.oracle.graal.java;
 
+import static com.oracle.graal.api.code.TypeCheckHints.*;
 import static com.oracle.graal.api.meta.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
 import static com.oracle.graal.compiler.common.GraalInternalError.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.compiler.common.type.StampFactory.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
 import static com.oracle.graal.nodes.type.StampTool.*;
 import static java.lang.String.*;
@@ -52,6 +54,7 @@
 import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
+import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
@@ -61,6 +64,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -69,6 +73,125 @@
  */
 public class GraphBuilderPhase extends BasePhase<HighTierContext> {
 
+    public static class Options {
+        // @formatter:off
+        @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug)
+        public static final OptionValue<Integer> TraceBytecodeParserLevel = new OptionValue<>(0);
+
+        @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert)
+        public static final StableOptionValue<Boolean> InlineDuringParsing = new StableOptionValue<>(false);
+
+        @Option(help = "Inlines intrinsic methods during bytecode parsing.", type = OptionType.Expert)
+        public static final StableOptionValue<Boolean> InlineIntrinsicsDuringParsing = new StableOptionValue<>(true);
+
+        @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceInlineDuringParsing = new StableOptionValue<>(false);
+
+        @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceParserPlugins = new StableOptionValue<>(false);
+
+        @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug)
+        public static final StableOptionValue<Integer> InlineDuringParsingMaxDepth = new StableOptionValue<>(10);
+
+        @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> DumpDuringGraphBuilding = new StableOptionValue<>(false);
+
+        @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)
+        public static final OptionValue<Integer> MaximumLoopExplosionCount = new OptionValue<>(10000);
+
+        @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> FailedLoopExplosionIsFatal = new OptionValue<>(false);
+
+        @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> HideSubstitutionStates = new OptionValue<>(false);
+
+        // @formatter:on
+    }
+
+    /**
+     * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the
+     * bytecode instructions as they are parsed.
+     */
+    public static final int TRACELEVEL_INSTRUCTIONS = 1;
+
+    /**
+     * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the
+     * frame state before each bytecode instruction as it is parsed.
+     */
+    public static final int TRACELEVEL_STATE = 2;
+
+    /**
+     * Meters the number of actual bytecodes parsed.
+     */
+    public static final DebugMetric BytecodesParsed = Debug.metric("BytecodesParsed");
+
+    /**
+     * Gets the kind of array elements for the array type code that appears in a
+     * {@link Bytecodes#NEWARRAY} bytecode.
+     *
+     * @param code the array type code
+     * @return the kind from the array type code
+     */
+    public static Class<?> arrayTypeCodeToClass(int code) {
+        // Checkstyle: stop
+        switch (code) {
+            case 4:
+                return boolean.class;
+            case 5:
+                return char.class;
+            case 6:
+                return float.class;
+            case 7:
+                return double.class;
+            case 8:
+                return byte.class;
+            case 9:
+                return short.class;
+            case 10:
+                return int.class;
+            case 11:
+                return long.class;
+            default:
+                throw new IllegalArgumentException("unknown array type code: " + code);
+        }
+        // Checkstyle: resume
+    }
+
+    protected static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions");
+
+    protected static boolean allPositive(double[] a) {
+        for (double d : a) {
+            if (d < 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Helper function that sums up the probabilities of all keys that lead to a specific successor.
+     *
+     * @return an array of size successorCount with the accumulated probability for each successor.
+     */
+    public static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) {
+        double[] probability = new double[successorCount];
+        for (int i = 0; i < keySuccessors.length; i++) {
+            probability[keySuccessors[i]] += keyProbabilities[i];
+        }
+        return probability;
+    }
+
+    static class SuccessorInfo {
+
+        int blockIndex;
+        int actualIndex;
+
+        public SuccessorInfo(int blockSuccessorIndex) {
+            this.blockIndex = blockSuccessorIndex;
+            actualIndex = -1;
+        }
+    }
+
     private final GraphBuilderConfiguration graphBuilderConfig;
 
     public GraphBuilderPhase(GraphBuilderConfiguration config) {
@@ -84,6 +207,103 @@
         return graphBuilderConfig;
     }
 
+    /**
+     * A scoped object for tasks to be performed after parsing an intrinsic such as processing
+     * {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frames states.
+     */
+    static class IntrinsicScope implements AutoCloseable {
+        FrameState stateBefore;
+        final Mark mark;
+        final BytecodeParser parser;
+
+        /**
+         * Creates a scope for root parsing an intrinsic.
+         *
+         * @param parser the parsing context of the intrinsic
+         */
+        public IntrinsicScope(BytecodeParser parser) {
+            this.parser = parser;
+            assert parser.parent == null;
+            assert parser.bci() == 0;
+            mark = null;
+        }
+
+        /**
+         * Creates a scope for parsing an intrinsic during graph builder inlining.
+         *
+         * @param parser the parsing context of the (non-intrinsic) method calling the intrinsic
+         * @param args the arguments to the call
+         */
+        public IntrinsicScope(BytecodeParser parser, ValueNode[] args) {
+            assert !parser.parsingIntrinsic();
+            this.parser = parser;
+            mark = parser.getGraph().getMark();
+            stateBefore = parser.frameState.create(parser.bci(), parser.getNonIntrinsicAncestor(), false, args);
+        }
+
+        public void close() {
+            IntrinsicContext intrinsic = parser.intrinsicContext;
+            if (intrinsic != null && intrinsic.isPostParseInlined()) {
+                return;
+            }
+
+            processPlaceholderFrameStates(intrinsic);
+        }
+
+        /**
+         * Fixes up the {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frame states
+         * added to the graph while parsing/inlining the intrinsic for which this object exists.
+         */
+        private void processPlaceholderFrameStates(IntrinsicContext intrinsic) {
+            FrameState stateAfterReturn = null;
+            StructuredGraph graph = parser.getGraph();
+            for (Node node : graph.getNewNodes(mark)) {
+                if (node instanceof FrameState) {
+                    FrameState frameState = (FrameState) node;
+                    if (BytecodeFrame.isPlaceholderBci(frameState.bci)) {
+                        if (frameState.bci == BytecodeFrame.AFTER_BCI) {
+                            FrameStateBuilder frameStateBuilder = parser.frameState;
+                            if (frameState.stackSize() != 0) {
+                                assert frameState.usages().count() == 1;
+                                ValueNode returnVal = frameState.stackAt(0);
+                                assert returnVal == frameState.usages().first();
+
+                                /*
+                                 * Swap the top-of-stack value with the side-effect return value
+                                 * using the frame state.
+                                 */
+                                ValueNode tos = frameStateBuilder.pop(returnVal.getKind());
+                                assert tos.getKind() == returnVal.getKind();
+                                FrameState newFrameState = frameStateBuilder.create(parser.stream.nextBCI(), parser.getNonIntrinsicAncestor(), false, returnVal);
+                                frameState.replaceAndDelete(newFrameState);
+                                frameStateBuilder.push(tos.getKind(), tos);
+                            } else {
+                                if (stateAfterReturn == null) {
+                                    if (intrinsic != null) {
+                                        assert intrinsic.isCompilationRoot();
+                                        stateAfterReturn = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
+                                    } else {
+                                        stateAfterReturn = frameStateBuilder.create(parser.stream.nextBCI(), null);
+                                    }
+                                }
+                                frameState.replaceAndDelete(stateAfterReturn);
+                            }
+                        } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) {
+                            if (stateBefore == null) {
+                                stateBefore = graph.start().stateAfter();
+                            }
+                            if (stateBefore != frameState) {
+                                frameState.replaceAndDelete(stateBefore);
+                            }
+                        } else {
+                            assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     // Fully qualified name is a workaround for JDK-8056066
     public static class Instance extends com.oracle.graal.phases.Phase {
 
@@ -91,7 +311,7 @@
 
         private final MetaAccessProvider metaAccess;
 
-        private final ReplacementContext initialReplacementContext;
+        private final IntrinsicContext initialIntrinsicContext;
 
         private final GraphBuilderConfiguration graphBuilderConfig;
         private final OptimisticOptimizations optimisticOpts;
@@ -99,13 +319,13 @@
         private final ConstantReflectionProvider constantReflection;
 
         public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
-                        OptimisticOptimizations optimisticOpts, ReplacementContext initialReplacementContext) {
+                        OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
             this.graphBuilderConfig = graphBuilderConfig;
             this.optimisticOpts = optimisticOpts;
             this.metaAccess = metaAccess;
             this.stampProvider = stampProvider;
             this.constantReflection = constantReflection;
-            this.initialReplacementContext = initialReplacementContext;
+            this.initialIntrinsicContext = initialIntrinsicContext;
 
             assert metaAccess != null;
         }
@@ -118,12 +338,15 @@
             this.graph = graph;
             TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
             try {
-                ReplacementContext replacementContext = initialReplacementContext;
-                BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, replacementContext);
-                HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(parser, method, graph);
-                frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || replacementContext != null, graphBuilderConfig.getPlugins().getParameterPlugin());
-                parser.build(graph.start(), frameState);
-
+                IntrinsicContext intrinsicContext = initialIntrinsicContext;
+                BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, intrinsicContext);
+                FrameStateBuilder frameState = new FrameStateBuilder(parser, method, graph);
+
+                frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || intrinsicContext != null, graphBuilderConfig.getPlugins().getParameterPlugin());
+
+                try (IntrinsicScope s = intrinsicContext != null ? new IntrinsicScope(parser) : null) {
+                    parser.build(graph.start(), frameState);
+                }
                 GraphUtil.normalizeLoops(graph);
 
                 // Remove dead parameters.
@@ -193,9 +416,9 @@
         private static class Target {
 
             FixedNode fixed;
-            HIRFrameStateBuilder state;
-
-            public Target(FixedNode fixed, HIRFrameStateBuilder state) {
+            FrameStateBuilder state;
+
+            public Target(FixedNode fixed, FrameStateBuilder state) {
                 this.fixed = fixed;
                 this.state = state;
             }
@@ -219,7 +442,7 @@
             }
         }
 
-        public class BytecodeParser extends AbstractBytecodeParser implements GraphBuilderContext {
+        public class BytecodeParser implements GraphBuilderContext {
 
             private BciBlockMapping blockMap;
             private LocalLiveness liveness;
@@ -240,24 +463,32 @@
             private FixedWithNextNode lastInstr;                 // the last instruction added
             private final boolean explodeLoops;
             private final boolean mergeExplosions;
-            private final Map<HIRFrameStateBuilder, Integer> mergeExplosionsMap;
+            private final Map<FrameStateBuilder, Integer> mergeExplosionsMap;
             private Deque<ExplodedLoopContext> explodeLoopsContext;
             private int nextPeelIteration = 1;
             private boolean controlFlowSplit;
             private final InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(this);
 
             private FixedWithNextNode[] firstInstructionArray;
-            private HIRFrameStateBuilder[] entryStateArray;
+            private FrameStateBuilder[] entryStateArray;
             private FixedWithNextNode[][] firstInstructionMatrix;
-            private HIRFrameStateBuilder[][] entryStateMatrix;
+            private FrameStateBuilder[][] entryStateMatrix;
 
             public BytecodeParser(BytecodeParser parent, MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig,
-                            OptimisticOptimizations optimisticOpts, int entryBCI, ReplacementContext replacementContext) {
-                super(metaAccess, method, graphBuilderConfig, optimisticOpts, replacementContext);
+                            OptimisticOptimizations optimisticOpts, int entryBCI, IntrinsicContext intrinsicContext) {
+                this.graphBuilderConfig = graphBuilderConfig;
+                this.optimisticOpts = optimisticOpts;
+                this.metaAccess = metaAccess;
+                this.stream = new BytecodeStream(method.getCode());
+                this.profilingInfo = (graphBuilderConfig.getUseProfiling() ? method.getProfilingInfo() : null);
+                this.constantPool = method.getConstantPool();
+                this.method = method;
+                this.intrinsicContext = intrinsicContext;
+                assert metaAccess != null;
                 this.entryBCI = entryBCI;
                 this.parent = parent;
 
-                if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
+                if (graphBuilderConfig.insertNonSafepointDebugInfo() && !parsingIntrinsic()) {
                     lnt = method.getLineNumberTable();
                     previousLineNumber = -1;
                 }
@@ -295,7 +526,7 @@
                 return this.beforeUnwindNode;
             }
 
-            protected void build(FixedWithNextNode startInstruction, HIRFrameStateBuilder startFrameState) {
+            protected void build(FixedWithNextNode startInstruction, FrameStateBuilder startFrameState) {
                 if (PrintProfilingInformation.getValue() && profilingInfo != null) {
                     TTY.println("Profiling info for " + method.format("%H.%n(%p)"));
                     TTY.println(MetaUtil.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), "  "));
@@ -307,15 +538,13 @@
                     BciBlockMapping newMapping = BciBlockMapping.create(stream, method);
                     this.blockMap = newMapping;
                     this.firstInstructionArray = new FixedWithNextNode[blockMap.getBlockCount()];
-                    this.entryStateArray = new HIRFrameStateBuilder[blockMap.getBlockCount()];
-
-                    if (graphBuilderConfig.doLivenessAnalysis()) {
-                        try (Scope s = Debug.scope("LivenessAnalysis")) {
-                            int maxLocals = method.getMaxLocals();
-                            liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount());
-                        } catch (Throwable e) {
-                            throw Debug.handle(e);
-                        }
+                    this.entryStateArray = new FrameStateBuilder[blockMap.getBlockCount()];
+
+                    try (Scope s = Debug.scope("LivenessAnalysis")) {
+                        int maxLocals = method.getMaxLocals();
+                        liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount());
+                    } catch (Throwable e) {
+                        throw Debug.handle(e);
                     }
 
                     lastInstr = startInstruction;
@@ -326,11 +555,27 @@
                     if (startInstruction == graph.start()) {
                         StartNode startNode = graph.start();
                         if (method.isSynchronized()) {
-                            startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI));
+                            assert !parsingIntrinsic();
+                            startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI, startNode));
                         } else {
-                            frameState.clearNonLiveLocals(startBlock, liveness, true);
-                            assert bci() == 0;
-                            startNode.setStateAfter(createFrameState(bci()));
+                            if (!parsingIntrinsic()) {
+                                if (graph.method() != null && graph.method().isJavaLangObjectInit()) {
+                                    /*
+                                     * Don't clear the receiver when Object.<init> is the
+                                     * compilation root. The receiver is needed as input to
+                                     * RegisterFinalizerNode.
+                                     */
+                                } else {
+                                    frameState.clearNonLiveLocals(startBlock, liveness, true);
+                                }
+                                assert bci() == 0;
+                                startNode.setStateAfter(createFrameState(bci(), startNode));
+                            } else {
+                                if (startNode.stateAfter() == null) {
+                                    FrameState stateAfterStart = createStateAfterStartOfReplacementGraph();
+                                    startNode.setStateAfter(stateAfterStart);
+                                }
+                            }
                         }
                     }
 
@@ -342,7 +587,7 @@
                         genMonitorEnter(methodSynchronizedObject, bci());
                     }
 
-                    if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
+                    if (graphBuilderConfig.insertNonSafepointDebugInfo() && !parsingIntrinsic()) {
                         append(createInfoPointNode(InfopointReason.METHOD_START));
                     }
 
@@ -372,6 +617,42 @@
                 }
             }
 
+            /**
+             * Creates the frame state after the start node of a graph for an
+             * {@link IntrinsicContext intrinsic} that is the parse root (either for root compiling
+             * or for post-parse inlining).
+             */
+            private FrameState createStateAfterStartOfReplacementGraph() {
+                assert parent == null;
+                assert frameState.method.equals(intrinsicContext.getIntrinsicMethod());
+                assert bci() == 0;
+                assert frameState.stackSize == 0;
+                FrameState stateAfterStart;
+                if (intrinsicContext.isPostParseInlined()) {
+                    stateAfterStart = graph.add(new FrameState(BytecodeFrame.BEFORE_BCI));
+                } else {
+                    ResolvedJavaMethod original = intrinsicContext.getOriginalMethod();
+                    ValueNode[] locals;
+                    if (original.getMaxLocals() == frameState.localsSize() || original.isNative()) {
+                        locals = frameState.locals;
+                    } else {
+                        locals = new ValueNode[original.getMaxLocals()];
+                        int parameterCount = original.getSignature().getParameterCount(!original.isStatic());
+                        for (int i = 0; i < parameterCount; i++) {
+                            ValueNode param = frameState.locals[i];
+                            locals[i] = param;
+                            assert param == null || param instanceof ParameterNode || param.isConstant();
+                        }
+                    }
+                    ValueNode[] stack = {};
+                    int stackSize = 0;
+                    ValueNode[] locks = {};
+                    List<MonitorIdNode> monitorIds = Collections.emptyList();
+                    stateAfterStart = graph.add(new FrameState(null, original, 0, locals, stack, stackSize, locks, monitorIds, false, false));
+                }
+                return stateAfterStart;
+            }
+
             private void detectLoops(FixedNode startInstruction) {
                 NodeBitMap visited = graph.createNodeBitMap();
                 NodeBitMap active = graph.createNodeBitMap();
@@ -404,7 +685,7 @@
                                 }
                                 LoopBeginNode loopBegin = (LoopBeginNode) ((EndNode) merge.next()).merge();
                                 LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin));
-                                if (parsingReplacement()) {
+                                if (parsingIntrinsic()) {
                                     loopEnd.disableSafepoint();
                                 }
                                 endNode.replaceAndDelete(loopEnd);
@@ -566,7 +847,7 @@
                 return header.loopEnd + 1;
             }
 
-            private void addToMergeCache(HIRFrameStateBuilder key, int dimension) {
+            private void addToMergeCache(FrameStateBuilder key, int dimension) {
                 mergeExplosionsMap.put(key, dimension);
             }
 
@@ -605,7 +886,6 @@
             /**
              * @param type the unresolved type of the constant
              */
-            @Override
             protected void handleUnresolvedLoadConstant(JavaType type) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -615,7 +895,6 @@
              * @param type the unresolved type of the type check
              * @param object the object value whose type is being checked against {@code type}
              */
-            @Override
             protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new FixedGuardNode(graph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile));
@@ -626,7 +905,6 @@
              * @param type the unresolved type of the type check
              * @param object the object value whose type is being checked against {@code type}
              */
-            @Override
             protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) {
                 assert !graphBuilderConfig.eagerResolving();
                 AbstractBeginNode successor = graph.add(new BeginNode());
@@ -639,7 +917,6 @@
             /**
              * @param type the type being instantiated
              */
-            @Override
             protected void handleUnresolvedNewInstance(JavaType type) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -649,7 +926,6 @@
              * @param type the type of the array being instantiated
              * @param length the length of the array
              */
-            @Override
             protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -659,7 +935,6 @@
              * @param type the type being instantiated
              * @param dims the dimensions for the multi-array
              */
-            @Override
             protected void handleUnresolvedNewMultiArray(JavaType type, List<ValueNode> dims) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -670,7 +945,6 @@
              * @param receiver the object containing the field or {@code null} if {@code field} is
              *            static
              */
-            @Override
             protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -682,7 +956,6 @@
              * @param receiver the object containing the field or {@code null} if {@code field} is
              *            static
              */
-            @Override
             protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -691,7 +964,6 @@
             /**
              * @param type
              */
-            @Override
             protected void handleUnresolvedExceptionType(JavaType type) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -720,7 +992,7 @@
                     dispatchBlock = blockMap.getUnwindBlock();
                 }
 
-                HIRFrameStateBuilder dispatchState = frameState.copy();
+                FrameStateBuilder dispatchState = frameState.copy();
                 dispatchState.clearStack();
 
                 DispatchBeginNode dispatchBegin;
@@ -728,11 +1000,11 @@
                     dispatchBegin = graph.add(new ExceptionObjectNode(metaAccess));
                     dispatchState.apush(dispatchBegin);
                     dispatchState.setRethrowException(true);
-                    dispatchBegin.setStateAfter(dispatchState.create(bci));
+                    dispatchBegin.setStateAfter(dispatchState.create(bci, dispatchBegin));
                 } else {
                     dispatchBegin = graph.add(new DispatchBeginNode());
                     dispatchState.apush(exceptionObject);
-                    dispatchBegin.setStateAfter(dispatchState.create(bci));
+                    dispatchBegin.setStateAfter(dispatchState.create(bci, dispatchBegin));
                     dispatchState.setRethrowException(true);
                 }
                 this.controlFlowSplit = true;
@@ -742,148 +1014,119 @@
                 return dispatchBegin;
             }
 
-            @Override
             protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, Kind kind) {
                 return LoadIndexedNode.create(array, index, kind, metaAccess, constantReflection);
             }
 
-            @Override
             protected void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value) {
                 add(new StoreIndexedNode(array, index, kind, value));
             }
 
-            @Override
-            protected ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genIntegerAdd(ValueNode x, ValueNode y) {
                 return AddNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genIntegerSub(ValueNode x, ValueNode y) {
                 return SubNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genIntegerMul(ValueNode x, ValueNode y) {
                 return MulNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genFloatAdd(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
+            protected ValueNode genFloatAdd(ValueNode x, ValueNode y) {
                 return AddNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genFloatSub(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
+            protected ValueNode genFloatSub(ValueNode x, ValueNode y) {
                 return SubNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genFloatMul(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
+            protected ValueNode genFloatMul(ValueNode x, ValueNode y) {
                 return MulNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genFloatDiv(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
+            protected ValueNode genFloatDiv(ValueNode x, ValueNode y) {
                 return DivNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genFloatRem(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
+            protected ValueNode genFloatRem(ValueNode x, ValueNode y) {
                 return new RemNode(x, y);
             }
 
-            @Override
-            protected ValueNode genIntegerDiv(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genIntegerDiv(ValueNode x, ValueNode y) {
                 return new IntegerDivNode(x, y);
             }
 
-            @Override
-            protected ValueNode genIntegerRem(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genIntegerRem(ValueNode x, ValueNode y) {
                 return new IntegerRemNode(x, y);
             }
 
-            @Override
             protected ValueNode genNegateOp(ValueNode x) {
                 return (new NegateNode(x));
             }
 
-            @Override
-            protected ValueNode genLeftShift(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genLeftShift(ValueNode x, ValueNode y) {
                 return new LeftShiftNode(x, y);
             }
 
-            @Override
-            protected ValueNode genRightShift(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genRightShift(ValueNode x, ValueNode y) {
                 return new RightShiftNode(x, y);
             }
 
-            @Override
-            protected ValueNode genUnsignedRightShift(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genUnsignedRightShift(ValueNode x, ValueNode y) {
                 return new UnsignedRightShiftNode(x, y);
             }
 
-            @Override
-            protected ValueNode genAnd(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genAnd(ValueNode x, ValueNode y) {
                 return AndNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genOr(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genOr(ValueNode x, ValueNode y) {
                 return OrNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genXor(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genXor(ValueNode x, ValueNode y) {
                 return XorNode.create(x, y);
             }
 
-            @Override
             protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) {
                 return NormalizeCompareNode.create(x, y, isUnorderedLess, constantReflection);
             }
 
-            @Override
             protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) {
                 return FloatConvertNode.create(op, input);
             }
 
-            @Override
             protected ValueNode genNarrow(ValueNode input, int bitCount) {
                 return NarrowNode.create(input, bitCount);
             }
 
-            @Override
             protected ValueNode genSignExtend(ValueNode input, int bitCount) {
                 return SignExtendNode.create(input, bitCount);
             }
 
-            @Override
             protected ValueNode genZeroExtend(ValueNode input, int bitCount) {
                 return ZeroExtendNode.create(input, bitCount);
             }
 
-            @Override
             protected void genGoto() {
                 appendGoto(currentBlock.getSuccessor(0));
                 assert currentBlock.numNormalSuccessors() == 1;
             }
 
-            @Override
             protected LogicNode genObjectEquals(ValueNode x, ValueNode y) {
                 return ObjectEqualsNode.create(x, y, constantReflection);
             }
 
-            @Override
             protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) {
                 return IntegerEqualsNode.create(x, y, constantReflection);
             }
 
-            @Override
             protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) {
                 return IntegerLessThanNode.create(x, y, constantReflection);
             }
 
-            @Override
             protected ValueNode genUnique(ValueNode x) {
                 return (ValueNode) graph.unique((Node & ValueNumberable) x);
             }
@@ -892,49 +1135,40 @@
                 return new IfNode(condition, falseSuccessor, trueSuccessor, d);
             }
 
-            @Override
             protected void genThrow() {
                 ValueNode exception = frameState.apop();
                 append(new FixedGuardNode(graph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true));
                 lastInstr.setNext(handleException(exception, bci()));
             }
 
-            @Override
             protected ValueNode createCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck) {
                 return CheckCastNode.create(type, object, profileForTypeCheck, forStoreCheck, graph.getAssumptions());
             }
 
-            @Override
             protected ValueNode createInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck) {
                 return InstanceOfNode.create(type, object, profileForTypeCheck);
             }
 
-            @Override
             protected ValueNode genConditional(ValueNode x) {
                 return new ConditionalNode((LogicNode) x);
             }
 
-            @Override
             protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) {
                 return new NewInstanceNode(type, fillContents);
             }
 
-            @Override
             protected NewArrayNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
                 return new NewArrayNode(elementType, length, fillContents);
             }
 
-            @Override
             protected NewMultiArrayNode createNewMultiArray(ResolvedJavaType type, List<ValueNode> dimensions) {
                 return new NewMultiArrayNode(type, dimensions.toArray(new ValueNode[0]));
             }
 
-            @Override
             protected ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field) {
                 return new LoadFieldNode(receiver, field);
             }
 
-            @Override
             protected ValueNode emitExplicitNullCheck(ValueNode receiver) {
                 if (StampTool.isPointerNonNull(receiver.stamp())) {
                     return receiver;
@@ -946,32 +1180,29 @@
                 append(new IfNode(graph.unique(new IsNullNode(receiver)), exception, falseSucc, 0.01));
                 lastInstr = falseSucc;
 
-                exception.setStateAfter(createFrameState(bci()));
+                exception.setStateAfter(createFrameState(bci(), exception));
                 exception.setNext(handleException(exception, bci()));
                 return nonNullReceiver;
             }
 
-            @Override
             protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) {
                 AbstractBeginNode trueSucc = graph.add(new BeginNode());
                 BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index));
                 append(new IfNode(graph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99));
                 lastInstr = trueSucc;
 
-                exception.setStateAfter(createFrameState(bci()));
+                exception.setStateAfter(createFrameState(bci(), exception));
                 exception.setNext(handleException(exception, bci()));
             }
 
-            @Override
             protected ValueNode genArrayLength(ValueNode x) {
                 return ArrayLengthNode.create(x, constantReflection);
             }
 
-            @Override
             protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) {
                 StoreFieldNode storeFieldNode = new StoreFieldNode(receiver, field, value);
                 append(storeFieldNode);
-                storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI()));
+                storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI(), storeFieldNode));
             }
 
             /**
@@ -990,7 +1221,6 @@
                 return false;
             }
 
-            @Override
             protected void genInvokeStatic(JavaMethod target) {
                 if (callTargetIsResolved(target)) {
                     ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target;
@@ -1006,7 +1236,6 @@
                 }
             }
 
-            @Override
             protected void genInvokeInterface(JavaMethod target) {
                 if (callTargetIsResolved(target)) {
                     ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true));
@@ -1016,7 +1245,6 @@
                 }
             }
 
-            @Override
             protected void genInvokeDynamic(JavaMethod target) {
                 if (target instanceof ResolvedJavaMethod) {
                     JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC);
@@ -1030,7 +1258,6 @@
                 }
             }
 
-            @Override
             protected void genInvokeVirtual(JavaMethod target) {
                 if (callTargetIsResolved(target)) {
                     /*
@@ -1057,7 +1284,6 @@
 
             }
 
-            @Override
             protected void genInvokeSpecial(JavaMethod target) {
                 if (callTargetIsResolved(target)) {
                     assert target != null;
@@ -1071,6 +1297,16 @@
 
             private InvokeKind currentInvokeKind;
             private JavaType currentInvokeReturnType;
+            protected FrameStateBuilder frameState;
+            protected BciBlock currentBlock;
+            protected final BytecodeStream stream;
+            protected final GraphBuilderConfiguration graphBuilderConfig;
+            protected final ResolvedJavaMethod method;
+            protected final ProfilingInfo profilingInfo;
+            protected final OptimisticOptimizations optimisticOpts;
+            protected final ConstantPool constantPool;
+            protected final MetaAccessProvider metaAccess;
+            protected final IntrinsicContext intrinsicContext;
 
             public InvokeKind getInvokeKind() {
                 return currentInvokeKind;
@@ -1104,7 +1340,7 @@
                 }
 
                 JavaType returnType = targetMethod.getSignature().getReturnType(method.getDeclaringClass());
-                if (graphBuilderConfig.eagerResolving() || parsingReplacement()) {
+                if (graphBuilderConfig.eagerResolving() || parsingIntrinsic()) {
                     returnType = returnType.resolve(targetMethod.getDeclaringClass());
                 }
                 if (invokeKind.hasReceiver()) {
@@ -1210,8 +1446,8 @@
                         for (Node n : newNodes) {
                             if (n instanceof StateSplit) {
                                 StateSplit stateSplit = (StateSplit) n;
-                                assert stateSplit.stateAfter() != null : error("%s node added by plugin for %s need to have a non-null frame state: %s", StateSplit.class.getSimpleName(),
-                                                targetMethod.format("%H.%n(%p)"), stateSplit);
+                                assert stateSplit.stateAfter() != null || !stateSplit.hasSideEffect() : error("%s node added by plugin for %s need to have a non-null frame state: %s",
+                                                StateSplit.class.getSimpleName(), targetMethod.format("%H.%n(%p)"), stateSplit);
                             }
                         }
                         try {
@@ -1231,9 +1467,8 @@
                 InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
                 if (plugin != null) {
 
-                    ReplacementContext context = this.replacementContext;
-                    if (context != null && context.isCallToOriginal(targetMethod)) {
-                        // Self recursive replacement means the original
+                    if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) {
+                        // Self recursive intrinsic means the original
                         // method should be called.
                         assert !targetMethod.hasBytecodes() : "TODO: when does this happen?";
                         return false;
@@ -1256,69 +1491,56 @@
 
             private boolean tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod, JavaType returnType) {
                 InlineInvokePlugin plugin = graphBuilderConfig.getPlugins().getInlineInvokePlugin();
-                boolean canBeInlined = parsingReplacement() || targetMethod.canBeInlined();
+                boolean canBeInlined = parsingIntrinsic() || targetMethod.canBeInlined();
                 if (plugin == null || !canBeInlined) {
                     return false;
                 }
                 InlineInfo inlineInfo = plugin.getInlineInfo(this, targetMethod, args, returnType);
                 if (inlineInfo != null) {
-                    return inline(plugin, targetMethod, inlineInfo.methodToInline, inlineInfo.isReplacement, inlineInfo.isIntrinsic, args);
+                    return inline(plugin, targetMethod, inlineInfo.methodToInline, inlineInfo.isIntrinsic, args);
                 }
                 return false;
             }
 
             public void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args) {
-                boolean res = inline(null, targetMethod, substitute, true, true, args);
+                boolean res = inline(null, targetMethod, substitute, true, args);
                 assert res : "failed to inline " + substitute;
             }
 
-            private boolean inline(InlineInvokePlugin plugin, ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, boolean isReplacement, boolean isIntrinsic, ValueNode[] args) {
-                int bci = bci();
+            private boolean inline(InlineInvokePlugin plugin, ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, boolean isIntrinsic, ValueNode[] args) {
                 if (TraceInlineDuringParsing.getValue() || TraceParserPlugins.getValue()) {
                     if (targetMethod.equals(inlinedMethod)) {
                         traceWithContext("inlining call to %s", inlinedMethod.format("%h.%n(%p)"));
                     } else {
-                        traceWithContext("inlining call to %s as replacement for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)"));
+                        traceWithContext("inlining call to %s as intrinsic for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)"));
                     }
                 }
-                ReplacementContext context = this.replacementContext;
-                if (context != null && context.isCallToOriginal(targetMethod)) {
-                    IntrinsicContext intrinsic = context.asIntrinsic();
-                    if (intrinsic != null) {
-                        if (intrinsic.isCompilationRoot()) {
-                            // A root compiled intrinsic needs to deoptimize
-                            // if the slow path is taken
-                            DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint));
-                            deopt.setStateBefore(intrinsic.getInvokeStateBefore(graph, null));
-                            return true;
-                        } else {
-                            // Otherwise inline the original method. Any frame state created
-                            // during the inlining will exclude frame(s) in the
-                            // intrinsic method (see HIRFrameStateBuilder.create(int bci)).
-                            parseAndInlineCallee(context.method, args, null);
-                            return true;
-                        }
+                IntrinsicContext intrinsic = this.intrinsicContext;
+                if (intrinsic != null && intrinsic.isCallToOriginal(targetMethod)) {
+                    if (intrinsic.isCompilationRoot()) {
+                        // A root compiled intrinsic needs to deoptimize
+                        // if the slow path is taken. During frame state
+                        // assignment, the deopt node will get its stateBefore
+                        // from the start node of the intrinsic
+                        append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint));
+                        return true;
                     } else {
-                        // Self recursive replacement means the original
-                        // method should be called.
-                        if (context.method.hasBytecodes()) {
-                            parseAndInlineCallee(context.method, args, null);
-                            return true;
-                        } else {
+                        // Otherwise inline the original method. Any frame state created
+                        // during the inlining will exclude frame(s) in the
+                        // intrinsic method (see HIRFrameStateBuilder.create(int bci)).
+                        if (intrinsic.getOriginalMethod().isNative()) {
                             return false;
                         }
+                        parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null);
+                        return true;
                     }
                 } else {
-                    if (context == null && isReplacement) {
+                    if (intrinsic == null && isIntrinsic) {
                         assert !inlinedMethod.equals(targetMethod);
-                        if (isIntrinsic) {
-                            context = new IntrinsicContext(targetMethod, inlinedMethod, args, bci);
-                        } else {
-                            context = new ReplacementContext(targetMethod, inlinedMethod);
-                        }
+                        intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, INLINE_DURING_PARSING);
                     }
                     if (inlinedMethod.hasBytecodes()) {
-                        parseAndInlineCallee(inlinedMethod, args, context);
+                        parseAndInlineCallee(inlinedMethod, args, intrinsic);
                         if (plugin != null) {
                             plugin.postInline(inlinedMethod);
                         }
@@ -1342,7 +1564,7 @@
              * @param format a format string
              * @param args arguments to the format string
              */
-            @Override
+
             protected void traceWithContext(String format, Object... args) {
                 StackTraceElement where = method.asStackTraceElement(bci());
                 TTY.println(format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(),
@@ -1362,34 +1584,36 @@
                 return res;
             }
 
-            private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, ReplacementContext calleeReplacementContext) {
-                BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeReplacementContext);
-                HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, graph);
-                if (!targetMethod.isStatic()) {
-                    args[0] = nullCheckedValue(args[0]);
-                }
-                startFrameState.initializeFromArgumentsArray(args);
-                parser.build(this.lastInstr, startFrameState);
-
-                FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode();
-                this.lastInstr = calleeBeforeReturnNode;
-                if (calleeBeforeReturnNode != null) {
-                    ValueNode calleeReturnValue = parser.getReturnValue();
-                    if (calleeReturnValue != null) {
-                        frameState.push(targetMethod.getSignature().getReturnKind().getStackKind(), calleeReturnValue);
+            private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) {
+                try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, args) : null) {
+
+                    BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeIntrinsicContext);
+                    FrameStateBuilder startFrameState = new FrameStateBuilder(parser, targetMethod, graph);
+                    if (!targetMethod.isStatic()) {
+                        args[0] = nullCheckedValue(args[0]);
                     }
-                }
-
-                FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
-                if (calleeBeforeUnwindNode != null) {
-                    ValueNode calleeUnwindValue = parser.getUnwindValue();
-                    assert calleeUnwindValue != null;
-                    calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
-                }
-
-                // Record inlined method dependency in the graph
-                if (graph.isInlinedMethodRecordingEnabled()) {
-                    graph.getInlinedMethods().add(targetMethod);
+                    startFrameState.initializeFromArgumentsArray(args);
+                    parser.build(this.lastInstr, startFrameState);
+
+                    FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode();
+                    this.lastInstr = calleeBeforeReturnNode;
+                    Kind calleeReturnKind = targetMethod.getSignature().getReturnKind();
+                    if (calleeBeforeReturnNode != null) {
+                        ValueNode calleeReturnValue = parser.getReturnValue();
+                        if (calleeReturnValue != null) {
+                            frameState.push(calleeReturnKind.getStackKind(), calleeReturnValue);
+                        }
+                    }
+
+                    FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
+                    if (calleeBeforeUnwindNode != null) {
+                        ValueNode calleeUnwindValue = parser.getUnwindValue();
+                        assert calleeUnwindValue != null;
+                        calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
+                    }
+
+                    // Record inlined method dependency in the graph
+                    graph.recordInlinedMethod(targetMethod);
                 }
             }
 
@@ -1400,21 +1624,50 @@
             protected InvokeNode createInvoke(CallTargetNode callTarget, Kind resultType) {
                 InvokeNode invoke = append(new InvokeNode(callTarget, bci()));
                 frameState.pushReturn(resultType, invoke);
-                invoke.setStateAfter(createFrameState(stream.nextBCI()));
+                invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
                 return invoke;
             }
 
             protected InvokeWithExceptionNode createInvokeWithException(CallTargetNode callTarget, Kind resultType) {
+                if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) {
+                    /*
+                     * Clear non-live locals early so that the exception handler entry gets the
+                     * cleared state.
+                     */
+                    frameState.clearNonLiveLocals(currentBlock, liveness, false);
+                }
+
                 DispatchBeginNode exceptionEdge = handleException(null, bci());
                 InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
                 frameState.pushReturn(resultType, invoke);
-                invoke.setStateAfter(createFrameState(stream.nextBCI()));
+                invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
                 return invoke;
             }
 
-            @Override
             protected void genReturn(ValueNode returnVal, Kind returnKind) {
-
+                if (parsingIntrinsic() && returnVal != null) {
+                    if (returnVal instanceof StateSplit) {
+                        StateSplit stateSplit = (StateSplit) returnVal;
+                        FrameState stateAfter = stateSplit.stateAfter();
+                        if (stateSplit.hasSideEffect()) {
+                            assert stateSplit != null;
+                            if (stateAfter.bci == BytecodeFrame.AFTER_BCI) {
+                                assert stateAfter.usages().count() == 1;
+                                assert stateAfter.usages().first() == stateSplit;
+                                stateAfter.replaceAtUsages(graph.add(new FrameState(BytecodeFrame.AFTER_BCI, returnVal)));
+                                GraphUtil.killWithUnusedFloatingInputs(stateAfter);
+                            } else {
+                                /*
+                                 * This must be the return value from within a partial
+                                 * intrinsification.
+                                 */
+                                assert !BytecodeFrame.isPlaceholderBci(stateAfter.bci);
+                            }
+                        } else {
+                            assert stateAfter == null;
+                        }
+                    }
+                }
                 if (parent == null) {
                     frameState.setRethrowException(false);
                     frameState.clearStack();
@@ -1440,7 +1693,10 @@
             }
 
             private void beforeReturn(ValueNode x, Kind kind) {
-                if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
+                if (graph.method() != null && graph.method().isJavaLangObjectInit()) {
+                    append(new RegisterFinalizerNode(frameState.localAt(0)));
+                }
+                if (graphBuilderConfig.insertNonSafepointDebugInfo() && !parsingIntrinsic()) {
                     append(createInfoPointNode(InfopointReason.METHOD_END));
                 }
 
@@ -1450,15 +1706,13 @@
                 }
             }
 
-            @Override
             protected void genMonitorEnter(ValueNode x, int bci) {
                 MonitorIdNode monitorId = graph.add(new MonitorIdNode(frameState.lockDepth()));
                 MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, monitorId));
                 frameState.pushLock(x, monitorId);
-                monitorEnter.setStateAfter(createFrameState(bci));
+                monitorEnter.setStateAfter(createFrameState(bci, monitorEnter));
             }
 
-            @Override
             protected void genMonitorExit(ValueNode x, ValueNode escapedReturnValue, int bci) {
                 MonitorIdNode monitorId = frameState.peekMonitorId();
                 ValueNode lockedObject = frameState.popLock();
@@ -1466,10 +1720,9 @@
                     throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject)));
                 }
                 MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, escapedReturnValue));
-                monitorExit.setStateAfter(createFrameState(bci));
+                monitorExit.setStateAfter(createFrameState(bci, monitorExit));
             }
 
-            @Override
             protected void genJsr(int dest) {
                 BciBlock successor = currentBlock.getJsrSuccessor();
                 assert successor.startBci == dest : successor.startBci + " != " + dest + " @" + bci();
@@ -1486,7 +1739,6 @@
                 appendGoto(successor);
             }
 
-            @Override
             protected void genRet(int localIndex) {
                 BciBlock successor = currentBlock.getRetSuccessor();
                 ValueNode local = frameState.loadLocal(localIndex);
@@ -1509,7 +1761,6 @@
                 return graph.unique(nextBciNode);
             }
 
-            @Override
             protected void genIntegerSwitch(ValueNode value, ArrayList<BciBlock> actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
                 if (value.isConstant()) {
                     JavaConstant constant = (JavaConstant) value.asConstant();
@@ -1531,7 +1782,6 @@
                 }
             }
 
-            @Override
             protected ConstantNode appendConstant(JavaConstant constant) {
                 assert constant != null;
                 return ConstantNode.forConstant(constant, metaAccess, graph);
@@ -1574,7 +1824,7 @@
                 }
             }
 
-            private Target checkLoopExit(FixedNode target, BciBlock targetBlock, HIRFrameStateBuilder state) {
+            private Target checkLoopExit(FixedNode target, BciBlock targetBlock, FrameStateBuilder state) {
                 if (currentBlock != null && !explodeLoops) {
                     long exits = currentBlock.loops & ~targetBlock.loops;
                     if (exits != 0) {
@@ -1604,7 +1854,7 @@
                         if (targetBlock instanceof ExceptionDispatchBlock) {
                             bci = ((ExceptionDispatchBlock) targetBlock).deoptBci;
                         }
-                        HIRFrameStateBuilder newState = state.copy();
+                        FrameStateBuilder newState = state.copy();
                         for (BciBlock loop : exitLoops) {
                             LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(loop, this.getCurrentDimension());
                             LoopExitNode loopExit = graph.add(new LoopExitNode(loopBegin));
@@ -1617,7 +1867,7 @@
                             lastLoopExit = loopExit;
                             Debug.log("Target %s Exits %s, scanning framestates...", targetBlock, loop);
                             newState.insertLoopProxies(loopExit, getEntryState(loop, this.getCurrentDimension()));
-                            loopExit.setStateAfter(newState.create(bci));
+                            loopExit.setStateAfter(newState.create(bci, loopExit));
                         }
 
                         lastLoopExit.setNext(target);
@@ -1627,7 +1877,7 @@
                 return new Target(target, state);
             }
 
-            private HIRFrameStateBuilder getEntryState(BciBlock block, int dimension) {
+            private FrameStateBuilder getEntryState(BciBlock block, int dimension) {
                 int id = block.id;
                 if (dimension == 0) {
                     return entryStateArray[id];
@@ -1636,9 +1886,9 @@
                 }
             }
 
-            private HIRFrameStateBuilder getEntryStateMultiDimension(int dimension, int id) {
+            private FrameStateBuilder getEntryStateMultiDimension(int dimension, int id) {
                 if (entryStateMatrix != null && dimension - 1 < entryStateMatrix.length) {
-                    HIRFrameStateBuilder[] entryStateArrayEntry = entryStateMatrix[dimension - 1];
+                    FrameStateBuilder[] entryStateArrayEntry = entryStateMatrix[dimension - 1];
                     if (entryStateArrayEntry == null) {
                         return null;
                     }
@@ -1648,7 +1898,7 @@
                 }
             }
 
-            private void setEntryState(BciBlock block, int dimension, HIRFrameStateBuilder entryState) {
+            private void setEntryState(BciBlock block, int dimension, FrameStateBuilder entryState) {
                 int id = block.id;
                 if (dimension == 0) {
                     this.entryStateArray[id] = entryState;
@@ -1657,9 +1907,9 @@
                 }
             }
 
-            private void setEntryStateMultiDimension(int dimension, HIRFrameStateBuilder entryState, int id) {
+            private void setEntryStateMultiDimension(int dimension, FrameStateBuilder entryState, int id) {
                 if (entryStateMatrix == null) {
-                    entryStateMatrix = new HIRFrameStateBuilder[4][];
+                    entryStateMatrix = new FrameStateBuilder[4][];
                 }
                 if (dimension - 1 < entryStateMatrix.length) {
                     // We are within bounds.
@@ -1668,7 +1918,7 @@
                     entryStateMatrix = Arrays.copyOf(entryStateMatrix, Math.max(entryStateMatrix.length * 2, dimension));
                 }
                 if (entryStateMatrix[dimension - 1] == null) {
-                    entryStateMatrix[dimension - 1] = new HIRFrameStateBuilder[blockMap.getBlockCount()];
+                    entryStateMatrix[dimension - 1] = new FrameStateBuilder[blockMap.getBlockCount()];
                 }
                 entryStateMatrix[dimension - 1][id] = entryState;
             }
@@ -1719,7 +1969,7 @@
                 }
             }
 
-            private FixedNode createTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) {
+            private FixedNode createTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) {
                 assert probability >= 0 && probability <= 1.01 : probability;
                 if (isNeverExecutedCode(probability)) {
                     return graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
@@ -1729,11 +1979,11 @@
                 }
             }
 
-            private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state) {
+            private FixedNode createTarget(BciBlock block, FrameStateBuilder state) {
                 return createTarget(block, state, false, false);
             }
 
-            private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) {
+            private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) {
                 assert block != null && state != null;
                 assert !block.isExceptionEntry || state.stackSize() == 1;
 
@@ -1755,7 +2005,7 @@
                     targetNode = getFirstInstruction(block, operatingDimension);
                     Target target = checkLoopExit(targetNode, block, state);
                     FixedNode result = target.fixed;
-                    HIRFrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state;
+                    FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state;
                     setEntryState(block, operatingDimension, currentEntryState);
                     currentEntryState.clearNonLiveLocals(block, liveness, true);
 
@@ -1776,7 +2026,7 @@
                      */
                     LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block, operatingDimension);
                     LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin));
-                    if (parsingReplacement()) {
+                    if (parsingIntrinsic()) {
                         loopEnd.disableSafepoint();
                     }
                     Target target = checkLoopExit(loopEnd, block, state);
@@ -1828,14 +2078,14 @@
                 return result;
             }
 
-            private int findOperatingDimension(BciBlock block, HIRFrameStateBuilder state) {
+            private int findOperatingDimension(BciBlock block, FrameStateBuilder state) {
                 if (this.explodeLoops && this.explodeLoopsContext != null && !this.explodeLoopsContext.isEmpty()) {
                     return findOperatingDimensionWithLoopExplosion(block, state);
                 }
                 return this.getCurrentDimension();
             }
 
-            private int findOperatingDimensionWithLoopExplosion(BciBlock block, HIRFrameStateBuilder state) {
+            private int findOperatingDimensionWithLoopExplosion(BciBlock block, FrameStateBuilder state) {
                 for (ExplodedLoopContext context : explodeLoopsContext) {
                     if (context.header == block) {
 
@@ -1886,7 +2136,7 @@
              * Returns a block begin node with the specified state. If the specified probability is
              * 0, the block deoptimizes immediately.
              */
-            private AbstractBeginNode createBlockTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) {
+            private AbstractBeginNode createBlockTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) {
                 FixedNode target = createTarget(probability, block, stateAfter);
                 AbstractBeginNode begin = BeginNode.begin(target);
 
@@ -1895,7 +2145,7 @@
                 return begin;
             }
 
-            private ValueNode synchronizedObject(HIRFrameStateBuilder state, ResolvedJavaMethod target) {
+            private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) {
                 if (target.isStatic()) {
                     return appendConstant(target.getDeclaringClass().getJavaClass());
                 } else {
@@ -1962,7 +2212,7 @@
                     if (block instanceof ExceptionDispatchBlock) {
                         bci = ((ExceptionDispatchBlock) block).deoptBci;
                     }
-                    abstractMergeNode.setStateAfter(createFrameState(bci));
+                    abstractMergeNode.setStateAfter(createFrameState(bci, abstractMergeNode));
                 }
             }
 
@@ -2034,7 +2284,6 @@
                 }
             }
 
-            @Override
             protected void iterateBytecodesForBlock(BciBlock block) {
                 if (block.isLoopHeader && !explodeLoops) {
                     // Create the loop header block, which later will merge the backward branches of
@@ -2044,8 +2293,8 @@
                     lastInstr = loopBegin;
 
                     // Create phi functions for all local variables and operand stack slots.
-                    frameState.insertLoopPhis(liveness, block.loopId, loopBegin);
-                    loopBegin.setStateAfter(createFrameState(block.startBci));
+                    frameState.insertLoopPhis(liveness, block.loopId, loopBegin, forceLoopPhis());
+                    loopBegin.setStateAfter(createFrameState(block.startBci, loopBegin));
 
                     /*
                      * We have seen all forward branches. All subsequent backward branches will
@@ -2074,9 +2323,14 @@
                 int bci = block.startBci;
                 BytecodesParsed.add(block.endBci - bci);
 
+                /* Reset line number for new block */
+                if (graphBuilderConfig.insertSimpleDebugInfo()) {
+                    previousLineNumber = -1;
+                }
+
                 while (bci < endBCI) {
-                    if (graphBuilderConfig.insertNonSafepointDebugInfo() && lnt != null) {
-                        currentLineNumber = lnt.getLineNumber(bci);
+                    if (graphBuilderConfig.insertNonSafepointDebugInfo() && !parsingIntrinsic()) {
+                        currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : (graphBuilderConfig.insertFullDebugInfo() ? -1 : bci);
                         if (currentLineNumber != previousLineNumber) {
                             append(createInfoPointNode(InfopointReason.LINE_NUMBER));
                             previousLineNumber = currentLineNumber;
@@ -2093,7 +2347,7 @@
                         }
                         EntryMarkerNode x = append(new EntryMarkerNode());
                         frameState.insertProxies(x);
-                        x.setStateAfter(createFrameState(bci));
+                        x.setStateAfter(createFrameState(bci, x));
                     }
 
                     try {
@@ -2110,7 +2364,7 @@
                     bci = stream.currentBCI();
 
                     assert block == currentBlock;
-                    assert !(lastInstr instanceof StateSplit) || lastInstr instanceof BeginNode || ((StateSplit) lastInstr).stateAfter() != null : lastInstr;
+                    assert checkLastInstruction();
                     lastInstr = finishInstruction(lastInstr, frameState);
                     if (bci < endBCI) {
                         if (bci > block.endBci) {
@@ -2124,6 +2378,23 @@
                 }
             }
 
+            /* Also a hook for subclasses. */
+            protected boolean forceLoopPhis() {
+                return graph.isOSR();
+            }
+
+            protected boolean checkLastInstruction() {
+                if (lastInstr instanceof BeginNode) {
+                    // ignore
+                } else if (lastInstr instanceof StateSplit) {
+                    StateSplit stateSplit = (StateSplit) lastInstr;
+                    if (stateSplit.hasSideEffect()) {
+                        assert stateSplit.stateAfter() != null : "side effect " + lastInstr + " requires a non-null stateAfter";
+                    }
+                }
+                return true;
+            }
+
             private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext) {
                 EndNode preLoopEnd = graph.add(new EndNode());
                 LoopBeginNode loopBegin = graph.add(new LoopBeginNode());
@@ -2140,15 +2411,24 @@
              * @param state The current frame state.
              * @return Returns the (new) last instruction.
              */
-            protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, HIRFrameStateBuilder state) {
+            protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, FrameStateBuilder state) {
                 return instr;
             }
 
             private InfopointNode createInfoPointNode(InfopointReason reason) {
                 if (graphBuilderConfig.insertFullDebugInfo()) {
-                    return new FullInfopointNode(reason, createFrameState(bci()));
+                    return new FullInfopointNode(reason, createFrameState(bci(), null));
                 } else {
-                    return new SimpleInfopointNode(reason, new BytecodePosition(null, method, bci()));
+                    BytecodePosition position = createBytecodePosition();
+                    // Update the previous infopoint position if no new fixed nodes were inserted
+                    if (lastInstr instanceof SimpleInfopointNode) {
+                        SimpleInfopointNode lastInfopoint = (SimpleInfopointNode) lastInstr;
+                        if (lastInfopoint.getReason() == reason) {
+                            lastInfopoint.setPosition(position);
+                            return lastInfopoint;
+                        }
+                    }
+                    return new SimpleInfopointNode(reason, position);
                 }
             }
 
@@ -2171,7 +2451,6 @@
                 }
             }
 
-            @Override
             protected void genIf(ValueNode x, Condition cond, ValueNode y) {
                 assert currentBlock.getSuccessorCount() == 2;
                 BciBlock trueBlock = currentBlock.getSuccessor(0);
@@ -2247,7 +2526,7 @@
                     FixedNode falseSuccessor = createTarget(falseBlock, frameState, false, true);
                     ValueNode ifNode = genIfNode(condition, trueSuccessor, falseSuccessor, probability);
                     append(ifNode);
-                    if (parsingReplacement()) {
+                    if (parsingIntrinsic()) {
                         if (x instanceof BranchProbabilityNode) {
                             ((BranchProbabilityNode) x).simplify(null);
                         } else if (y instanceof BranchProbabilityNode) {
@@ -2377,8 +2656,8 @@
                 return parent;
             }
 
-            public Replacement getReplacement() {
-                return replacementContext;
+            public IntrinsicContext getIntrinsic() {
+                return intrinsicContext;
             }
 
             @Override
@@ -2390,7 +2669,7 @@
                     if (bp != this) {
                         fmt.format("%n%s", indent);
                     }
-                    fmt.format("%s [bci: %d, replacement: %s]", bp.method.asStackTraceElement(bp.bci()), bp.bci(), bp.parsingReplacement());
+                    fmt.format("%s [bci: %d, intrinsic: %s]", bp.method.asStackTraceElement(bp.bci()), bp.bci(), bp.parsingIntrinsic());
                     fmt.format("%n%s", new BytecodeDisassembler().disassemble(bp.method, bp.bci(), bp.bci() + 10));
                     bp = bp.parent;
                     indent += " ";
@@ -2399,21 +2678,964 @@
             }
 
             public BailoutException bailout(String string) {
-                FrameState currentFrameState = createFrameState(bci());
+                FrameState currentFrameState = createFrameState(bci(), null);
                 StackTraceElement[] elements = GraphUtil.approxSourceStackTraceElement(currentFrameState);
                 BailoutException bailout = new BailoutException(string);
                 throw GraphUtil.createBailoutException(string, bailout, elements);
             }
 
-            private FrameState createFrameState(int bci) {
+            private FrameState createFrameState(int bci, StateSplit forStateSplit) {
                 if (currentBlock != null && bci > currentBlock.endBci) {
                     frameState.clearNonLiveLocals(currentBlock, liveness, false);
                 }
-                return frameState.create(bci);
+                return frameState.create(bci, forStateSplit);
+            }
+
+            public void setStateAfter(StateSplit sideEffect) {
+                assert sideEffect.hasSideEffect();
+                FrameState stateAfter = createFrameState(stream.nextBCI(), sideEffect);
+                sideEffect.setStateAfter(stateAfter);
+            }
+
+            private BytecodePosition createBytecodePosition() {
+                return frameState.createBytecodePosition(bci());
+            }
+
+            public void setCurrentFrameState(FrameStateBuilder frameState) {
+                this.frameState = frameState;
+            }
+
+            protected final BytecodeStream getStream() {
+                return stream;
+            }
+
+            public int bci() {
+                return stream.currentBCI();
+            }
+
+            public void loadLocal(int index, Kind kind) {
+                frameState.push(kind, frameState.loadLocal(index));
+            }
+
+            public void storeLocal(Kind kind, int index) {
+                ValueNode value;
+                if (kind == Kind.Object) {
+                    value = frameState.xpop();
+                    // astore and astore_<n> may be used to store a returnAddress (jsr)
+                    assert parsingIntrinsic() || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind();
+                } else {
+                    value = frameState.pop(kind);
+                }
+                frameState.storeLocal(index, value, kind);
+            }
+
+            private void genLoadConstant(int cpi, int opcode) {
+                Object con = lookupConstant(cpi, opcode);
+
+                if (con instanceof JavaType) {
+                    // this is a load of class constant which might be unresolved
+                    JavaType type = (JavaType) con;
+                    if (type instanceof ResolvedJavaType) {
+                        frameState.push(Kind.Object, appendConstant(((ResolvedJavaType) type).getJavaClass()));
+                    } else {
+                        handleUnresolvedLoadConstant(type);
+                    }
+                } else if (con instanceof JavaConstant) {
+                    JavaConstant constant = (JavaConstant) con;
+                    frameState.push(constant.getKind().getStackKind(), appendConstant(constant));
+                } else {
+                    throw new Error("lookupConstant returned an object of incorrect type");
+                }
+            }
+
+            private void genLoadIndexed(Kind kind) {
+                ValueNode index = frameState.ipop();
+                ValueNode array = emitExplicitExceptions(frameState.apop(), index);
+                if (!tryLoadIndexedPlugin(kind, index, array)) {
+                    frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind)));
+                }
+            }
+
+            protected boolean tryLoadIndexedPlugin(Kind kind, ValueNode index, ValueNode array) {
+                LoadIndexedPlugin loadIndexedPlugin = graphBuilderConfig.getPlugins().getLoadIndexedPlugin();
+                if (loadIndexedPlugin != null && loadIndexedPlugin.apply(this, array, index, kind)) {
+                    if (TraceParserPlugins.getValue()) {
+                        traceWithContext("used load indexed plugin");
+                    }
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+
+            private void genStoreIndexed(Kind kind) {
+                ValueNode value = frameState.pop(kind.getStackKind());
+                ValueNode index = frameState.ipop();
+                ValueNode array = emitExplicitExceptions(frameState.apop(), index);
+                genStoreIndexed(array, index, kind, value);
+            }
+
+            private void stackOp(int opcode) {
+                switch (opcode) {
+                    case DUP_X1: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        frameState.xpush(w1);
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        break;
+                    }
+                    case DUP_X2: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        ValueNode w3 = frameState.xpop();
+                        frameState.xpush(w1);
+                        frameState.xpush(w3);
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        break;
+                    }
+                    case DUP2: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        break;
+                    }
+                    case DUP2_X1: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        ValueNode w3 = frameState.xpop();
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        frameState.xpush(w3);
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        break;
+                    }
+                    case DUP2_X2: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        ValueNode w3 = frameState.xpop();
+                        ValueNode w4 = frameState.xpop();
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        frameState.xpush(w4);
+                        frameState.xpush(w3);
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        break;
+                    }
+                    case SWAP: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        frameState.xpush(w1);
+                        frameState.xpush(w2);
+                        break;
+                    }
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+
+            private void genArithmeticOp(Kind result, int opcode) {
+                ValueNode y = frameState.pop(result);
+                ValueNode x = frameState.pop(result);
+                ValueNode v;
+                switch (opcode) {
+                    case IADD:
+                    case LADD:
+                        v = genIntegerAdd(x, y);
+                        break;
+                    case FADD:
+                    case DADD:
+                        v = genFloatAdd(x, y);
+                        break;
+                    case ISUB:
+                    case LSUB:
+                        v = genIntegerSub(x, y);
+                        break;
+                    case FSUB:
+                    case DSUB:
+                        v = genFloatSub(x, y);
+                        break;
+                    case IMUL:
+                    case LMUL:
+                        v = genIntegerMul(x, y);
+                        break;
+                    case FMUL:
+                    case DMUL:
+                        v = genFloatMul(x, y);
+                        break;
+                    case FDIV:
+                    case DDIV:
+                        v = genFloatDiv(x, y);
+                        break;
+                    case FREM:
+                    case DREM:
+                        v = genFloatRem(x, y);
+                        break;
+                    default:
+                        throw new GraalInternalError("should not reach");
+                }
+                frameState.push(result, append(v));
+            }
+
+            private void genIntegerDivOp(Kind result, int opcode) {
+                ValueNode y = frameState.pop(result);
+                ValueNode x = frameState.pop(result);
+                ValueNode v;
+                switch (opcode) {
+                    case IDIV:
+                    case LDIV:
+                        v = genIntegerDiv(x, y);
+                        break;
+                    case IREM:
+                    case LREM:
+                        v = genIntegerRem(x, y);
+                        break;
+                    default:
+                        throw new GraalInternalError("should not reach");
+                }
+                frameState.push(result, append(v));
+            }
+
+            private void genNegateOp(Kind kind) {
+                frameState.push(kind, append(genNegateOp(frameState.pop(kind))));
+            }
+
+            private void genShiftOp(Kind kind, int opcode) {
+                ValueNode s = frameState.ipop();
+                ValueNode x = frameState.pop(kind);
+                ValueNode v;
+                switch (opcode) {
+                    case ISHL:
+                    case LSHL:
+                        v = genLeftShift(x, s);
+                        break;
+                    case ISHR:
+                    case LSHR:
+                        v = genRightShift(x, s);
+                        break;
+                    case IUSHR:
+                    case LUSHR:
+                        v = genUnsignedRightShift(x, s);
+                        break;
+                    default:
+                        throw new GraalInternalError("should not reach");
+                }
+                frameState.push(kind, append(v));
+            }
+
+            private void genLogicOp(Kind kind, int opcode) {
+                ValueNode y = frameState.pop(kind);
+                ValueNode x = frameState.pop(kind);
+                ValueNode v;
+                switch (opcode) {
+                    case IAND:
+                    case LAND:
+                        v = genAnd(x, y);
+                        break;
+                    case IOR:
+                    case LOR:
+                        v = genOr(x, y);
+                        break;
+                    case IXOR:
+                    case LXOR:
+                        v = genXor(x, y);
+                        break;
+                    default:
+                        throw new GraalInternalError("should not reach");
+                }
+                frameState.push(kind, append(v));
+            }
+
+            private void genCompareOp(Kind kind, boolean isUnorderedLess) {
+                ValueNode y = frameState.pop(kind);
+                ValueNode x = frameState.pop(kind);
+                frameState.ipush(append(genNormalizeCompare(x, y, isUnorderedLess)));
+            }
+
+            private void genFloatConvert(FloatConvert op, Kind from, Kind to) {
+                ValueNode input = frameState.pop(from.getStackKind());
+                frameState.push(to.getStackKind(), append(genFloatConvert(op, input)));
+            }
+
+            private void genSignExtend(Kind from, Kind to) {
+                ValueNode input = frameState.pop(from.getStackKind());
+                if (from != from.getStackKind()) {
+                    input = append(genNarrow(input, from.getBitCount()));
+                }
+                frameState.push(to.getStackKind(), append(genSignExtend(input, to.getBitCount())));
+            }
+
+            private void genZeroExtend(Kind from, Kind to) {
+                ValueNode input = frameState.pop(from.getStackKind());
+                if (from != from.getStackKind()) {
+                    input = append(genNarrow(input, from.getBitCount()));
+                }
+                frameState.push(to.getStackKind(), append(genZeroExtend(input, to.getBitCount())));
+            }
+
+            private void genNarrow(Kind from, Kind to) {
+                ValueNode input = frameState.pop(from.getStackKind());
+                frameState.push(to.getStackKind(), append(genNarrow(input, to.getBitCount())));
+            }
+
+            private void genIncrement() {
+                int index = getStream().readLocalIndex();
+                int delta = getStream().readIncrement();
+                ValueNode x = frameState.loadLocal(index);
+                ValueNode y = appendConstant(JavaConstant.forInt(delta));
+                frameState.storeLocal(index, append(genIntegerAdd(x, y)));
+            }
+
+            private void genIfZero(Condition cond) {
+                ValueNode y = appendConstant(JavaConstant.INT_0);
+                ValueNode x = frameState.ipop();
+                genIf(x, cond, y);
+            }
+
+            private void genIfNull(Condition cond) {
+                ValueNode y = appendConstant(JavaConstant.NULL_POINTER);
+                ValueNode x = frameState.apop();
+                genIf(x, cond, y);
+            }
+
+            private void genIfSame(Kind kind, Condition cond) {
+                ValueNode y = frameState.pop(kind);
+                ValueNode x = frameState.pop(kind);
+                genIf(x, cond, y);
+            }
+
+            protected JavaType lookupType(int cpi, int bytecode) {
+                maybeEagerlyResolve(cpi, bytecode);
+                JavaType result = constantPool.lookupType(cpi, bytecode);
+                assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType;
+                return result;
+            }
+
+            private JavaMethod lookupMethod(int cpi, int opcode) {
+                maybeEagerlyResolve(cpi, opcode);
+                JavaMethod result = constantPool.lookupMethod(cpi, opcode);
+                /*
+                 * In general, one cannot assume that the declaring class being initialized is
+                 * useful, since the actual concrete receiver may be a different class (except for
+                 * static calls). Also, interfaces are initialized only under special circumstances,
+                 * so that this assertion would often fail for interface calls.
+                 */
+                assert !graphBuilderConfig.unresolvedIsError() ||
+                                (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result;
+                return result;
+            }
+
+            private JavaField lookupField(int cpi, int opcode) {
+                maybeEagerlyResolve(cpi, opcode);
+                JavaField result = constantPool.lookupField(cpi, opcode);
+                assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
+                return result;
+            }
+
+            private Object lookupConstant(int cpi, int opcode) {
+                maybeEagerlyResolve(cpi, opcode);
+                Object result = constantPool.lookupConstant(cpi);
+                assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result;
+                return result;
+            }
+
+            private void maybeEagerlyResolve(int cpi, int bytecode) {
+                if (graphBuilderConfig.eagerResolving() || intrinsicContext != null) {
+                    constantPool.loadReferencedType(cpi, bytecode);
+                }
+            }
+
+            private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) {
+                if (parsingIntrinsic() || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
+                    return null;
+                } else {
+                    return profilingInfo.getTypeProfile(bci());
+                }
+            }
+
+            private void genCheckCast() {
+                int cpi = getStream().readCPI();
+                JavaType type = lookupType(cpi, CHECKCAST);
+                ValueNode object = frameState.apop();
+                if (type instanceof ResolvedJavaType) {
+                    ResolvedJavaType resolvedType = (ResolvedJavaType) type;
+                    JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
+                    TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin();
+                    if (typeCheckPlugin == null || !typeCheckPlugin.checkCast(this, object, resolvedType, profile)) {
+                        ValueNode checkCastNode = null;
+                        if (profile != null) {
+                            if (profile.getNullSeen().isFalse()) {
+                                object = append(GuardingPiNode.createNullCheck(object));
+                                ResolvedJavaType singleType = profile.asSingleType();
+                                if (singleType != null) {
+                                    LogicNode typeCheck = append(TypeCheckNode.create(singleType, object));
+                                    if (typeCheck.isTautology()) {
+                                        checkCastNode = object;
+                                    } else {
+                                        GuardingPiNode piNode = append(new GuardingPiNode(object, typeCheck, false, DeoptimizationReason.TypeCheckedInliningViolated,
+                                                        DeoptimizationAction.InvalidateReprofile, StampFactory.exactNonNull(singleType)));
+                                        checkCastNode = piNode;
+                                    }
+                                }
+                            }
+                        }
+                        if (checkCastNode == null) {
+                            checkCastNode = append(createCheckCast(resolvedType, object, profile, false));
+                        }
+                        frameState.apush(checkCastNode);
+                    }
+                } else {
+                    handleUnresolvedCheckCast(type, object);
+                }
+            }
+
+            private void genInstanceOf() {
+                int cpi = getStream().readCPI();
+                JavaType type = lookupType(cpi, INSTANCEOF);
+                ValueNode object = frameState.apop();
+                if (type instanceof ResolvedJavaType) {
+                    ResolvedJavaType resolvedType = (ResolvedJavaType) type;
+                    JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
+                    TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin();
+                    if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf(this, object, resolvedType, profile)) {
+                        ValueNode instanceOfNode = null;
+                        if (profile != null) {
+                            if (profile.getNullSeen().isFalse()) {
+                                object = append(GuardingPiNode.createNullCheck(object));
+                                ResolvedJavaType singleType = profile.asSingleType();
+                                if (singleType != null) {
+                                    LogicNode typeCheck = append(TypeCheckNode.create(singleType, object));
+                                    append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
+                                    instanceOfNode = LogicConstantNode.forBoolean(resolvedType.isAssignableFrom(singleType));
+                                }
+                            }
+                        }
+                        if (instanceOfNode == null) {
+                            instanceOfNode = createInstanceOf(resolvedType, object, profile);
+                        }
+                        frameState.ipush(append(genConditional(genUnique(instanceOfNode))));
+                    }
+                } else {
+                    handleUnresolvedInstanceOf(type, object);
+                }
+            }
+
+            void genNewInstance(int cpi) {
+                JavaType type = lookupType(cpi, NEW);
+                if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
+                    ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes();
+                    if (skippedExceptionTypes != null) {
+                        for (ResolvedJavaType exceptionType : skippedExceptionTypes) {
+                            if (exceptionType.isAssignableFrom((ResolvedJavaType) type)) {
+                                append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter));
+                                return;
+                            }
+                        }
+                    }
+                    frameState.apush(append(createNewInstance((ResolvedJavaType) type, true)));
+                } else {
+                    handleUnresolvedNewInstance(type);
+                }
+            }
+
+            private void genNewPrimitiveArray(int typeCode) {
+                Class<?> clazz = arrayTypeCodeToClass(typeCode);
+                ResolvedJavaType elementType = metaAccess.lookupJavaType(clazz);
+                frameState.apush(append(createNewArray(elementType, frameState.ipop(), true)));
+            }
+
+            private void genNewObjectArray(int cpi) {
+                JavaType type = lookupType(cpi, ANEWARRAY);
+                ValueNode length = frameState.ipop();
+                if (type instanceof ResolvedJavaType) {
+                    frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true)));
+                } else {
+                    handleUnresolvedNewObjectArray(type, length);
+                }
+
             }
 
-            public FrameState createStateAfter() {
-                return createFrameState(stream.nextBCI());
+            private void genNewMultiArray(int cpi) {
+                JavaType type = lookupType(cpi, MULTIANEWARRAY);
+                int rank = getStream().readUByte(bci() + 3);
+                List<ValueNode> dims = new ArrayList<>(Collections.nCopies(rank, null));
+                for (int i = rank - 1; i >= 0; i--) {
+                    dims.set(i, frameState.ipop());
+                }
+                if (type instanceof ResolvedJavaType) {
+                    frameState.apush(append(createNewMultiArray((ResolvedJavaType) type, dims)));
+                } else {
+                    handleUnresolvedNewMultiArray(type, dims);
+                }
+            }
+
+            private void genGetField(JavaField field) {
+                Kind kind = field.getKind();
+                ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
+                if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
+                    LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
+                    if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) {
+                        appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
+                    }
+                } else {
+                    handleUnresolvedLoadField(field, receiver);
+                }
+            }
+
+            /**
+             * @param receiver the receiver of an object based operation
+             * @param index the index of an array based operation that is to be tested for out of
+             *            bounds. This is null for a non-array operation.
+             * @return the receiver value possibly modified to have a tighter stamp
+             */
+            protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) {
+                assert receiver != null;
+                if (graphBuilderConfig.omitAllExceptionEdges() ||
+                                profilingInfo == null ||
+                                (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) {
+                    return receiver;
+                }
+
+                ValueNode nonNullReceiver = emitExplicitNullCheck(receiver);
+                if (index != null) {
+                    ValueNode length = append(genArrayLength(nonNullReceiver));
+                    emitExplicitBoundsCheck(index, length);
+                }
+                EXPLICIT_EXCEPTIONS.increment();
+                return nonNullReceiver;
+            }
+
+            private void genPutField(JavaField field) {
+                ValueNode value = frameState.pop(field.getKind().getStackKind());
+                ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
+                if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
+                    genStoreField(receiver, (ResolvedJavaField) field, value);
+                } else {
+                    handleUnresolvedStoreField(field, value, receiver);
+                }
+            }
+
+            private void genGetStatic(JavaField field) {
+                Kind kind = field.getKind();
+                if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
+                    ResolvedJavaField resolvedField = (ResolvedJavaField) field;
+                    // Javac does not allow use of "$assertionsDisabled" for a field name but
+                    // Eclipse does in which case a suffix is added to the generated field.
+                    if ((parsingIntrinsic() || graphBuilderConfig.omitAssertions()) && resolvedField.isSynthetic() && resolvedField.getName().startsWith("$assertionsDisabled")) {
+                        appendOptimizedLoadField(kind, ConstantNode.forBoolean(true));
+                        return;
+                    }
+
+                    LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
+                    if (loadFieldPlugin == null || !loadFieldPlugin.apply(this, resolvedField)) {
+                        appendOptimizedLoadField(kind, genLoadField(null, resolvedField));
+                    }
+                } else {
+                    handleUnresolvedLoadField(field, null);
+                }
+            }
+
+            public boolean tryLoadFieldPlugin(JavaField field, LoadFieldPlugin loadFieldPlugin) {
+                return loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field);
+            }
+
+            private void genPutStatic(JavaField field) {
+                ValueNode value = frameState.pop(field.getKind().getStackKind());
+                if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
+                    genStoreField(null, (ResolvedJavaField) field, value);
+                } else {
+                    handleUnresolvedStoreField(field, value, null);
+                }
+            }
+
+            protected void appendOptimizedLoadField(Kind kind, ValueNode load) {
+                // append the load to the instruction
+                ValueNode optimized = append(load);
+                frameState.push(kind.getStackKind(), optimized);
+            }
+
+            private double[] switchProbability(int numberOfCases, int bci) {
+                double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci));
+                if (prob != null) {
+                    assert prob.length == numberOfCases;
+                } else {
+                    Debug.log("Missing probability (switch) in %s at bci %d", method, bci);
+                    prob = new double[numberOfCases];
+                    for (int i = 0; i < numberOfCases; i++) {
+                        prob[i] = 1.0d / numberOfCases;
+                    }
+                }
+                assert allPositive(prob);
+                return prob;
+            }
+
+            private void genSwitch(BytecodeSwitch bs) {
+                int bci = bci();
+                ValueNode value = frameState.ipop();
+
+                int nofCases = bs.numberOfCases();
+                double[] keyProbabilities = switchProbability(nofCases + 1, bci);
+
+                Map<Integer, SuccessorInfo> bciToBlockSuccessorIndex = new HashMap<>();
+                for (int i = 0; i < currentBlock.getSuccessorCount(); i++) {
+                    assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci);
+                    if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) {
+                        bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i));
+                    }
+                }
+
+                ArrayList<BciBlock> actualSuccessors = new ArrayList<>();
+                int[] keys = new int[nofCases];
+                int[] keySuccessors = new int[nofCases + 1];
+                int deoptSuccessorIndex = -1;
+                int nextSuccessorIndex = 0;
+                boolean constantValue = value.isConstant();
+                for (int i = 0; i < nofCases + 1; i++) {
+                    if (i < nofCases) {
+                        keys[i] = bs.keyAt(i);
+                    }
+
+                    if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) {
+                        if (deoptSuccessorIndex < 0) {
+                            deoptSuccessorIndex = nextSuccessorIndex++;
+                            actualSuccessors.add(null);
+                        }
+                        keySuccessors[i] = deoptSuccessorIndex;
+                    } else {
+                        int targetBci = i >= nofCases ? bs.defaultTarget() : bs.targetAt(i);
+                        SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci);
+                        if (info.actualIndex < 0) {
+                            info.actualIndex = nextSuccessorIndex++;
+                            actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex));
+                        }
+                        keySuccessors[i] = info.actualIndex;
+                    }
+                }
+
+                genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors);
+
+            }
+
+            protected boolean isNeverExecutedCode(double probability) {
+                return probability == 0 && optimisticOpts.removeNeverExecutedCode();
+            }
+
+            protected double branchProbability() {
+                if (profilingInfo == null) {
+                    return 0.5;
+                }
+                assert assertAtIfBytecode();
+                double probability = profilingInfo.getBranchTakenProbability(bci());
+                if (probability < 0) {
+                    assert probability == -1 : "invalid probability";
+                    Debug.log("missing probability in %s at bci %d", method, bci());
+                    probability = 0.5;
+                }
+
+                if (!optimisticOpts.removeNeverExecutedCode()) {
+                    if (probability == 0) {
+                        probability = 0.0000001;
+                    } else if (probability == 1) {
+                        probability = 0.999999;
+                    }
+                }
+                return probability;
+            }
+
+            private boolean assertAtIfBytecode() {
+                int bytecode = stream.currentBC();
+                switch (bytecode) {
+                    case IFEQ:
+                    case IFNE:
+                    case IFLT:
+                    case IFGE:
+                    case IFGT:
+                    case IFLE:
+                    case IF_ICMPEQ:
+                    case IF_ICMPNE:
+                    case IF_ICMPLT:
+                    case IF_ICMPGE:
+                    case IF_ICMPGT:
+                    case IF_ICMPLE:
+                    case IF_ACMPEQ:
+                    case IF_ACMPNE:
+                    case IFNULL:
+                    case IFNONNULL:
+                        return true;
+                }
+                assert false : String.format("%x is not an if bytecode", bytecode);
+                return true;
+            }
+
+            public final void processBytecode(int bci, int opcode) {
+                int cpi;
+
+                // Checkstyle: stop
+                // @formatter:off
+                switch (opcode) {
+                    case NOP            : /* nothing to do */ break;
+                    case ACONST_NULL    : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break;
+                    case ICONST_M1      : // fall through
+                    case ICONST_0       : // fall through
+                    case ICONST_1       : // fall through
+                    case ICONST_2       : // fall through
+                    case ICONST_3       : // fall through
+                    case ICONST_4       : // fall through
+                    case ICONST_5       : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break;
+                    case LCONST_0       : // fall through
+                    case LCONST_1       : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break;
+                    case FCONST_0       : // fall through
+                    case FCONST_1       : // fall through
+                    case FCONST_2       : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break;
+                    case DCONST_0       : // fall through
+                    case DCONST_1       : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break;
+                    case BIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break;
+                    case SIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break;
+                    case LDC            : // fall through
+                    case LDC_W          : // fall through
+                    case LDC2_W         : genLoadConstant(stream.readCPI(), opcode); break;
+                    case ILOAD          : loadLocal(stream.readLocalIndex(), Kind.Int); break;
+                    case LLOAD          : loadLocal(stream.readLocalIndex(), Kind.Long); break;
+                    case FLOAD          : loadLocal(stream.readLocalIndex(), Kind.Float); break;
+                    case DLOAD          : loadLocal(stream.readLocalIndex(), Kind.Double); break;
+                    case ALOAD          : loadLocal(stream.readLocalIndex(), Kind.Object); break;
+                    case ILOAD_0        : // fall through
+                    case ILOAD_1        : // fall through
+                    case ILOAD_2        : // fall through
+                    case ILOAD_3        : loadLocal(opcode - ILOAD_0, Kind.Int); break;
+                    case LLOAD_0        : // fall through
+                    case LLOAD_1        : // fall through
+                    case LLOAD_2        : // fall through
+                    case LLOAD_3        : loadLocal(opcode - LLOAD_0, Kind.Long); break;
+                    case FLOAD_0        : // fall through
+                    case FLOAD_1        : // fall through
+                    case FLOAD_2        : // fall through
+                    case FLOAD_3        : loadLocal(opcode - FLOAD_0, Kind.Float); break;
+                    case DLOAD_0        : // fall through
+                    case DLOAD_1        : // fall through
+                    case DLOAD_2        : // fall through
+                    case DLOAD_3        : loadLocal(opcode - DLOAD_0, Kind.Double); break;
+                    case ALOAD_0        : // fall through
+                    case ALOAD_1        : // fall through
+                    case ALOAD_2        : // fall through
+                    case ALOAD_3        : loadLocal(opcode - ALOAD_0, Kind.Object); break;
+                    case IALOAD         : genLoadIndexed(Kind.Int   ); break;
+                    case LALOAD         : genLoadIndexed(Kind.Long  ); break;
+                    case FALOAD         : genLoadIndexed(Kind.Float ); break;
+                    case DALOAD         : genLoadIndexed(Kind.Double); break;
+                    case AALOAD         : genLoadIndexed(Kind.Object); break;
+                    case BALOAD         : genLoadIndexed(Kind.Byte  ); break;
+                    case CALOAD         : genLoadIndexed(Kind.Char  ); break;
+                    case SALOAD         : genLoadIndexed(Kind.Short ); break;
+                    case ISTORE         : storeLocal(Kind.Int, stream.readLocalIndex()); break;
+                    case LSTORE         : storeLocal(Kind.Long, stream.readLocalIndex()); break;
+                    case FSTORE         : storeLocal(Kind.Float, stream.readLocalIndex()); break;
+                    case DSTORE         : storeLocal(Kind.Double, stream.readLocalIndex()); break;
+                    case ASTORE         : storeLocal(Kind.Object, stream.readLocalIndex()); break;
+                    case ISTORE_0       : // fall through
+                    case ISTORE_1       : // fall through
+                    case ISTORE_2       : // fall through
+                    case ISTORE_3       : storeLocal(Kind.Int, opcode - ISTORE_0); break;
+                    case LSTORE_0       : // fall through
+                    case LSTORE_1       : // fall through
+                    case LSTORE_2       : // fall through
+                    case LSTORE_3       : storeLocal(Kind.Long, opcode - LSTORE_0); break;
+                    case FSTORE_0       : // fall through
+                    case FSTORE_1       : // fall through
+                    case FSTORE_2       : // fall through
+                    case FSTORE_3       : storeLocal(Kind.Float, opcode - FSTORE_0); break;
+                    case DSTORE_0       : // fall through
+                    case DSTORE_1       : // fall through
+                    case DSTORE_2       : // fall through
+                    case DSTORE_3       : storeLocal(Kind.Double, opcode - DSTORE_0); break;
+                    case ASTORE_0       : // fall through
+                    case ASTORE_1       : // fall through
+                    case ASTORE_2       : // fall through
+                    case ASTORE_3       : storeLocal(Kind.Object, opcode - ASTORE_0); break;
+                    case IASTORE        : genStoreIndexed(Kind.Int   ); break;
+                    case LASTORE        : genStoreIndexed(Kind.Long  ); break;
+                    case FASTORE        : genStoreIndexed(Kind.Float ); break;
+                    case DASTORE        : genStoreIndexed(Kind.Double); break;
+                    case AASTORE        : genStoreIndexed(Kind.Object); break;
+                    case BASTORE        : genStoreIndexed(Kind.Byte  ); break;
+                    case CASTORE        : genStoreIndexed(Kind.Char  ); break;
+                    case SASTORE        : genStoreIndexed(Kind.Short ); break;
+                    case POP            : frameState.xpop(); break;
+                    case POP2           : frameState.xpop(); frameState.xpop(); break;
+                    case DUP            : frameState.xpush(frameState.xpeek()); break;
+                    case DUP_X1         : // fall through
+                    case DUP_X2         : // fall through
+                    case DUP2           : // fall through
+                    case DUP2_X1        : // fall through
+                    case DUP2_X2        : // fall through
+                    case SWAP           : stackOp(opcode); break;
+                    case IADD           : // fall through
+                    case ISUB           : // fall through
+                    case IMUL           : genArithmeticOp(Kind.Int, opcode); break;
+                    case IDIV           : // fall through
+                    case IREM           : genIntegerDivOp(Kind.Int, opcode); break;
+                    case LADD           : // fall through
+                    case LSUB           : // fall through
+                    case LMUL           : genArithmeticOp(Kind.Long, opcode); break;
+                    case LDIV           : // fall through
+                    case LREM           : genIntegerDivOp(Kind.Long, opcode); break;
+                    case FADD           : // fall through
+                    case FSUB           : // fall through
+                    case FMUL           : // fall through
+                    case FDIV           : // fall through
+                    case FREM           : genArithmeticOp(Kind.Float, opcode); break;
+                    case DADD           : // fall through
+                    case DSUB           : // fall through
+                    case DMUL           : // fall through
+                    case DDIV           : // fall through
+                    case DREM           : genArithmeticOp(Kind.Double, opcode); break;
+                    case INEG           : genNegateOp(Kind.Int); break;
+                    case LNEG           : genNegateOp(Kind.Long); break;
+                    case FNEG           : genNegateOp(Kind.Float); break;
+                    case DNEG           : genNegateOp(Kind.Double); break;
+                    case ISHL           : // fall through
+                    case ISHR           : // fall through
+                    case IUSHR          : genShiftOp(Kind.Int, opcode); break;
+                    case IAND           : // fall through
+                    case IOR            : // fall through
+                    case IXOR           : genLogicOp(Kind.Int, opcode); break;
+                    case LSHL           : // fall through
+                    case LSHR           : // fall through
+                    case LUSHR          : genShiftOp(Kind.Long, opcode); break;
+                    case LAND           : // fall through
+                    case LOR            : // fall through
+                    case LXOR           : genLogicOp(Kind.Long, opcode); break;
+                    case IINC           : genIncrement(); break;
+                    case I2F            : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break;
+                    case I2D            : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break;
+                    case L2F            : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break;
+                    case L2D            : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break;
+                    case F2I            : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break;
+                    case F2L            : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break;
+                    case F2D            : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break;
+                    case D2I            : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break;
+                    case D2L            : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break;
+                    case D2F            : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break;
+                    case L2I            : genNarrow(Kind.Long, Kind.Int); break;
+                    case I2L            : genSignExtend(Kind.Int, Kind.Long); break;
+                    case I2B            : genSignExtend(Kind.Byte, Kind.Int); break;
+                    case I2S            : genSignExtend(Kind.Short, Kind.Int); break;
+                    case I2C            : genZeroExtend(Kind.Char, Kind.Int); break;
+                    case LCMP           : genCompareOp(Kind.Long, false); break;
+                    case FCMPL          : genCompareOp(Kind.Float, true); break;
+                    case FCMPG          : genCompareOp(Kind.Float, false); break;
+                    case DCMPL          : genCompareOp(Kind.Double, true); break;
+                    case DCMPG          : genCompareOp(Kind.Double, false); break;
+                    case IFEQ           : genIfZero(Condition.EQ); break;
+                    case IFNE           : genIfZero(Condition.NE); break;
+                    case IFLT           : genIfZero(Condition.LT); break;
+                    case IFGE           : genIfZero(Condition.GE); break;
+                    case IFGT           : genIfZero(Condition.GT); break;
+                    case IFLE           : genIfZero(Condition.LE); break;
+                    case IF_ICMPEQ      : genIfSame(Kind.Int, Condition.EQ); break;
+                    case IF_ICMPNE      : genIfSame(Kind.Int, Condition.NE); break;
+                    case IF_ICMPLT      : genIfSame(Kind.Int, Condition.LT); break;
+                    case IF_ICMPGE      : genIfSame(Kind.Int, Condition.GE); break;
+                    case IF_ICMPGT      : genIfSame(Kind.Int, Condition.GT); break;
+                    case IF_ICMPLE      : genIfSame(Kind.Int, Condition.LE); break;
+                    case IF_ACMPEQ      : genIfSame(Kind.Object, Condition.EQ); break;
+                    case IF_ACMPNE      : genIfSame(Kind.Object, Condition.NE); break;
+                    case GOTO           : genGoto(); break;
+                    case JSR            : genJsr(stream.readBranchDest()); break;
+                    case RET            : genRet(stream.readLocalIndex()); break;
+                    case TABLESWITCH    : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break;
+                    case LOOKUPSWITCH   : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break;
+                    case IRETURN        : genReturn(frameState.ipop(), Kind.Int); break;
+                    case LRETURN        : genReturn(frameState.lpop(), Kind.Long); break;
+                    case FRETURN        : genReturn(frameState.fpop(), Kind.Float); break;
+                    case DRETURN        : genReturn(frameState.dpop(), Kind.Double); break;
+                    case ARETURN        : genReturn(frameState.apop(), Kind.Object); break;
+                    case RETURN         : genReturn(null, Kind.Void); break;
+                    case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break;
+                    case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break;
+                    case GETFIELD       : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break;
+                    case PUTFIELD       : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break;
+                    case INVOKEVIRTUAL  : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break;
+                    case INVOKESPECIAL  : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break;
+                    case INVOKESTATIC   : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break;
+                    case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break;
+                    case INVOKEDYNAMIC  : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break;
+                    case NEW            : genNewInstance(stream.readCPI()); break;
+                    case NEWARRAY       : genNewPrimitiveArray(stream.readLocalIndex()); break;
+                    case ANEWARRAY      : genNewObjectArray(stream.readCPI()); break;
+                    case ARRAYLENGTH    : genArrayLength(); break;
+                    case ATHROW         : genThrow(); break;
+                    case CHECKCAST      : genCheckCast(); break;
+                    case INSTANCEOF     : genInstanceOf(); break;
+                    case MONITORENTER   : genMonitorEnter(frameState.apop(), stream.nextBCI()); break;
+                    case MONITOREXIT    : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break;
+                    case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break;
+                    case IFNULL         : genIfNull(Condition.EQ); break;
+                    case IFNONNULL      : genIfNull(Condition.NE); break;
+                    case GOTO_W         : genGoto(); break;
+                    case JSR_W          : genJsr(stream.readBranchDest()); break;
+                    case BREAKPOINT:
+                        throw new BailoutException("concurrent setting of breakpoint");
+                    default:
+                        throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci);
+                }
+                // @formatter:on
+                // Checkstyle: resume
+            }
+
+            private void genArrayLength() {
+                frameState.ipush(append(genArrayLength(frameState.apop())));
+            }
+
+            public ResolvedJavaMethod getMethod() {
+                return method;
+            }
+
+            public FrameStateBuilder getFrameStateBuilder() {
+                return frameState;
+            }
+
+            protected boolean traceInstruction(int bci, int opcode, boolean blockStart) {
+                if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) {
+                    traceInstructionHelper(bci, opcode, blockStart);
+                }
+                return true;
+            }
+
+            private void traceInstructionHelper(int bci, int opcode, boolean blockStart) {
+                StringBuilder sb = new StringBuilder(40);
+                sb.append(blockStart ? '+' : '|');
+                if (bci < 10) {
+                    sb.append("  ");
+                } else if (bci < 100) {
+                    sb.append(' ');
+                }
+                sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode));
+                for (int i = bci + 1; i < stream.nextBCI(); ++i) {
+                    sb.append(' ').append(stream.readUByte(i));
+                }
+                if (!currentBlock.getJsrScope().isEmpty()) {
+                    sb.append(' ').append(currentBlock.getJsrScope());
+                }
+                Debug.log("%s", sb);
+            }
+
+            public boolean parsingIntrinsic() {
+                return intrinsicContext != null;
+            }
+
+            public BytecodeParser getNonIntrinsicAncestor() {
+                BytecodeParser ancestor = parent;
+                while (ancestor != null && ancestor.parsingIntrinsic()) {
+                    ancestor = ancestor.parent;
+                }
+                return ancestor;
             }
         }
     }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,973 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.java;
-
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.util.*;
-
-public final class HIRFrameStateBuilder {
-
-    static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
-    static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
-
-    protected final BytecodeParser parser;
-    protected final ResolvedJavaMethod method;
-    protected int stackSize;
-    protected final ValueNode[] locals;
-    protected final ValueNode[] stack;
-    protected ValueNode[] lockedObjects;
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    protected boolean rethrowException;
-
-    private MonitorIdNode[] monitorIds;
-    private final StructuredGraph graph;
-    private FrameState outerFrameState;
-
-    /**
-     * Creates a new frame state builder for the given method and the given target graph.
-     *
-     * @param method the method whose frame is simulated
-     * @param graph the target graph of Graal nodes created by the builder
-     */
-    public HIRFrameStateBuilder(BytecodeParser parser, ResolvedJavaMethod method, StructuredGraph graph) {
-        this.parser = parser;
-        this.method = method;
-        this.locals = allocateArray(method.getMaxLocals());
-        this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
-        this.lockedObjects = allocateArray(0);
-
-        assert graph != null;
-
-        this.monitorIds = EMPTY_MONITOR_ARRAY;
-        this.graph = graph;
-    }
-
-    public void initializeFromArgumentsArray(ValueNode[] arguments) {
-
-        int javaIndex = 0;
-        int index = 0;
-        if (!method.isStatic()) {
-            // set the receiver
-            locals[javaIndex] = arguments[index];
-            javaIndex = 1;
-            index = 1;
-        }
-        Signature sig = method.getSignature();
-        int max = sig.getParameterCount(false);
-        for (int i = 0; i < max; i++) {
-            Kind kind = sig.getParameterKind(i);
-            locals[javaIndex] = arguments[index];
-            javaIndex += kind.getSlotCount();
-            index++;
-        }
-    }
-
-    public void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) {
-
-        int javaIndex = 0;
-        int index = 0;
-        if (!method.isStatic()) {
-            // add the receiver
-            FloatingNode receiver = null;
-            Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass());
-            if (parameterPlugin != null) {
-                receiver = parameterPlugin.interceptParameter(parser, index, receiverStamp);
-            }
-            if (receiver == null) {
-                receiver = new ParameterNode(javaIndex, receiverStamp);
-            }
-            locals[javaIndex] = graph.unique(receiver);
-            javaIndex = 1;
-            index = 1;
-        }
-        Signature sig = method.getSignature();
-        int max = sig.getParameterCount(false);
-        ResolvedJavaType accessingClass = method.getDeclaringClass();
-        for (int i = 0; i < max; i++) {
-            JavaType type = sig.getParameterType(i, accessingClass);
-            if (eagerResolve) {
-                type = type.resolve(accessingClass);
-            }
-            Kind kind = type.getKind();
-            Stamp stamp;
-            if (kind == Kind.Object && type instanceof ResolvedJavaType) {
-                stamp = StampFactory.declared((ResolvedJavaType) type);
-            } else {
-                stamp = StampFactory.forKind(kind);
-            }
-            FloatingNode param = null;
-            if (parameterPlugin != null) {
-                param = parameterPlugin.interceptParameter(parser, index, stamp);
-            }
-            if (param == null) {
-                param = new ParameterNode(index, stamp);
-            }
-            locals[javaIndex] = graph.unique(param);
-            javaIndex += kind.getSlotCount();
-            index++;
-        }
-
-        if (parser.replacementContext instanceof IntrinsicContext) {
-            IntrinsicContext intrinsic = (IntrinsicContext) parser.replacementContext;
-            if (intrinsic.isCompilationRoot()) {
-                // Records the parameters to an root compiled intrinsic
-                intrinsic.args = locals.clone();
-            }
-        }
-    }
-
-    private HIRFrameStateBuilder(HIRFrameStateBuilder other) {
-        this.parser = other.parser;
-        this.method = other.method;
-        this.stackSize = other.stackSize;
-        this.locals = other.locals.clone();
-        this.stack = other.stack.clone();
-        this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
-        this.rethrowException = other.rethrowException;
-
-        assert locals.length == method.getMaxLocals();
-        assert stack.length == Math.max(1, method.getMaxStackSize());
-
-        assert other.graph != null;
-        graph = other.graph;
-        monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone();
-
-        assert locals.length == method.getMaxLocals();
-        assert stack.length == Math.max(1, method.getMaxStackSize());
-        assert lockedObjects.length == monitorIds.length;
-    }
-
-    private static ValueNode[] allocateArray(int length) {
-        return length == 0 ? EMPTY_ARRAY : new ValueNode[length];
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("[locals: [");
-        for (int i = 0; i < locals.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString(Verbosity.Id));
-        }
-        sb.append("] stack: [");
-        for (int i = 0; i < stackSize; i++) {
-            sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id));
-        }
-        sb.append("] locks: [");
-        for (int i = 0; i < lockedObjects.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id));
-        }
-        sb.append("]");
-        if (rethrowException) {
-            sb.append(" rethrowException");
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
-    public FrameState create(int bci) {
-        BytecodeParser parent = parser.getParent();
-        if (parser.parsingReplacement()) {
-            IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic();
-            if (intrinsic != null) {
-                return intrinsic.getInvokeStateBefore(parser.getGraph(), parent);
-            }
-        }
-        // If this is the recursive call in a partial intrinsification
-        // the frame(s) of the intrinsic method are omitted
-        while (parent != null && parent.parsingReplacement() && parent.replacementContext.asIntrinsic() != null) {
-            parent = parent.getParent();
-        }
-        return create(bci, parent, false);
-    }
-
-    public FrameState create(int bci, BytecodeParser parent, boolean duringCall) {
-        if (outerFrameState == null && parent != null) {
-            outerFrameState = parent.getFrameState().create(parent.bci());
-        }
-        if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
-            FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0));
-            return newFrameState;
-        }
-        if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
-            throw GraalInternalError.shouldNotReachHere();
-            // return graph.add(new FrameState(bci));
-        }
-        return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
-    }
-
-    public HIRFrameStateBuilder copy() {
-        return new HIRFrameStateBuilder(this);
-    }
-
-    public boolean isCompatibleWith(HIRFrameStateBuilder other) {
-        assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
-        assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds";
-
-        if (stackSize() != other.stackSize()) {
-            return false;
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            ValueNode x = stackAt(i);
-            ValueNode y = other.stackAt(i);
-            if (x != y && (x == null || x.isDeleted() || y == null || y.isDeleted() || x.getKind() != y.getKind())) {
-                return false;
-            }
-        }
-        if (lockedObjects.length != other.lockedObjects.length) {
-            return false;
-        }
-        for (int i = 0; i < lockedObjects.length; i++) {
-            if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) {
-                throw new BailoutException("unbalanced monitors");
-            }
-        }
-        return true;
-    }
-
-    public void merge(AbstractMergeNode block, HIRFrameStateBuilder other) {
-        assert isCompatibleWith(other);
-
-        for (int i = 0; i < localsSize(); i++) {
-            ValueNode curLocal = localAt(i);
-            ValueNode mergedLocal = merge(curLocal, other.localAt(i), block);
-            if (curLocal != mergedLocal) {
-                storeLocal(i, mergedLocal);
-            }
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            ValueNode curStack = stackAt(i);
-            ValueNode mergedStack = merge(curStack, other.stackAt(i), block);
-            if (curStack != mergedStack) {
-                storeStack(i, mergedStack);
-            }
-        }
-        for (int i = 0; i < lockedObjects.length; i++) {
-            lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block);
-            assert monitorIds[i] == other.monitorIds[i];
-        }
-    }
-
-    private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
-        if (currentValue == null || currentValue.isDeleted()) {
-            return null;
-        } else if (block.isPhiAtMerge(currentValue)) {
-            if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
-                propagateDelete((ValuePhiNode) currentValue);
-                return null;
-            }
-            ((PhiNode) currentValue).addInput(otherValue);
-            return currentValue;
-        } else if (currentValue != otherValue) {
-            assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue);
-            if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
-                return null;
-            }
-            return createValuePhi(currentValue, otherValue, block);
-        } else {
-            return currentValue;
-        }
-    }
-
-    private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
-        ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block));
-        for (int i = 0; i < block.phiPredecessorCount(); i++) {
-            phi.addInput(currentValue);
-        }
-        phi.addInput(otherValue);
-        assert phi.valueCount() == block.phiPredecessorCount() + 1;
-        return phi;
-    }
-
-    private void propagateDelete(FloatingNode node) {
-        assert node instanceof ValuePhiNode || node instanceof ProxyNode;
-        if (node.isDeleted()) {
-            return;
-        }
-        // Collect all phi functions that use this phi so that we can delete them recursively (after
-        // we delete ourselves to avoid circles).
-        List<FloatingNode> propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(ValuePhiNode.class).or(ProxyNode.class)).snapshot();
-
-        // Remove the phi function from all FrameStates where it is used and then delete it.
-        assert node.usages().filter(isNotA(FrameState.class).nor(ValuePhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states";
-        node.replaceAtUsages(null);
-        node.safeDelete();
-
-        for (FloatingNode phiUsage : propagateUsages) {
-            propagateDelete(phiUsage);
-        }
-    }
-
-    public void insertLoopPhis(LocalLiveness liveness, int loopId, LoopBeginNode loopBegin) {
-        for (int i = 0; i < localsSize(); i++) {
-            if (loopBegin.graph().isOSR() || liveness.localIsChangedInLoop(loopId, i)) {
-                storeLocal(i, createLoopPhi(loopBegin, localAt(i)));
-            }
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            storeStack(i, createLoopPhi(loopBegin, stackAt(i)));
-        }
-        for (int i = 0; i < lockedObjects.length; i++) {
-            lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i]);
-        }
-    }
-
-    public void insertLoopProxies(LoopExitNode loopExit, HIRFrameStateBuilder loopEntryState) {
-        for (int i = 0; i < localsSize(); i++) {
-            ValueNode value = localAt(i);
-            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
-                Debug.log(" inserting proxy for %s", value);
-                storeLocal(i, ProxyNode.forValue(value, loopExit, graph));
-            }
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            ValueNode value = stackAt(i);
-            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
-                Debug.log(" inserting proxy for %s", value);
-                storeStack(i, ProxyNode.forValue(value, loopExit, graph));
-            }
-        }
-        for (int i = 0; i < lockedObjects.length; i++) {
-            ValueNode value = lockedObjects[i];
-            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
-                Debug.log(" inserting proxy for %s", value);
-                lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph);
-            }
-        }
-    }
-
-    public void insertProxies(AbstractBeginNode begin) {
-        for (int i = 0; i < localsSize(); i++) {
-            ValueNode value = localAt(i);
-            if (value != null) {
-                Debug.log(" inserting proxy for %s", value);
-                storeLocal(i, ProxyNode.forValue(value, begin, graph));
-            }
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            ValueNode value = stackAt(i);
-            if (value != null) {
-                Debug.log(" inserting proxy for %s", value);
-                storeStack(i, ProxyNode.forValue(value, begin, graph));
-            }
-        }
-        for (int i = 0; i < lockedObjects.length; i++) {
-            ValueNode value = lockedObjects[i];
-            if (value != null) {
-                Debug.log(" inserting proxy for %s", value);
-                lockedObjects[i] = ProxyNode.forValue(value, begin, graph);
-            }
-        }
-    }
-
-    private ValuePhiNode createLoopPhi(AbstractMergeNode block, ValueNode value) {
-        if (value == null) {
-            return null;
-        }
-        assert !block.isPhiAtMerge(value) : "phi function for this block already created";
-
-        ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(value.stamp().unrestricted(), block));
-        phi.addInput(value);
-        return phi;
-    }
-
-    /**
-     * Adds a locked monitor to this frame state.
-     *
-     * @param object the object whose monitor will be locked.
-     */
-    public void pushLock(ValueNode object, MonitorIdNode monitorId) {
-        assert object.isAlive() && object.getKind() == Kind.Object : "unexpected value: " + object;
-        lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1);
-        monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1);
-        lockedObjects[lockedObjects.length - 1] = object;
-        monitorIds[monitorIds.length - 1] = monitorId;
-        assert lockedObjects.length == monitorIds.length;
-    }
-
-    /**
-     * Removes a locked monitor from this frame state.
-     *
-     * @return the object whose monitor was removed from the locks list.
-     */
-    public ValueNode popLock() {
-        try {
-            return lockedObjects[lockedObjects.length - 1];
-        } finally {
-            lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1);
-            monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1);
-            assert lockedObjects.length == monitorIds.length;
-        }
-    }
-
-    public MonitorIdNode peekMonitorId() {
-        return monitorIds[monitorIds.length - 1];
-    }
-
-    /**
-     * @return the current lock depth
-     */
-    public int lockDepth() {
-        assert lockedObjects.length == monitorIds.length;
-        return lockedObjects.length;
-    }
-
-    public boolean contains(ValueNode value) {
-        for (int i = 0; i < localsSize(); i++) {
-            if (localAt(i) == value) {
-                return true;
-            }
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            if (stackAt(i) == value) {
-                return true;
-            }
-        }
-        assert lockedObjects.length == monitorIds.length;
-        for (int i = 0; i < lockedObjects.length; i++) {
-            if (lockedObjects[i] == value || monitorIds[i] == value) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
-        /*
-         * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
-         * remove it for normal compilations, but not for OSR compilations - otherwise dead object
-         * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
-         * Kind.Illegal, because the conflicting branch might not have been parsed.
-         */
-        if (liveness == null) {
-            return;
-        }
-        if (liveIn) {
-            for (int i = 0; i < locals.length; i++) {
-                if (!liveness.localIsLiveIn(block, i)) {
-                    locals[i] = null;
-                }
-            }
-        } else {
-            for (int i = 0; i < locals.length; i++) {
-                if (!liveness.localIsLiveOut(block, i)) {
-                    locals[i] = null;
-                }
-            }
-        }
-    }
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    public boolean rethrowException() {
-        return rethrowException;
-    }
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    public void setRethrowException(boolean b) {
-        rethrowException = b;
-    }
-
-    /**
-     * Returns the size of the local variables.
-     *
-     * @return the size of the local variables
-     */
-    public int localsSize() {
-        return locals.length;
-    }
-
-    /**
-     * Gets the current size (height) of the stack.
-     */
-    public int stackSize() {
-        return stackSize;
-    }
-
-    /**
-     * Gets the value in the local variables at the specified index, without any sanity checking.
-     *
-     * @param i the index into the locals
-     * @return the instruction that produced the value for the specified local
-     */
-    public ValueNode localAt(int i) {
-        return locals[i];
-    }
-
-    /**
-     * Get the value on the stack at the specified stack index.
-     *
-     * @param i the index into the stack, with {@code 0} being the bottom of the stack
-     * @return the instruction at the specified position in the stack
-     */
-    public ValueNode stackAt(int i) {
-        return stack[i];
-    }
-
-    /**
-     * Gets the value in the lock at the specified index, without any sanity checking.
-     *
-     * @param i the index into the lock
-     * @return the instruction that produced the value for the specified lock
-     */
-    public ValueNode lockAt(int i) {
-        return lockedObjects[i];
-    }
-
-    public void storeLock(int i, ValueNode lock) {
-        lockedObjects[i] = lock;
-    }
-
-    /**
-     * Loads the local variable at the specified index, checking that the returned value is non-null
-     * and that two-stack values are properly handled.
-     *
-     * @param i the index of the local variable to load
-     * @return the instruction that produced the specified local
-     */
-    public ValueNode loadLocal(int i) {
-        ValueNode x = locals[i];
-        assert assertLoadLocal(i, x);
-        return x;
-    }
-
-    private boolean assertLoadLocal(int i, ValueNode x) {
-        assert x != null : i;
-        assert parser.parsingReplacement() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
-        assert parser.parsingReplacement() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
-        return true;
-    }
-
-    public void storeLocal(int i, ValueNode x) {
-        storeLocal(i, x, x == null ? null : x.getKind());
-    }
-
-    /**
-     * Stores a given local variable at the specified index. If the value occupies two slots, then
-     * the next local variable index is also overwritten.
-     *
-     * @param i the index at which to store
-     * @param x the instruction which produces the value for the local
-     */
-    public void storeLocal(int i, ValueNode x, Kind kind) {
-        assert assertStoreLocal(x);
-        locals[i] = x;
-        if (x != null) {
-            if (kind.needsTwoSlots() && !parser.parsingReplacement()) {
-                // if this is a double word, then kill i+1
-                locals[i + 1] = null;
-            }
-            if (i > 0 && !parser.parsingReplacement()) {
-                ValueNode p = locals[i - 1];
-                if (p != null && p.getKind().needsTwoSlots()) {
-                    // if there was a double word at i - 1, then kill it
-                    locals[i - 1] = null;
-                }
-            }
-        }
-    }
-
-    private boolean assertStoreLocal(ValueNode x) {
-        assert x == null || parser.parsingReplacement() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
-        return true;
-    }
-
-    public void storeStack(int i, ValueNode x) {
-        assert assertStoreStack(i, x);
-        stack[i] = x;
-    }
-
-    private boolean assertStoreStack(int i, ValueNode x) {
-        assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values";
-        return true;
-    }
-
-    /**
-     * Pushes an instruction onto the stack with the expected type.
-     *
-     * @param kind the type expected for this instruction
-     * @param x the instruction to push onto the stack
-     */
-    public void push(Kind kind, ValueNode x) {
-        assert assertPush(kind, x);
-        xpush(x);
-        if (kind.needsTwoSlots()) {
-            xpush(null);
-        }
-    }
-
-    private boolean assertPush(Kind kind, ValueNode x) {
-        assert parser.parsingReplacement() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
-        assert x != null && (parser.parsingReplacement() || x.getKind() == kind);
-        return true;
-    }
-
-    /**
-     * Pushes a value onto the stack without checking the type.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void xpush(ValueNode x) {
-        assert assertXpush(x);
-        stack[stackSize++] = x;
-    }
-
-    private boolean assertXpush(ValueNode x) {
-        assert parser.parsingReplacement() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
-        return true;
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an int.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void ipush(ValueNode x) {
-        assert assertInt(x);
-        xpush(x);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a float.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void fpush(ValueNode x) {
-        assert assertFloat(x);
-        xpush(x);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an object.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void apush(ValueNode x) {
-        assert assertObject(x);
-        xpush(x);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a long.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void lpush(ValueNode x) {
-        assert assertLong(x);
-        xpush(x);
-        xpush(null);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a double.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void dpush(ValueNode x) {
-        assert assertDouble(x);
-        xpush(x);
-        xpush(null);
-    }
-
-    public void pushReturn(Kind kind, ValueNode x) {
-        if (kind != Kind.Void) {
-            push(kind.getStackKind(), x);
-        }
-    }
-
-    /**
-     * Pops an instruction off the stack with the expected type.
-     *
-     * @param kind the expected type
-     * @return the instruction on the top of the stack
-     */
-    public ValueNode pop(Kind kind) {
-        if (kind.needsTwoSlots()) {
-            xpop();
-        }
-        assert assertPop(kind);
-        return xpop();
-    }
-
-    private boolean assertPop(Kind kind) {
-        assert kind != Kind.Void;
-        ValueNode x = xpeek();
-        assert x != null && (parser.parsingReplacement() || x.getKind() == kind);
-        return true;
-    }
-
-    /**
-     * Pops a value off of the stack without checking the type.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode xpop() {
-        return stack[--stackSize];
-    }
-
-    public ValueNode xpeek() {
-        return stack[stackSize - 1];
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is an int.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode ipop() {
-        assert assertIntPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a float.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode fpop() {
-        assert assertFloatPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is an object.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode apop() {
-        assert assertObjectPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a long.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode lpop() {
-        assert assertHighPeek();
-        xpop();
-        assert assertLongPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a double.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode dpop() {
-        assert assertHighPeek();
-        xpop();
-        assert assertDoublePeek();
-        return xpop();
-    }
-
-    /**
-     * Pop the specified number of slots off of this stack and return them as an array of
-     * instructions.
-     *
-     * @return an array containing the arguments off of the stack
-     */
-    public ValueNode[] popArguments(int argSize) {
-        ValueNode[] result = allocateArray(argSize);
-        int newStackSize = stackSize;
-        for (int i = argSize - 1; i >= 0; i--) {
-            newStackSize--;
-            if (stack[newStackSize] == null) {
-                /* Two-slot value. */
-                newStackSize--;
-                assert stack[newStackSize].getKind().needsTwoSlots();
-            } else {
-                assert parser.parsingReplacement() || (stack[newStackSize].getKind().getSlotCount() == 1);
-            }
-            result[i] = stack[newStackSize];
-        }
-        stackSize = newStackSize;
-        return result;
-    }
-
-    /**
-     * Peeks an element from the operand stack.
-     *
-     * @param argumentNumber The number of the argument, relative from the top of the stack (0 =
-     *            top). Long and double arguments only count as one argument, i.e., null-slots are
-     *            ignored.
-     * @return The peeked argument.
-     */
-    public ValueNode peek(int argumentNumber) {
-        int idx = stackSize() - 1;
-        for (int i = 0; i < argumentNumber; i++) {
-            if (stackAt(idx) == null) {
-                idx--;
-                assert stackAt(idx).getKind().needsTwoSlots();
-            }
-            idx--;
-        }
-        return stackAt(idx);
-    }
-
-    /**
-     * Clears all values on this stack.
-     */
-    public void clearStack() {
-        stackSize = 0;
-    }
-
-    private boolean assertLongPeek() {
-        return assertLong(xpeek());
-    }
-
-    private static boolean assertLong(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Long);
-        return true;
-    }
-
-    private boolean assertIntPeek() {
-        return assertInt(xpeek());
-    }
-
-    private static boolean assertInt(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Int);
-        return true;
-    }
-
-    private boolean assertFloatPeek() {
-        return assertFloat(xpeek());
-    }
-
-    private static boolean assertFloat(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Float);
-        return true;
-    }
-
-    private boolean assertObjectPeek() {
-        return assertObject(xpeek());
-    }
-
-    private boolean assertObject(ValueNode x) {
-        assert x != null && (parser.parsingReplacement() || (x.getKind() == Kind.Object));
-        return true;
-    }
-
-    private boolean assertDoublePeek() {
-        return assertDouble(xpeek());
-    }
-
-    private static boolean assertDouble(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Double);
-        return true;
-    }
-
-    private boolean assertHighPeek() {
-        assert xpeek() == null;
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = hashCode(locals, locals.length);
-        result *= 13;
-        result += hashCode(stack, this.stackSize);
-        return result;
-    }
-
-    private static int hashCode(Object[] a, int length) {
-        int result = 1;
-        for (int i = 0; i < length; ++i) {
-            Object element = a[i];
-            result = 31 * result + (element == null ? 0 : System.identityHashCode(element));
-        }
-        return result;
-    }
-
-    private static boolean equals(ValueNode[] a, ValueNode[] b, int length) {
-        for (int i = 0; i < length; ++i) {
-            if (a[i] != b[i]) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public boolean equals(Object otherObject) {
-        if (otherObject instanceof HIRFrameStateBuilder) {
-            HIRFrameStateBuilder other = (HIRFrameStateBuilder) otherObject;
-            if (!other.method.equals(method)) {
-                return false;
-            }
-            if (other.stackSize != stackSize) {
-                return false;
-            }
-            if (other.parser != parser) {
-                return false;
-            }
-            if (other.rethrowException != rethrowException) {
-                return false;
-            }
-            if (other.graph != graph) {
-                return false;
-            }
-            if (other.locals.length != locals.length) {
-                return false;
-            }
-            return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) &&
-                            equals(other.monitorIds, monitorIds, monitorIds.length);
-        }
-        return false;
-    }
-
-    public void replace(ValueNode oldValue, ValueNode newValue) {
-        for (int i = 0; i < locals.length; i++) {
-            if (locals[i] == oldValue) {
-                locals[i] = newValue;
-            }
-        }
-        for (int i = 0; i < stackSize; i++) {
-            if (stack[i] == oldValue) {
-                stack[i] = newValue;
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/IntrinsicContext.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.java;
-
-import static com.oracle.graal.java.HIRFrameStateBuilder.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.java.GraphBuilderPhase.Instance.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-
-/**
- * Context for a replacement being inlined as a compiler intrinsic. Deoptimization within a compiler
- * intrinsic must replay the intrinsified call. This context object retains the information required
- * to build a frame state denoting the JVM state just before the intrinsified call.
- */
-public class IntrinsicContext extends ReplacementContext {
-
-    /**
-     * BCI denoting an intrinsic is being parsed for inlining after the caller has been parsed.
-     */
-    public static final int POST_PARSE_INLINE_BCI = -1;
-
-    /**
-     * BCI denoting an intrinsic is the compilation root.
-     */
-    public static final int ROOT_COMPILATION_BCI = -2;
-
-    /**
-     * The arguments to the intrinsic.
-     */
-    ValueNode[] args;
-
-    /**
-     * The BCI of the intrinsified invocation, {@link #POST_PARSE_INLINE_BCI} or
-     * {@link #ROOT_COMPILATION_BCI}.
-     */
-    final int bci;
-
-    private FrameState stateBeforeCache;
-
-    public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] args, int bci) {
-        super(method, substitute);
-        assert bci != POST_PARSE_INLINE_BCI || args == null;
-        this.args = args;
-        this.bci = bci;
-        assert !isCompilationRoot() || method.hasBytecodes() : "Cannot intrinsic for native or abstract method " + method.format("%H.%n(%p)");
-    }
-
-    @Override
-    public boolean isIntrinsic() {
-        return true;
-    }
-
-    public boolean isPostParseInlined() {
-        return bci == POST_PARSE_INLINE_BCI;
-    }
-
-    public boolean isCompilationRoot() {
-        return bci == ROOT_COMPILATION_BCI;
-    }
-
-    public FrameState getInvokeStateBefore(StructuredGraph graph, BytecodeParser parent) {
-        if (isCompilationRoot()) {
-            int maxLocals = method.getMaxLocals();
-            // The 'args' were initialized based on the intrinsic method but a
-            // frame state's 'locals' needs to have the same length as the frame
-            // state method's 'max_locals'.
-            ValueNode[] locals = maxLocals == args.length ? args : Arrays.copyOf(args, maxLocals);
-            ValueNode[] stack = EMPTY_ARRAY;
-            int stackSize = 0;
-            ValueNode[] locks = EMPTY_ARRAY;
-            List<MonitorIdNode> monitorIds = Collections.emptyList();
-            return graph.add(new FrameState(null, method, 0, locals, stack, stackSize, locks, monitorIds, false, false));
-        } else if (isPostParseInlined()) {
-            return graph.add(new FrameState(BytecodeFrame.BEFORE_BCI));
-        } else {
-            assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext;
-            if (stateBeforeCache == null) {
-
-                // Find the non-intrinsic ancestor calling the intrinsified method
-                BytecodeParser ancestor = parent;
-                while (ancestor.parsingReplacement()) {
-                    assert ancestor.replacementContext instanceof IntrinsicContext;
-                    ancestor = ancestor.getParent();
-                }
-                FrameState stateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true);
-                stateBeforeCache = stateDuring.duplicateModifiedBeforeCall(bci, Kind.Void, args);
-            }
-            return stateBeforeCache;
-        }
-    }
-
-    @Override
-    IntrinsicContext asIntrinsic() {
-        return this;
-    }
-
-    @Override
-    public String toString() {
-        return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + ", bci: " + bci + (args == null ? "" : ", args: " + Arrays.toString(args)) +
-                        (stateBeforeCache == null ? "" : ", stateBefore: " + stateBeforeCache) + "}";
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/ReplacementContext.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.java;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement;
-
-/**
- * Information about a substitute method being parsed in lieu of an original method. This can happen
- * when a call to a {@link MethodSubstitution} is encountered or the root of compilation is a
- * {@link MethodSubstitution} or a snippet.
- */
-public class ReplacementContext implements Replacement {
-    /**
-     * The method being replaced.
-     */
-    final ResolvedJavaMethod method;
-
-    /**
-     * The replacement method.
-     */
-    final ResolvedJavaMethod replacement;
-
-    public ReplacementContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute) {
-        this.method = method;
-        this.replacement = substitute;
-    }
-
-    public ResolvedJavaMethod getOriginalMethod() {
-        return method;
-    }
-
-    public ResolvedJavaMethod getReplacementMethod() {
-        return replacement;
-    }
-
-    public boolean isIntrinsic() {
-        return false;
-    }
-
-    /**
-     * Determines if a call within the compilation scope of a replacement represents a call to the
-     * original method.
-     */
-    public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) {
-        return method.equals(targetMethod) || replacement.equals(targetMethod);
-    }
-
-    IntrinsicContext asIntrinsic() {
-        return null;
-    }
-
-    @Override
-    public String toString() {
-        return "Replacement{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + "}";
-    }
-}
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java	Thu May 28 17:44:05 2015 +0200
@@ -44,6 +44,21 @@
     }
 
     @Test
+    public void runFirst() throws Throwable {
+        /*
+         * Execute Double.isNaN enough times to create a profile indicating that the path returning
+         * false is never taken. Then compile and execute the test with a NaN value to test that
+         * deoptimization works in the case of an uncommon trap inlined into an intrinsic. Of
+         * course, this relies on Double.isNaN never having yet been called with NaN. if it has,
+         * this test is equivalent to run0.
+         */
+        for (int i = 0; i < 10000; i++) {
+            Double.isNaN(1D);
+        }
+        executeActual(getResolvedJavaMethod("test"), null, java.lang.Double.NaN);
+    }
+
+    @Test
     public void run0() throws Throwable {
         runTest("test", java.lang.Double.NaN);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java	Thu May 28 17:44:05 2015 +0200
@@ -67,7 +67,7 @@
 
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Thu May 28 17:44:05 2015 +0200
@@ -35,7 +35,6 @@
 import com.oracle.graal.lir.LIRInstruction.*;
 
 public final class AMD64AddressValue extends CompositeValue {
-    private static final long serialVersionUID = -4444600052487578694L;
 
     @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base;
     @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Thu May 28 17:44:05 2015 +0200
@@ -71,9 +71,13 @@
     }
 
     @Opcode("CALL_DIRECT")
-    public abstract static class DirectCallOp extends MethodCallOp {
+    public static class DirectCallOp extends MethodCallOp {
         public static final LIRInstructionClass<DirectCallOp> TYPE = LIRInstructionClass.create(DirectCallOp.class);
 
+        public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            this(TYPE, callTarget, result, parameters, temps, state);
+        }
+
         protected DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
             super(c, callTarget, result, parameters, temps, state);
         }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Thu May 28 17:44:05 2015 +0200
@@ -38,13 +38,12 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
 import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure;
-import com.oracle.graal.lir.amd64.AMD64Call.CallOp;
 import com.oracle.graal.lir.asm.*;
 
 public class AMD64ControlFlow {
 
     public static final class ReturnOp extends AMD64LIRInstruction implements BlockEndOp {
-        public static final LIRInstructionClass<CallOp> TYPE = LIRInstructionClass.create(CallOp.class);
+        public static final LIRInstructionClass<ReturnOp> TYPE = LIRInstructionClass.create(ReturnOp.class);
         @Use({REG, ILLEGAL}) protected Value x;
 
         public ReturnOp(Value x) {
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Thu May 28 17:44:05 2015 +0200
@@ -30,7 +30,10 @@
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.MoveOp;
@@ -563,22 +566,23 @@
     private static void const2stack(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, JavaConstant input) {
         assert !crb.codeCache.needsDataPatch(input);
         AMD64Address dest = (AMD64Address) crb.asAddress(result);
+        final long imm;
         switch (input.getKind().getStackKind()) {
             case Int:
-                masm.movl(dest, input.asInt());
+                imm = input.asInt();
                 break;
             case Long:
-                masm.movlong(dest, input.asLong());
+                imm = input.asLong();
                 break;
             case Float:
-                masm.movl(dest, floatToRawIntBits(input.asFloat()));
+                imm = floatToRawIntBits(input.asFloat());
                 break;
             case Double:
-                masm.movlong(dest, doubleToRawLongBits(input.asDouble()));
+                imm = doubleToRawLongBits(input.asDouble());
                 break;
             case Object:
                 if (input.isNull()) {
-                    masm.movlong(dest, 0L);
+                    imm = 0;
                 } else {
                     throw GraalInternalError.shouldNotReachHere("Non-null object constants must be in register");
                 }
@@ -586,5 +590,27 @@
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
+        switch (result.getKind()) {
+            case Byte:
+                assert NumUtil.isByte(imm) : "Is not in byte range: " + imm;
+                AMD64MIOp.MOVB.emit(masm, OperandSize.BYTE, dest, (int) imm);
+                break;
+            case Short:
+                assert NumUtil.isShort(imm) : "Is not in short range: " + imm;
+                AMD64MIOp.MOV.emit(masm, OperandSize.WORD, dest, (int) imm);
+                break;
+            case Int:
+            case Float:
+                assert NumUtil.isInt(imm) : "Is not in int range: " + imm;
+                masm.movl(dest, (int) imm);
+                break;
+            case Long:
+            case Double:
+            case Object:
+                masm.movlong(dest, imm);
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("Unknown result Kind: " + result.getKind());
+        }
     }
 }
--- a/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/LIRTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/LIRTest.java	Thu May 28 17:44:05 2015 +0200
@@ -31,7 +31,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.graphbuilderconf.MethodIdMap.Receiver;
 import com.oracle.graal.jtt.*;
@@ -49,26 +48,30 @@
  */
 public abstract class LIRTest extends JTTTest {
 
-    protected abstract static class LIRTestSpecification {
+    public abstract static class LIRTestSpecification {
         private Value result;
 
-        void generate(LIRGeneratorTool gen, Value arg0) {
+        public void generate(LIRGeneratorTool gen) {
+            defaultHandler(gen);
+        }
+
+        public void generate(LIRGeneratorTool gen, Value arg0) {
             defaultHandler(gen, arg0);
         }
 
-        void generate(LIRGeneratorTool gen, Value arg0, Value arg1) {
+        public void generate(LIRGeneratorTool gen, Value arg0, Value arg1) {
             defaultHandler(gen, arg0, arg1);
         }
 
-        void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2) {
+        public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2) {
             defaultHandler(gen, arg0, arg1, arg2);
         }
 
-        void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3) {
+        public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3) {
             defaultHandler(gen, arg0, arg1, arg2, arg3);
         }
 
-        void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3, Value arg4) {
+        public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3, Value arg4) {
             defaultHandler(gen, arg0, arg1, arg2, arg3, arg4);
         }
 
@@ -77,7 +80,9 @@
         }
 
         void generate(LIRGeneratorTool gen, Value[] values) {
-            if (values.length == 1) {
+            if (values.length == 0) {
+                generate(gen);
+            } else if (values.length == 1) {
                 generate(gen, values[0]);
             } else if (values.length == 2) {
                 generate(gen, values[0], values[1]);
@@ -142,7 +147,7 @@
     }
 
     @NodeInfo
-    private static final class FloatingLIRTestNode extends FloatingNode implements LIRLowerable, Simplifiable {
+    private static final class FloatingLIRTestNode extends FloatingNode implements LIRLowerable {
 
         public static final NodeClass<FloatingLIRTestNode> TYPE = NodeClass.create(FloatingLIRTestNode.class);
         @Input protected ValueNode opsNode;
@@ -165,13 +170,6 @@
         }
 
         @Override
-        public void simplify(SimplifierTool tool) {
-            if (tool.allUsagesAvailable() && getLIROpsNode().isConstant()) {
-                getLIROpsNode().asConstant();
-            }
-        }
-
-        @Override
         public void generate(NodeLIRBuilderTool gen) {
             LIRTestSpecification ops = getLIROperations();
             Stream<Value> v = values().stream().map(node -> gen.operand(node));
@@ -252,7 +250,7 @@
                 assert Modifier.isStatic(m.getModifiers());
                 Class<?>[] p = m.getParameterTypes();
                 assert p.length > 0;
-                assert p[0].equals(LIRTestSpecification.class);
+                assert LIRTestSpecification.class.isAssignableFrom(p[0]);
 
                 if (m.getReturnType().equals(void.class)) {
                     invocationPlugins.register(fixedLIRNodePlugin, c, m.getName(), p);
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java	Thu May 28 17:44:05 2015 +0200
@@ -35,7 +35,6 @@
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
 public final class SPARCAddressValue extends CompositeValue {
-    private static final long serialVersionUID = -3583286416638228207L;
 
     @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base;
     @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Thu May 28 17:44:05 2015 +0200
@@ -90,7 +90,7 @@
         public static final LIRInstructionClass<BinaryRegReg> TYPE = LIRInstructionClass.create(BinaryRegReg.class);
 
         @Opcode private final SPARCArithmetic opcode;
-        @Def({REG, HINT}) protected Value result;
+        @Def({REG}) protected Value result;
         @Use({REG}) protected Value x;
         @Alive({REG}) protected Value y;
         @State LIRFrameState state;
@@ -127,7 +127,7 @@
         public static final LIRInstructionClass<BinaryRegConst> TYPE = LIRInstructionClass.create(BinaryRegConst.class);
 
         @Opcode private final SPARCArithmetic opcode;
-        @Def({REG, HINT}) protected AllocatableValue result;
+        @Def({REG}) protected AllocatableValue result;
         @Use({REG}) protected Value x;
         @State protected LIRFrameState state;
         protected JavaConstant y;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java	Thu May 28 17:44:05 2015 +0200
@@ -133,6 +133,7 @@
      * Emits code that uses 8-byte vector compares.
      */
     private void emit8ByteCompare(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) {
+        assert lengthValue.getPlatformKind().equals(Kind.Int);
         Label loop = new Label();
         Label compareTail = new Label();
         Label compareTailCorrectVectorEnd = new Label();
@@ -142,6 +143,7 @@
 
         boolean hasCBcond = masm.hasFeature(CPUFeature.CBCOND);
 
+        masm.sra(length, 0, length);
         masm.and(result, VECTOR_SIZE - 1, result); // tail count (in bytes)
         masm.andcc(length, ~(VECTOR_SIZE - 1), length);  // vector count (in bytes)
         masm.bpcc(ConditionFlag.Equal, NOT_ANNUL, compareTail, CC.Xcc, PREDICT_NOT_TAKEN);
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Thu May 28 17:44:05 2015 +0200
@@ -31,7 +31,8 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
@@ -280,16 +281,15 @@
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
             try (ScratchRegister scratchReg = masm.getScratchRegister()) {
                 Register scratch = scratchReg.getRegister();
-                StackSlot intInput = reInterprete(asStackSlot(getInput()));
-                StackSlot intResult = reInterprete(asStackSlot(getResult()));
+                StackSlot intInput = reInterpret(asStackSlot(getInput()));
+                StackSlot intResult = reInterpret(asStackSlot(getResult()));
                 // move stack slot
                 move(crb, masm, scratch.asValue(intInput.getLIRKind()), intInput, SPARCDelayedControlTransfer.DUMMY);
                 move(crb, masm, intResult, scratch.asValue(intResult.getLIRKind()), delayedControlTransfer);
             }
-
         }
 
-        private static StackSlot reInterprete(StackSlot slot) {
+        private static StackSlot reInterpret(StackSlot slot) {
             switch ((Kind) slot.getPlatformKind()) {
                 case Boolean:
                 case Byte:
@@ -343,52 +343,21 @@
         public static final LIRInstructionClass<LoadOp> TYPE = LIRInstructionClass.create(LoadOp.class);
 
         @Def({REG}) protected AllocatableValue result;
+        protected boolean signExtend;
 
         public LoadOp(Kind kind, AllocatableValue result, SPARCAddressValue address, LIRFrameState state) {
+            this(kind, result, address, state, false);
+        }
+
+        public LoadOp(Kind kind, AllocatableValue result, SPARCAddressValue address, LIRFrameState state, boolean signExtend) {
             super(TYPE, kind, address, state);
             this.result = result;
+            this.signExtend = signExtend;
         }
 
         @Override
         public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            try (ScratchRegister sc = masm.getScratchRegister()) {
-                Register scratch = sc.getRegister();
-                final SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch);
-                final Register dst = asRegister(result);
-                delayedControlTransfer.emitControlTransfer(crb, masm);
-                if (state != null) {
-                    crb.recordImplicitException(masm.position(), state);
-                }
-                switch ((Kind) kind) {
-                    case Boolean:
-                    case Byte:
-                        masm.ldsb(addr, dst);
-                        break;
-                    case Short:
-                        masm.ldsh(addr, dst);
-                        break;
-                    case Char:
-                        masm.lduh(addr, dst);
-                        break;
-                    case Int:
-                        masm.ldsw(addr, dst);
-                        break;
-                    case Long:
-                        masm.ldx(addr, dst);
-                        break;
-                    case Float:
-                        masm.ldf(addr, dst);
-                        break;
-                    case Double:
-                        masm.lddf(addr, dst);
-                        break;
-                    case Object:
-                        masm.ldx(addr, dst);
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
-            }
+            emitLoad(address.toAddress(), result, signExtend, kind, delayedControlTransfer, state, crb, masm);
         }
     }
 
@@ -433,7 +402,7 @@
         }
     }
 
-    public static final class MembarOp extends SPARCLIRInstruction {
+    public static final class MembarOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
         public static final LIRInstructionClass<MembarOp> TYPE = LIRInstructionClass.create(MembarOp.class);
 
         private final int barriers;
@@ -445,6 +414,7 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            delayedControlTransfer.emitControlTransfer(crb, masm);
             masm.membar(barriers);
         }
     }
@@ -452,10 +422,10 @@
     public static final class NullCheckOp extends SPARCLIRInstruction implements NullCheck, SPARCTailDelayedLIRInstruction {
         public static final LIRInstructionClass<NullCheckOp> TYPE = LIRInstructionClass.create(NullCheckOp.class);
 
-        @Use({REG}) protected AllocatableValue input;
+        @Use({COMPOSITE}) protected SPARCAddressValue input;
         @State protected LIRFrameState state;
 
-        public NullCheckOp(Variable input, LIRFrameState state) {
+        public NullCheckOp(SPARCAddressValue input, LIRFrameState state) {
             super(TYPE);
             this.input = input;
             this.state = state;
@@ -464,8 +434,9 @@
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
             delayedControlTransfer.emitControlTransfer(crb, masm);
+            SPARCAddress addr = input.toAddress();
             crb.recordImplicitException(masm.position(), state);
-            masm.ldx(new SPARCAddress(asRegister(input), 0), g0);
+            masm.ldx(addr, g0);
         }
 
         public Value getCheckedValue() {
@@ -496,8 +467,8 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            move(crb, masm, result, newValue, delayedControlTransfer);
-            compareAndSwap(masm, address, cmpValue, result);
+            move(crb, masm, result, newValue, SPARCDelayedControlTransfer.DUMMY);
+            compareAndSwap(crb, masm, address, cmpValue, result, delayedControlTransfer);
         }
     }
 
@@ -550,42 +521,7 @@
 
         @Override
         public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            assert isRegister(input);
-            try (ScratchRegister sc = masm.getScratchRegister()) {
-                Register scratch = sc.getRegister();
-                SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch);
-                delayedControlTransfer.emitControlTransfer(crb, masm);
-                if (state != null) {
-                    crb.recordImplicitException(masm.position(), state);
-                }
-                switch ((Kind) kind) {
-                    case Boolean:
-                    case Byte:
-                        masm.stb(asRegister(input), addr);
-                        break;
-                    case Short:
-                    case Char:
-                        masm.sth(asRegister(input), addr);
-                        break;
-                    case Int:
-                        masm.stw(asRegister(input), addr);
-                        break;
-                    case Long:
-                        masm.stx(asRegister(input), addr);
-                        break;
-                    case Object:
-                        masm.stx(asRegister(input), addr);
-                        break;
-                    case Float:
-                        masm.stf(asRegister(input), addr);
-                        break;
-                    case Double:
-                        masm.stdf(asRegister(input), addr);
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere("missing: " + kind);
-                }
-            }
+            emitStore(input, address.toAddress(), kind, delayedControlTransfer, state, crb, masm);
         }
     }
 
@@ -642,13 +578,15 @@
             if (isRegister(result)) {
                 reg2reg(crb, masm, result, input, delaySlotLir);
             } else if (isStackSlot(result)) {
-                reg2stack(crb, masm, result, input, delaySlotLir);
+                SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result);
+                emitStore(input, resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm);
             } else {
                 throw GraalInternalError.shouldNotReachHere();
             }
         } else if (isStackSlot(input)) {
             if (isRegister(result)) {
-                stack2reg(crb, masm, result, input, delaySlotLir);
+                SPARCAddress inputAddress = (SPARCAddress) crb.asAddress(input);
+                emitLoad(inputAddress, result, false, input.getPlatformKind(), delaySlotLir, null, crb, masm);
             } else {
                 throw GraalInternalError.shouldNotReachHere();
             }
@@ -658,7 +596,8 @@
                 const2reg(crb, masm, result, constant, delaySlotLir);
             } else if (isStackSlot(result)) {
                 if (constant.isDefaultForKind() || constant.isNull()) {
-                    reg2stack(crb, masm, result, g0.asValue(LIRKind.derive(input)), delaySlotLir);
+                    SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result);
+                    emitStore(g0.asValue(LIRKind.derive(input)), resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm);
                 } else {
                     try (ScratchRegister sc = masm.getScratchRegister()) {
                         Register scratch = sc.getRegister();
@@ -668,7 +607,8 @@
                         } else {
                             new Setx(value, scratch).emit(masm);
                         }
-                        reg2stack(crb, masm, result, scratch.asValue(LIRKind.derive(input)), delaySlotLir);
+                        SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result);
+                        emitStore(scratch.asValue(LIRKind.derive(input)), resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm);
                     }
                 }
             } else {
@@ -735,78 +675,6 @@
         }
     }
 
-    private static void reg2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) {
-        SPARCAddress dst = (SPARCAddress) crb.asAddress(result);
-        try (ScratchRegister sc = masm.getScratchRegister()) {
-            Register scratch = sc.getRegister();
-            dst = generateSimm13OffsetLoad(dst, masm, scratch);
-            Register src = asRegister(input);
-            delaySlotLir.emitControlTransfer(crb, masm);
-            switch (input.getKind()) {
-                case Byte:
-                case Boolean:
-                    masm.stb(src, dst);
-                    break;
-                case Char:
-                case Short:
-                    masm.sth(src, dst);
-                    break;
-                case Int:
-                    masm.stw(src, dst);
-                    break;
-                case Long:
-                case Object:
-                    masm.stx(src, dst);
-                    break;
-                case Float:
-                    masm.stf(src, dst);
-                    break;
-                case Double:
-                    masm.stdf(src, dst);
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere("Input is a: " + input.getKind() + "(" + input + ")");
-            }
-        }
-    }
-
-    private static void stack2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) {
-        SPARCAddress src = (SPARCAddress) crb.asAddress(input);
-        try (ScratchRegister sc = masm.getScratchRegister()) {
-            Register scratch = sc.getRegister();
-            src = generateSimm13OffsetLoad(src, masm, scratch);
-            Register dst = asRegister(result);
-            delaySlotLir.emitControlTransfer(crb, masm);
-            switch (input.getKind()) {
-                case Boolean:
-                case Byte:
-                    masm.ldsb(src, dst);
-                    break;
-                case Short:
-                    masm.ldsh(src, dst);
-                    break;
-                case Char:
-                    masm.lduh(src, dst);
-                    break;
-                case Int:
-                    masm.ldsw(src, dst);
-                    break;
-                case Long:
-                case Object:
-                    masm.ldx(src, dst);
-                    break;
-                case Float:
-                    masm.ldf(src, dst);
-                    break;
-                case Double:
-                    masm.lddf(src, dst);
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere("Input is a: " + input.getKind());
-            }
-        }
-    }
-
     private static void const2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, JavaConstant input, SPARCDelayedControlTransfer delaySlotLir) {
         try (ScratchRegister sc = masm.getScratchRegister()) {
             Register scratch = sc.getRegister();
@@ -912,7 +780,9 @@
         }
     }
 
-    protected static void compareAndSwap(SPARCMacroAssembler masm, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
+    protected static void compareAndSwap(CompilationResultBuilder crb, SPARCMacroAssembler masm, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue,
+                    SPARCDelayedControlTransfer delay) {
+        delay.emitControlTransfer(crb, masm);
         switch (cmpValue.getKind()) {
             case Int:
                 masm.cas(asRegister(address), asRegister(cmpValue), asRegister(newValue));
@@ -925,4 +795,101 @@
                 throw GraalInternalError.shouldNotReachHere();
         }
     }
+
+    private static void emitLoad(SPARCAddress address, Value result, boolean signExtend, PlatformKind kind, SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state,
+                    CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        try (ScratchRegister sc = masm.getScratchRegister()) {
+            Register scratch = sc.getRegister();
+            final SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch);
+            final Register dst = asRegister(result);
+            delayedControlTransfer.emitControlTransfer(crb, masm);
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            switch ((Kind) kind) {
+                case Boolean:
+                case Byte:
+                    if (signExtend) {
+                        masm.ldsb(addr, dst);
+                    } else {
+                        masm.ldub(addr, dst);
+                    }
+                    break;
+                case Short:
+                    if (signExtend) {
+                        masm.ldsh(addr, dst);
+                    } else {
+                        masm.lduh(addr, dst);
+                    }
+                    break;
+                case Char:
+                    if (signExtend) {
+                        masm.ldsh(addr, dst);
+                    } else {
+                        masm.lduh(addr, dst);
+                    }
+                    break;
+                case Int:
+                    if (signExtend) {
+                        masm.ldsw(addr, dst);
+                    } else {
+                        masm.lduw(addr, dst);
+                    }
+                    break;
+                case Long:
+                    masm.ldx(addr, dst);
+                    break;
+                case Float:
+                    masm.ldf(addr, dst);
+                    break;
+                case Double:
+                    masm.lddf(addr, dst);
+                    break;
+                case Object:
+                    masm.ldx(addr, dst);
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    private static void emitStore(Value input, SPARCAddress address, PlatformKind kind, SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state, CompilationResultBuilder crb,
+                    SPARCMacroAssembler masm) {
+        try (ScratchRegister sc = masm.getScratchRegister()) {
+            Register scratch = sc.getRegister();
+            SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch);
+            delayedControlTransfer.emitControlTransfer(crb, masm);
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            switch ((Kind) kind) {
+                case Boolean:
+                case Byte:
+                    masm.stb(asRegister(input), addr);
+                    break;
+                case Short:
+                case Char:
+                    masm.sth(asRegister(input), addr);
+                    break;
+                case Int:
+                    masm.stw(asRegister(input), addr);
+                    break;
+                case Long:
+                    masm.stx(asRegister(input), addr);
+                    break;
+                case Object:
+                    masm.stx(asRegister(input), addr);
+                    break;
+                case Float:
+                    masm.stf(asRegister(input), addr);
+                    break;
+                case Double:
+                    masm.stdf(asRegister(input), addr);
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere("missing: " + kind);
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java	Thu May 28 17:44:05 2015 +0200
@@ -43,7 +43,6 @@
 
     private static class TestCompositeValue extends CompositeValue {
 
-        private static final long serialVersionUID = -8804214200173503527L;
         @Component({REG, OperandFlag.ILLEGAL}) protected Value value;
 
         public TestCompositeValue(Value value) {
@@ -70,7 +69,6 @@
 
     private static class DummyValue extends AbstractValue {
 
-        private static final long serialVersionUID = -645435039553382737L;
         private final int id;
         private static int counter = 1;
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Thu May 28 17:44:05 2015 +0200
@@ -37,8 +37,6 @@
  */
 public abstract class CompositeValue extends AbstractValue {
 
-    private static final long serialVersionUID = -169180052684126180L;
-
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.FIELD)
     public static @interface Component {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Thu May 28 17:44:05 2015 +0200
@@ -39,7 +39,7 @@
  * such fields.</li>
  * </ul>
  */
-public final class CompositeValueClass<T> {
+public final class CompositeValueClass<T> extends FieldIntrospection<T> {
 
     /**
      * The CompositeValueClass is only used for formatting for the most part so cache it as a
@@ -56,16 +56,15 @@
 
     };
 
-    public static CompositeValueClass<?> get(Class<?> type) {
-        return compositeClass.get(type);
+    @SuppressWarnings("unchecked")
+    public static <T> CompositeValueClass<T> get(Class<T> type) {
+        return (CompositeValueClass<T>) compositeClass.get(type);
     }
 
-    private final Class<?> clazz;
     private final Values values;
-    private final Fields data;
 
     private CompositeValueClass(Class<T> clazz) {
-        this.clazz = clazz;
+        super(clazz);
 
         CompositeValueFieldsScanner vfs = new CompositeValueFieldsScanner(new FieldsScanner.DefaultCalcOffset());
         vfs.scan(clazz, CompositeValue.class, false);
@@ -94,9 +93,14 @@
     }
 
     @Override
+    public Fields[] getAllFields() {
+        return new Fields[]{data, values};
+    }
+
+    @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
-        str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" components[");
+        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" components[");
         values.appendFields(str);
         str.append("] data[");
         data.appendFields(str);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Thu May 28 17:44:05 2015 +0200
@@ -76,6 +76,17 @@
         }
     }
 
+    @SuppressWarnings("unchecked")
+    public static <T> LIRInstructionClass<T> get(Class<T> clazz) {
+        try {
+            Field field = clazz.getDeclaredField("TYPE");
+            field.setAccessible(true);
+            return (LIRInstructionClass<T>) field.get(null);
+        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private static class LIRInstructionFieldsScanner extends LIRFieldsScanner {
 
         private String opcodeConstant;
@@ -137,7 +148,7 @@
             if (STATE_CLASS.isAssignableFrom(type)) {
                 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
                 assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field;
-                states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type));
+                states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type, field.getDeclaringClass()));
             } else {
                 super.scanField(field, offset);
             }
@@ -151,6 +162,12 @@
     }
 
     @Override
+    public Fields[] getAllFields() {
+        assert values == null;
+        return new Fields[]{data, uses, alives, temps, defs, states};
+    }
+
+    @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
         str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use[");
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Thu May 28 17:44:05 2015 +0200
@@ -100,8 +100,8 @@
 
         final EnumSet<OperandFlag> flags;
 
-        public ValueFieldInfo(long offset, String name, Class<?> type, EnumSet<OperandFlag> flags) {
-            super(offset, name, type);
+        public ValueFieldInfo(long offset, String name, Class<?> type, Class<?> declaringClass, EnumSet<OperandFlag> flags) {
+            super(offset, name, type, declaringClass);
             assert VALUE_ARRAY_CLASS.isAssignableFrom(type) || VALUE_CLASS.isAssignableFrom(type);
             this.flags = flags;
         }
@@ -171,14 +171,14 @@
                 assert annotation != null : "Field must have operand mode annotation: " + field;
                 EnumSet<OperandFlag> flags = getFlags(field);
                 assert verifyFlags(field, type, flags);
-                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags));
+                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags));
                 annotation.directCount++;
             } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
                 OperandModeAnnotation annotation = getOperandModeAnnotation(field);
                 assert annotation != null : "Field must have operand mode annotation: " + field;
                 EnumSet<OperandFlag> flags = getFlags(field);
                 assert verifyFlags(field, type.getComponentType(), flags);
-                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags));
+                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags));
             } else {
                 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
                 assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Thu May 28 17:44:05 2015 +0200
@@ -31,8 +31,6 @@
  */
 public final class Variable extends AllocatableValue {
 
-    private static final long serialVersionUID = 4507578431686109809L;
-
     /**
      * The identifier of the variable. This is a non-zero index in a contiguous 0-based name space.
      */
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Thu May 28 17:44:05 2015 +0200
@@ -25,9 +25,7 @@
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.compiler.common.cfg.AbstractControlFlowGraph.*;
 import static com.oracle.graal.lir.LIRValueUtil.*;
-import static com.oracle.graal.lir.debug.LIRGenerationDebugContext.*;
 
 import java.util.*;
 
@@ -36,20 +34,16 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.common.util.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.alloc.lsra.Interval.RegisterBinding;
-import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority;
-import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext;
 import com.oracle.graal.options.*;
 
 /**
@@ -60,19 +54,18 @@
  */
 class LinearScan {
 
-    final TargetDescription target;
     final LIRGenerationResult res;
     final LIR ir;
     final FrameMapBuilder frameMapBuilder;
-    final SpillMoveFactory spillMoveFactory;
     final RegisterAttributes[] registerAttributes;
     final Register[] registers;
     final RegisterAllocationConfig regAllocConfig;
+    private final SpillMoveFactory moveFactory;
 
     final boolean callKillsRegisters;
 
     public static final int DOMINATOR_SPILL_MOVE_ID = -2;
-    private static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1;
+    static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1;
 
     public static class Options {
         // @formatter:off
@@ -113,52 +106,45 @@
         public BitSet liveKill;
     }
 
-    final BlockMap<BlockData> blockData;
+    private final BlockMap<BlockData> blockData;
 
     /**
      * List of blocks in linear-scan order. This is only correct as long as the CFG does not change.
      */
     final List<? extends AbstractBlockBase<?>> sortedBlocks;
 
-    /**
-     * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
-     */
-    Interval[] intervals;
+    /** @see #intervals() */
+    private Interval[] intervals;
 
     /**
      * The number of valid entries in {@link #intervals}.
      */
-    int intervalsSize;
+    private int intervalsSize;
 
     /**
      * The index of the first entry in {@link #intervals} for a
      * {@linkplain #createDerivedInterval(Interval) derived interval}.
      */
-    int firstDerivedIntervalIndex = -1;
+    private int firstDerivedIntervalIndex = -1;
 
     /**
      * Intervals sorted by {@link Interval#from()}.
      */
-    Interval[] sortedIntervals;
+    private Interval[] sortedIntervals;
 
     /**
      * Map from an instruction {@linkplain LIRInstruction#id id} to the instruction. Entries should
      * be retrieved with {@link #instructionForId(int)} as the id is not simply an index into this
      * array.
      */
-    LIRInstruction[] opIdToInstructionMap;
+    private LIRInstruction[] opIdToInstructionMap;
 
     /**
      * Map from an instruction {@linkplain LIRInstruction#id id} to the
      * {@linkplain AbstractBlockBase block} containing the instruction. Entries should be retrieved
      * with {@link #blockForId(int)} as the id is not simply an index into this array.
      */
-    AbstractBlockBase<?>[] opIdToBlockMap;
-
-    /**
-     * Bit set for each variable that is contained in each loop.
-     */
-    BitMap2D intervalInLoop;
+    private AbstractBlockBase<?>[] opIdToBlockMap;
 
     /**
      * The {@linkplain #operandNumber(Value) number} of the first variable operand allocated.
@@ -166,10 +152,9 @@
     private final int firstVariableNumber;
 
     LinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig) {
-        this.target = target;
         this.res = res;
         this.ir = res.getLIR();
-        this.spillMoveFactory = spillMoveFactory;
+        this.moveFactory = spillMoveFactory;
         this.frameMapBuilder = res.getFrameMapBuilder();
         this.sortedBlocks = ir.linearScanOrder();
         this.registerAttributes = regAllocConfig.getRegisterConfig().getAttributesMap();
@@ -179,8 +164,10 @@
         this.firstVariableNumber = registers.length;
         this.blockData = new BlockMap<>(ir.getControlFlowGraph());
 
-        // If all allocatable registers are caller saved, then no registers are live across a call
-        // site. The register allocator can save time not trying to find a register at a call site.
+        /*
+         * If all allocatable registers are caller saved, then no registers are live across a call
+         * site. The register allocator can save time not trying to find a register at a call site.
+         */
         this.callKillsRegisters = regAllocConfig.getRegisterConfig().areAllAllocatableRegistersCallerSaved();
     }
 
@@ -198,7 +185,7 @@
     }
 
     SpillMoveFactory getSpillMoveFactory() {
-        return spillMoveFactory;
+        return moveFactory;
     }
 
     protected MoveResolver createMoveResolver() {
@@ -216,7 +203,7 @@
      * the {@linkplain Variable variables} and {@linkplain RegisterValue registers} being processed
      * by this allocator.
      */
-    private int operandNumber(Value operand) {
+    int operandNumber(Value operand) {
         if (isRegister(operand)) {
             int number = asRegister(operand).number;
             assert number < firstVariableNumber;
@@ -229,7 +216,7 @@
     /**
      * Gets the number of operands. This value will increase by 1 for new variable.
      */
-    private int operandSize() {
+    int operandSize() {
         return firstVariableNumber + ir.numVariables();
     }
 
@@ -240,6 +227,14 @@
         return firstVariableNumber - 1;
     }
 
+    BlockData getBlockData(AbstractBlockBase<?> block) {
+        return blockData.get(block);
+    }
+
+    void initBlockData(AbstractBlockBase<?> block) {
+        blockData.put(block, new BlockData());
+    }
+
     static final IntervalPredicate IS_PRECOLORED_INTERVAL = new IntervalPredicate() {
 
         @Override
@@ -273,8 +268,10 @@
     }
 
     void assignSpillSlot(Interval interval) {
-        // assign the canonical spill slot of the parent (if a part of the interval
-        // is already spilled) or allocate a new spill slot
+        /*
+         * Assign the canonical spill slot of the parent (if a part of the interval is already
+         * spilled) or allocate a new spill slot.
+         */
         if (interval.canMaterialize()) {
             interval.assignLocation(Value.ILLEGAL);
         } else if (interval.spillSlot() != null) {
@@ -287,6 +284,18 @@
     }
 
     /**
+     * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
+     */
+    Interval[] intervals() {
+        return intervals;
+    }
+
+    void initIntervals() {
+        intervalsSize = operandSize();
+        intervals = new Interval[intervalsSize + (intervalsSize >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT)];
+    }
+
+    /**
      * Creates a new interval.
      *
      * @param operand the operand for the interval
@@ -345,10 +354,6 @@
         return ir.getControlFlowGraph().getLoops().size();
     }
 
-    boolean isIntervalInLoop(int interval, int loop) {
-        return intervalInLoop.at(interval, loop);
-    }
-
     Interval intervalFor(int operandNumber) {
         return intervals[operandNumber];
     }
@@ -368,6 +373,16 @@
         }
     }
 
+    void initOpIdMaps(int numInstructions) {
+        opIdToInstructionMap = new LIRInstruction[numInstructions];
+        opIdToBlockMap = new AbstractBlockBase<?>[numInstructions];
+    }
+
+    void putOpIdMaps(int index, LIRInstruction op, AbstractBlockBase<?> block) {
+        opIdToInstructionMap[index] = op;
+        opIdToBlockMap[index] = block;
+    }
+
     /**
      * Gets the highest instruction id allocated by this object.
      */
@@ -378,10 +393,10 @@
 
     /**
      * Converts an {@linkplain LIRInstruction#id instruction id} to an instruction index. All LIR
-     * instructions in a method have an index one greater than their linear-scan order predecesor
+     * instructions in a method have an index one greater than their linear-scan order predecessor
      * with the first instruction having an index of 0.
      */
-    static int opIdToIndex(int opId) {
+    private static int opIdToIndex(int opId) {
         return opId >> 1;
     }
 
@@ -429,909 +444,15 @@
         return instructionForId(opId).destroysCallerSavedRegisters();
     }
 
-    /**
-     * Eliminates moves from register to stack if the stack slot is known to be correct.
-     */
-    void changeSpillDefinitionPos(Interval interval, int defPos) {
-        assert interval.isSplitParent() : "can only be called for split parents";
-
-        switch (interval.spillState()) {
-            case NoDefinitionFound:
-                assert interval.spillDefinitionPos() == -1 : "must no be set before";
-                interval.setSpillDefinitionPos(defPos);
-                interval.setSpillState(SpillState.NoSpillStore);
-                break;
-
-            case NoSpillStore:
-                assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created";
-                if (defPos < interval.spillDefinitionPos() - 2) {
-                    // second definition found, so no spill optimization possible for this interval
-                    interval.setSpillState(SpillState.NoOptimization);
-                } else {
-                    // two consecutive definitions (because of two-operand LIR form)
-                    assert blockForId(defPos) == blockForId(interval.spillDefinitionPos()) : "block must be equal";
-                }
-                break;
-
-            case NoOptimization:
-                // nothing to do
-                break;
-
-            default:
-                throw new BailoutException("other states not allowed at this time");
-        }
-    }
-
-    // called during register allocation
-    void changeSpillState(Interval interval, int spillPos) {
-        switch (interval.spillState()) {
-            case NoSpillStore: {
-                int defLoopDepth = blockForId(interval.spillDefinitionPos()).getLoopDepth();
-                int spillLoopDepth = blockForId(spillPos).getLoopDepth();
-
-                if (defLoopDepth < spillLoopDepth) {
-                    // the loop depth of the spilling position is higher then the loop depth
-                    // at the definition of the interval . move write to memory out of loop.
-                    if (Options.LSRAOptimizeSpillPosition.getValue()) {
-                        // find best spill position in dominator the tree
-                        interval.setSpillState(SpillState.SpillInDominator);
-                    } else {
-                        // store at definition of the interval
-                        interval.setSpillState(SpillState.StoreAtDefinition);
-                    }
-                } else {
-                    // the interval is currently spilled only once, so for now there is no
-                    // reason to store the interval at the definition
-                    interval.setSpillState(SpillState.OneSpillStore);
-                }
-                break;
-            }
-
-            case OneSpillStore: {
-                if (Options.LSRAOptimizeSpillPosition.getValue()) {
-                    // the interval is spilled more then once
-                    interval.setSpillState(SpillState.SpillInDominator);
-                } else {
-                    // it is better to store it to
-                    // memory at the definition
-                    interval.setSpillState(SpillState.StoreAtDefinition);
-                }
-                break;
-            }
-
-            case SpillInDominator:
-            case StoreAtDefinition:
-            case StartInMemory:
-            case NoOptimization:
-            case NoDefinitionFound:
-                // nothing to do
-                break;
-
-            default:
-                throw new BailoutException("other states not allowed at this time");
-        }
-    }
-
     abstract static class IntervalPredicate {
 
         abstract boolean apply(Interval i);
     }
 
-    private static final IntervalPredicate mustStoreAtDefinition = new IntervalPredicate() {
-
-        @Override
-        public boolean apply(Interval i) {
-            return i.isSplitParent() && i.spillState() == SpillState.StoreAtDefinition;
-        }
-    };
-
-    /**
-     * @return the index of the first instruction that is of interest for
-     *         {@link #eliminateSpillMoves()}
-     */
-    protected int firstInstructionOfInterest() {
-        // skip the first because it is always a label
-        return 1;
-    }
-
-    // called once before assignment of register numbers
-    void eliminateSpillMoves() {
-        try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves")) {
-
-            // collect all intervals that must be stored after their definition.
-            // the list is sorted by Interval.spillDefinitionPos
-            Interval interval;
-            interval = createUnhandledLists(mustStoreAtDefinition, null).first;
-            if (DetailedAsserts.getValue()) {
-                checkIntervals(interval);
-            }
-
-            LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer();
-            for (AbstractBlockBase<?> block : sortedBlocks) {
-                try (Indent indent1 = Debug.logAndIndent("Handle %s", block)) {
-                    List<LIRInstruction> instructions = ir.getLIRforBlock(block);
-                    int numInst = instructions.size();
-
-                    // iterate all instructions of the block.
-                    for (int j = firstInstructionOfInterest(); j < numInst; j++) {
-                        LIRInstruction op = instructions.get(j);
-                        int opId = op.id();
-
-                        if (opId == -1) {
-                            MoveOp move = (MoveOp) op;
-                            /*
-                             * Remove move from register to stack if the stack slot is guaranteed to
-                             * be correct. Only moves that have been inserted by LinearScan can be
-                             * removed.
-                             */
-                            if (canEliminateSpillMove(block, move)) {
-                                /*
-                                 * Move target is a stack slot that is always correct, so eliminate
-                                 * instruction.
-                                 */
-                                if (Debug.isLogEnabled()) {
-                                    Debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", operandNumber(move.getInput()), move.getInput(), operandNumber(move.getResult()),
-                                                    move.getResult(), block);
-                                }
-
-                                // null-instructions are deleted by assignRegNum
-                                instructions.set(j, null);
-                            }
-
-                        } else {
-                            /*
-                             * Insert move from register to stack just after the beginning of the
-                             * interval.
-                             */
-                            assert interval == Interval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order";
-                            assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval";
-
-                            while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) {
-                                if (!interval.canMaterialize()) {
-                                    if (!insertionBuffer.initialized()) {
-                                        /*
-                                         * prepare insertion buffer (appended when all instructions
-                                         * in the block are processed)
-                                         */
-                                        insertionBuffer.init(instructions);
-                                    }
-
-                                    AllocatableValue fromLocation = interval.location();
-                                    AllocatableValue toLocation = canonicalSpillOpr(interval);
-                                    if (!fromLocation.equals(toLocation)) {
-
-                                        assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" +
-                                                        interval.spillState();
-                                        assert isStackSlotValue(toLocation) : "to operand must be a stack slot";
-
-                                        LIRInstruction move = getSpillMoveFactory().createMove(toLocation, fromLocation);
-                                        insertionBuffer.append(j + 1, move);
-
-                                        if (Debug.isLogEnabled()) {
-                                            Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
-                                        }
-                                    }
-                                }
-                                interval = interval.next;
-                            }
-                        }
-                    } // end of instruction iteration
-
-                    if (insertionBuffer.initialized()) {
-                        insertionBuffer.finish();
-                    }
-                }
-            } // end of block iteration
-
-            assert interval == Interval.EndMarker : "missed an interval";
-        }
-    }
-
-    /**
-     * @param block The block {@code move} is located in.
-     * @param move Spill move.
-     */
-    protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) {
-        assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables: " + move;
-
-        Interval curInterval = intervalFor(move.getResult());
-
-        if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) {
-            assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location();
-            return true;
-        }
-        return false;
-    }
-
-    private static void checkIntervals(Interval interval) {
-        Interval prev = null;
-        Interval temp = interval;
-        while (temp != Interval.EndMarker) {
-            assert temp.spillDefinitionPos() > 0 : "invalid spill definition pos";
-            if (prev != null) {
-                assert temp.from() >= prev.from() : "intervals not sorted";
-                assert temp.spillDefinitionPos() >= prev.spillDefinitionPos() : "when intervals are sorted by from :  then they must also be sorted by spillDefinitionPos";
-            }
-
-            assert temp.spillSlot() != null || temp.canMaterialize() : "interval has no spill slot assigned";
-            assert temp.spillDefinitionPos() >= temp.from() : "invalid order";
-            assert temp.spillDefinitionPos() <= temp.from() + 2 : "only intervals defined once at their start-pos can be optimized";
-
-            if (Debug.isLogEnabled()) {
-                Debug.log("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos());
-            }
-
-            prev = temp;
-            temp = temp.next;
-        }
-    }
-
-    /**
-     * Numbers all instructions in all blocks. The numbering follows the
-     * {@linkplain ComputeBlockOrder linear scan order}.
-     */
-    void numberInstructions() {
-
-        intervalsSize = operandSize();
-        intervals = new Interval[intervalsSize + (intervalsSize >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT)];
-
-        ValueConsumer setVariableConsumer = (value, mode, flags) -> {
-            if (isVariable(value)) {
-                getOrCreateInterval(asVariable(value));
-            }
-        };
-
-        // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node.
-        int numInstructions = 0;
-        for (AbstractBlockBase<?> block : sortedBlocks) {
-            numInstructions += ir.getLIRforBlock(block).size();
-        }
-
-        // initialize with correct length
-        opIdToInstructionMap = new LIRInstruction[numInstructions];
-        opIdToBlockMap = new AbstractBlockBase<?>[numInstructions];
-
-        int opId = 0;
-        int index = 0;
-        for (AbstractBlockBase<?> block : sortedBlocks) {
-            blockData.put(block, new BlockData());
-
-            List<LIRInstruction> instructions = ir.getLIRforBlock(block);
-
-            int numInst = instructions.size();
-            for (int j = 0; j < numInst; j++) {
-                LIRInstruction op = instructions.get(j);
-                op.setId(opId);
-
-                opIdToInstructionMap[index] = op;
-                opIdToBlockMap[index] = block;
-                assert instructionForId(opId) == op : "must match";
-
-                op.visitEachTemp(setVariableConsumer);
-                op.visitEachOutput(setVariableConsumer);
-
-                index++;
-                opId += 2; // numbering of lirOps by two
-            }
-        }
-        assert index == numInstructions : "must match";
-        assert (index << 1) == opId : "must match: " + (index << 1);
-    }
-
-    /**
-     * Computes local live sets (i.e. {@link BlockData#liveGen} and {@link BlockData#liveKill})
-     * separately for each block.
-     */
-    void computeLocalLiveSets() {
-        int liveSize = liveSetSize();
-
-        intervalInLoop = new BitMap2D(operandSize(), numLoops());
-
-        // iterate all blocks
-        for (final AbstractBlockBase<?> block : sortedBlocks) {
-            try (Indent indent = Debug.logAndIndent("compute local live sets for block %s", block)) {
-
-                final BitSet liveGen = new BitSet(liveSize);
-                final BitSet liveKill = new BitSet(liveSize);
-
-                List<LIRInstruction> instructions = ir.getLIRforBlock(block);
-                int numInst = instructions.size();
-
-                ValueConsumer useConsumer = (operand, mode, flags) -> {
-                    if (isVariable(operand)) {
-                        int operandNum = operandNumber(operand);
-                        if (!liveKill.get(operandNum)) {
-                            liveGen.set(operandNum);
-                            if (Debug.isLogEnabled()) {
-                                Debug.log("liveGen for operand %d(%s)", operandNum, operand);
-                            }
-                        }
-                        if (block.getLoop() != null) {
-                            intervalInLoop.setBit(operandNum, block.getLoop().getIndex());
-                        }
-                    }
-
-                    if (DetailedAsserts.getValue()) {
-                        verifyInput(block, liveKill, operand);
-                    }
-                };
-                ValueConsumer stateConsumer = (operand, mode, flags) -> {
-                    if (isVariableOrRegister(operand)) {
-                        int operandNum = operandNumber(operand);
-                        if (!liveKill.get(operandNum)) {
-                            liveGen.set(operandNum);
-                            if (Debug.isLogEnabled()) {
-                                Debug.log("liveGen in state for operand %d(%s)", operandNum, operand);
-                            }
-                        }
-                    }
-                };
-                ValueConsumer defConsumer = (operand, mode, flags) -> {
-                    if (isVariable(operand)) {
-                        int varNum = operandNumber(operand);
-                        liveKill.set(varNum);
-                        if (Debug.isLogEnabled()) {
-                            Debug.log("liveKill for operand %d(%s)", varNum, operand);
-                        }
-                        if (block.getLoop() != null) {
-                            intervalInLoop.setBit(varNum, block.getLoop().getIndex());
-                        }
-                    }
-
-                    if (DetailedAsserts.getValue()) {
-                        // fixed intervals are never live at block boundaries, so
-                        // they need not be processed in live sets
-                        // process them only in debug mode so that this can be checked
-                        verifyTemp(liveKill, operand);
-                    }
-                };
-
-                // iterate all instructions of the block
-                for (int j = 0; j < numInst; j++) {
-                    final LIRInstruction op = instructions.get(j);
-
-                    try (Indent indent2 = Debug.logAndIndent("handle op %d", op.id())) {
-                        op.visitEachInput(useConsumer);
-                        op.visitEachAlive(useConsumer);
-                        // Add uses of live locals from interpreter's point of view for proper debug
-                        // information generation
-                        op.visitEachState(stateConsumer);
-                        op.visitEachTemp(defConsumer);
-                        op.visitEachOutput(defConsumer);
-                    }
-                } // end of instruction iteration
-
-                BlockData blockSets = blockData.get(block);
-                blockSets.liveGen = liveGen;
-                blockSets.liveKill = liveKill;
-                blockSets.liveIn = new BitSet(liveSize);
-                blockSets.liveOut = new BitSet(liveSize);
-
-                if (Debug.isLogEnabled()) {
-                    Debug.log("liveGen  B%d %s", block.getId(), blockSets.liveGen);
-                    Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill);
-                }
-
-            }
-        } // end of block iteration
-    }
-
-    private void verifyTemp(BitSet liveKill, Value operand) {
-        // fixed intervals are never live at block boundaries, so
-        // they need not be processed in live sets
-        // process them only in debug mode so that this can be checked
-        if (isRegister(operand)) {
-            if (isProcessed(operand)) {
-                liveKill.set(operandNumber(operand));
-            }
-        }
-    }
-
-    private void verifyInput(AbstractBlockBase<?> block, BitSet liveKill, Value operand) {
-        // fixed intervals are never live at block boundaries, so
-        // they need not be processed in live sets.
-        // this is checked by these assertions to be sure about it.
-        // the entry block may have incoming
-        // values in registers, which is ok.
-        if (isRegister(operand) && block != ir.getControlFlowGraph().getStartBlock()) {
-            if (isProcessed(operand)) {
-                assert liveKill.get(operandNumber(operand)) : "using fixed register that is not defined in this block";
-            }
-        }
-    }
-
-    /**
-     * Performs a backward dataflow analysis to compute global live sets (i.e.
-     * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block.
-     */
-    void computeGlobalLiveSets() {
-        try (Indent indent = Debug.logAndIndent("compute global live sets")) {
-            int numBlocks = blockCount();
-            boolean changeOccurred;
-            boolean changeOccurredInBlock;
-            int iterationCount = 0;
-            BitSet liveOut = new BitSet(liveSetSize()); // scratch set for calculations
-
-            // Perform a backward dataflow analysis to compute liveOut and liveIn for each block.
-            // The loop is executed until a fixpoint is reached (no changes in an iteration)
-            do {
-                changeOccurred = false;
-
-                try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) {
-
-                    // iterate all blocks in reverse order
-                    for (int i = numBlocks - 1; i >= 0; i--) {
-                        AbstractBlockBase<?> block = blockAt(i);
-                        BlockData blockSets = blockData.get(block);
-
-                        changeOccurredInBlock = false;
-
-                        // liveOut(block) is the union of liveIn(sux), for successors sux of block
-                        int n = block.getSuccessorCount();
-                        if (n > 0) {
-                            liveOut.clear();
-                            // block has successors
-                            if (n > 0) {
-                                for (AbstractBlockBase<?> successor : block.getSuccessors()) {
-                                    liveOut.or(blockData.get(successor).liveIn);
-                                }
-                            }
-
-                            if (!blockSets.liveOut.equals(liveOut)) {
-                                // A change occurred. Swap the old and new live out
-                                // sets to avoid copying.
-                                BitSet temp = blockSets.liveOut;
-                                blockSets.liveOut = liveOut;
-                                liveOut = temp;
-
-                                changeOccurred = true;
-                                changeOccurredInBlock = true;
-                            }
-                        }
-
-                        if (iterationCount == 0 || changeOccurredInBlock) {
-                            // liveIn(block) is the union of liveGen(block) with (liveOut(block) &
-                            // !liveKill(block))
-                            // note: liveIn has to be computed only in first iteration
-                            // or if liveOut has changed!
-                            BitSet liveIn = blockSets.liveIn;
-                            liveIn.clear();
-                            liveIn.or(blockSets.liveOut);
-                            liveIn.andNot(blockSets.liveKill);
-                            liveIn.or(blockSets.liveGen);
-
-                            if (Debug.isLogEnabled()) {
-                                Debug.log("block %d: livein = %s,  liveout = %s", block.getId(), liveIn, blockSets.liveOut);
-                            }
-                        }
-                    }
-                    iterationCount++;
-
-                    if (changeOccurred && iterationCount > 50) {
-                        throw new BailoutException("too many iterations in computeGlobalLiveSets");
-                    }
-                }
-            } while (changeOccurred);
-
-            if (DetailedAsserts.getValue()) {
-                verifyLiveness();
-            }
-
-            // check that the liveIn set of the first block is empty
-            AbstractBlockBase<?> startBlock = ir.getControlFlowGraph().getStartBlock();
-            if (blockData.get(startBlock).liveIn.cardinality() != 0) {
-                if (DetailedAsserts.getValue()) {
-                    reportFailure(numBlocks);
-                }
-                // bailout if this occurs in product mode.
-                throw new GraalInternalError("liveIn set of first block must be empty: " + blockData.get(startBlock).liveIn);
-            }
-        }
-    }
-
-    private void reportFailure(int numBlocks) {
-        try (Scope s = Debug.forceLog()) {
-            try (Indent indent = Debug.logAndIndent("report failure")) {
-
-                BitSet startBlockLiveIn = blockData.get(ir.getControlFlowGraph().getStartBlock()).liveIn;
-                try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) {
-                    for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
-                        Interval interval = intervalFor(operandNum);
-                        if (interval != null) {
-                            Value operand = interval.operand;
-                            Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getSourceForOperandFromDebugContext(operand));
-                        } else {
-                            Debug.log("var %d; missing operand", operandNum);
-                        }
-                    }
-                }
-
-                // print some additional information to simplify debugging
-                for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
-                    Interval interval = intervalFor(operandNum);
-                    Value operand = null;
-                    Object valueForOperandFromDebugContext = null;
-                    if (interval != null) {
-                        operand = interval.operand;
-                        valueForOperandFromDebugContext = getSourceForOperandFromDebugContext(operand);
-                    }
-                    try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, valueForOperandFromDebugContext)) {
-
-                        Deque<AbstractBlockBase<?>> definedIn = new ArrayDeque<>();
-                        HashSet<AbstractBlockBase<?>> usedIn = new HashSet<>();
-                        for (AbstractBlockBase<?> block : sortedBlocks) {
-                            if (blockData.get(block).liveGen.get(operandNum)) {
-                                usedIn.add(block);
-                                try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) {
-                                    for (LIRInstruction ins : ir.getLIRforBlock(block)) {
-                                        try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) {
-                                            ins.forEachState((liveStateOperand, mode, flags) -> {
-                                                Debug.log("operand=%s", liveStateOperand);
-                                                return liveStateOperand;
-                                            });
-                                        }
-                                    }
-                                }
-                            }
-                            if (blockData.get(block).liveKill.get(operandNum)) {
-                                definedIn.add(block);
-                                try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) {
-                                    for (LIRInstruction ins : ir.getLIRforBlock(block)) {
-                                        Debug.log("%d: %s", ins.id(), ins);
-                                    }
-                                }
-                            }
-                        }
-
-                        int[] hitCount = new int[numBlocks];
-
-                        while (!definedIn.isEmpty()) {
-                            AbstractBlockBase<?> block = definedIn.removeFirst();
-                            usedIn.remove(block);
-                            for (AbstractBlockBase<?> successor : block.getSuccessors()) {
-                                if (successor.isLoopHeader()) {
-                                    if (!block.isLoopEnd()) {
-                                        definedIn.add(successor);
-                                    }
-                                } else {
-                                    if (++hitCount[successor.getId()] == successor.getPredecessorCount()) {
-                                        definedIn.add(successor);
-                                    }
-                                }
-                            }
-                        }
-                        try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) {
-                            for (AbstractBlockBase<?> block : usedIn) {
-                                Debug.log("B%d", block.getId());
-                            }
-                        }
-                    }
-                }
-            }
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-    }
-
-    private void verifyLiveness() {
-        // check that fixed intervals are not live at block boundaries
-        // (live set must be empty at fixed intervals)
-        for (AbstractBlockBase<?> block : sortedBlocks) {
-            for (int j = 0; j <= maxRegisterNumber(); j++) {
-                assert !blockData.get(block).liveIn.get(j) : "liveIn  set of fixed register must be empty";
-                assert !blockData.get(block).liveOut.get(j) : "liveOut set of fixed register must be empty";
-                assert !blockData.get(block).liveGen.get(j) : "liveGen set of fixed register must be empty";
-            }
-        }
-    }
-
-    void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
-        if (!isProcessed(operand)) {
-            return;
-        }
-
-        Interval interval = getOrCreateInterval(operand);
-        if (!kind.equals(LIRKind.Illegal)) {
-            interval.setKind(kind);
-        }
-
-        interval.addRange(from, to);
-
-        // Register use position at even instruction id.
-        interval.addUsePos(to & ~1, registerPriority);
-
-        if (Debug.isLogEnabled()) {
-            Debug.log("add use: %s, from %d to %d (%s)", interval, from, to, registerPriority.name());
-        }
-    }
-
-    void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
-        if (!isProcessed(operand)) {
-            return;
-        }
-
-        Interval interval = getOrCreateInterval(operand);
-        if (!kind.equals(LIRKind.Illegal)) {
-            interval.setKind(kind);
-        }
-
-        interval.addRange(tempPos, tempPos + 1);
-        interval.addUsePos(tempPos, registerPriority);
-        interval.addMaterializationValue(null);
-
-        if (Debug.isLogEnabled()) {
-            Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
-        }
-    }
-
     boolean isProcessed(Value operand) {
         return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable();
     }
 
-    void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
-        if (!isProcessed(operand)) {
-            return;
-        }
-        int defPos = op.id();
-
-        Interval interval = getOrCreateInterval(operand);
-        if (!kind.equals(LIRKind.Illegal)) {
-            interval.setKind(kind);
-        }
-
-        Range r = interval.first();
-        if (r.from <= defPos) {
-            // Update the starting point (when a range is first created for a use, its
-            // start is the beginning of the current block until a def is encountered.)
-            r.from = defPos;
-            interval.addUsePos(defPos, registerPriority);
-
-        } else {
-            // Dead value - make vacuous interval
-            // also add register priority for dead intervals
-            interval.addRange(defPos, defPos + 1);
-            interval.addUsePos(defPos, registerPriority);
-            if (Debug.isLogEnabled()) {
-                Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
-            }
-        }
-
-        changeSpillDefinitionPos(interval, defPos);
-        if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) {
-            // detection of method-parameters and roundfp-results
-            interval.setSpillState(SpillState.StartInMemory);
-        }
-        interval.addMaterializationValue(LinearScan.getMaterializedValue(op, operand, interval));
-
-        if (Debug.isLogEnabled()) {
-            Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
-        }
-    }
-
-    /**
-     * Determines the register priority for an instruction's output/result operand.
-     */
-    static RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
-        if (op instanceof MoveOp) {
-            MoveOp move = (MoveOp) op;
-            if (optimizeMethodArgument(move.getInput())) {
-                return RegisterPriority.None;
-            }
-        } else if (op instanceof LabelOp) {
-            LabelOp label = (LabelOp) op;
-            if (label.isPhiIn()) {
-                return RegisterPriority.None;
-            }
-        }
-
-        // all other operands require a register
-        return RegisterPriority.MustHaveRegister;
-    }
-
-    /**
-     * Determines the priority which with an instruction's input operand will be allocated a
-     * register.
-     */
-    static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
-        if (flags.contains(OperandFlag.STACK)) {
-            return RegisterPriority.ShouldHaveRegister;
-        }
-        // all other operands require a register
-        return RegisterPriority.MustHaveRegister;
-    }
-
-    private static boolean optimizeMethodArgument(Value value) {
-        /*
-         * Object method arguments that are passed on the stack are currently not optimized because
-         * this requires that the runtime visits method arguments during stack walking.
-         */
-        return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && value.getKind() != Kind.Object;
-    }
-
-    /**
-     * Optimizes moves related to incoming stack based arguments. The interval for the destination
-     * of such moves is assigned the stack slot (which is in the caller's frame) as its spill slot.
-     */
-    void handleMethodArguments(LIRInstruction op) {
-        if (op instanceof MoveOp) {
-            MoveOp move = (MoveOp) op;
-            if (optimizeMethodArgument(move.getInput())) {
-                StackSlot slot = asStackSlot(move.getInput());
-                if (DetailedAsserts.getValue()) {
-                    assert op.id() > 0 : "invalid id";
-                    assert blockForId(op.id()).getPredecessorCount() == 0 : "move from stack must be in first block";
-                    assert isVariable(move.getResult()) : "result of move must be a variable";
-
-                    if (Debug.isLogEnabled()) {
-                        Debug.log("found move from stack slot %s to %s", slot, move.getResult());
-                    }
-                }
-
-                Interval interval = intervalFor(move.getResult());
-                interval.setSpillSlot(slot);
-                interval.assignLocation(slot);
-            }
-        }
-    }
-
-    void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
-        if (flags.contains(OperandFlag.HINT) && isVariableOrRegister(targetValue)) {
-
-            op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> {
-                if (isVariableOrRegister(registerHint)) {
-                    Interval from = getOrCreateInterval((AllocatableValue) registerHint);
-                    Interval to = getOrCreateInterval((AllocatableValue) targetValue);
-
-                    /* hints always point from def to use */
-                    if (hintAtDef) {
-                        to.setLocationHint(from);
-                    } else {
-                        from.setLocationHint(to);
-                    }
-                    if (Debug.isLogEnabled()) {
-                        Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber);
-                    }
-
-                    return registerHint;
-                }
-                return null;
-            });
-        }
-    }
-
-    void buildIntervals() {
-
-        try (Indent indent = Debug.logAndIndent("build intervals")) {
-            InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
-                if (isVariableOrRegister(operand)) {
-                    addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind());
-                    addRegisterHint(op, operand, mode, flags, true);
-                }
-            };
-
-            InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> {
-                if (isVariableOrRegister(operand)) {
-                    addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind());
-                    addRegisterHint(op, operand, mode, flags, false);
-                }
-            };
-
-            InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> {
-                if (isVariableOrRegister(operand)) {
-                    RegisterPriority p = registerPriorityOfInputOperand(flags);
-                    int opId = op.id();
-                    int blockFrom = getFirstLirInstructionId((blockForId(opId)));
-                    addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind());
-                    addRegisterHint(op, operand, mode, flags, false);
-                }
-            };
-
-            InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> {
-                if (isVariableOrRegister(operand)) {
-                    int opId = op.id();
-                    int blockFrom = getFirstLirInstructionId((blockForId(opId)));
-                    RegisterPriority p = registerPriorityOfInputOperand(flags);
-                    addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind());
-                    addRegisterHint(op, operand, mode, flags, false);
-                }
-            };
-
-            InstructionValueConsumer stateProc = (op, operand, mode, flags) -> {
-                if (isVariableOrRegister(operand)) {
-                    int opId = op.id();
-                    int blockFrom = getFirstLirInstructionId((blockForId(opId)));
-                    addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind());
-                }
-            };
-
-            // create a list with all caller-save registers (cpu, fpu, xmm)
-            Register[] callerSaveRegs = regAllocConfig.getRegisterConfig().getCallerSaveRegisters();
-
-            // iterate all blocks in reverse order
-            for (int i = blockCount() - 1; i >= 0; i--) {
-
-                AbstractBlockBase<?> block = blockAt(i);
-                try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
-
-                    List<LIRInstruction> instructions = ir.getLIRforBlock(block);
-                    final int blockFrom = getFirstLirInstructionId(block);
-                    int blockTo = getLastLirInstructionId(block);
-
-                    assert blockFrom == instructions.get(0).id();
-                    assert blockTo == instructions.get(instructions.size() - 1).id();
-
-                    // Update intervals for operands live at the end of this block;
-                    BitSet live = blockData.get(block).liveOut;
-                    for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) {
-                        assert live.get(operandNum) : "should not stop here otherwise";
-                        AllocatableValue operand = intervalFor(operandNum).operand;
-                        if (Debug.isLogEnabled()) {
-                            Debug.log("live in %d: %s", operandNum, operand);
-                        }
-
-                        addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, LIRKind.Illegal);
-
-                        // add special use positions for loop-end blocks when the
-                        // interval is used anywhere inside this loop. It's possible
-                        // that the block was part of a non-natural loop, so it might
-                        // have an invalid loop index.
-                        if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().getIndex())) {
-                            intervalFor(operandNum).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd);
-                        }
-                    }
-
-                    // iterate all instructions of the block in reverse order.
-                    // definitions of intervals are processed before uses
-                    for (int j = instructions.size() - 1; j >= 0; j--) {
-                        final LIRInstruction op = instructions.get(j);
-                        final int opId = op.id();
-
-                        try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) {
-
-                            // add a temp range for each register if operation destroys
-                            // caller-save registers
-                            if (op.destroysCallerSavedRegisters()) {
-                                for (Register r : callerSaveRegs) {
-                                    if (attributes(r).isAllocatable()) {
-                                        addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal);
-                                    }
-                                }
-                                if (Debug.isLogEnabled()) {
-                                    Debug.log("operation destroys all caller-save registers");
-                                }
-                            }
-
-                            op.visitEachOutput(outputConsumer);
-                            op.visitEachTemp(tempConsumer);
-                            op.visitEachAlive(aliveConsumer);
-                            op.visitEachInput(inputConsumer);
-
-                            // Add uses of live locals from interpreter's point of view for proper
-                            // debug information generation
-                            // Treat these operands as temp values (if the live range is extended
-                            // to a call site, the value would be in a register at
-                            // the call otherwise)
-                            op.visitEachState(stateProc);
-
-                            // special steps for some instructions (especially moves)
-                            handleMethodArguments(op);
-
-                        }
-
-                    } // end of instruction iteration
-                }
-            } // end of block iteration
-
-            // add the range [0, 1] to all fixed intervals.
-            // the register allocator need not handle unhandled fixed intervals
-            for (Interval interval : intervals) {
-                if (interval != null && isRegister(interval.operand)) {
-                    interval.addRange(0, 1);
-                }
-            }
-        }
-    }
-
     // * Phase 5: actual register allocation
 
     private static boolean isSorted(Interval[] intervals) {
@@ -1461,30 +582,6 @@
         sortedIntervals = combinedList;
     }
 
-    void allocateRegisters() {
-        try (Indent indent = Debug.logAndIndent("allocate registers")) {
-            Interval precoloredIntervals;
-            Interval notPrecoloredIntervals;
-
-            Interval.Pair result = createUnhandledLists(IS_PRECOLORED_INTERVAL, IS_VARIABLE_INTERVAL);
-            precoloredIntervals = result.first;
-            notPrecoloredIntervals = result.second;
-
-            // allocate cpu registers
-            LinearScanWalker lsw;
-            if (OptimizingLinearScanWalker.Options.LSRAOptimization.getValue()) {
-                lsw = new OptimizingLinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals);
-            } else {
-                lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals);
-            }
-            lsw.walk();
-            lsw.finishAllocation();
-        }
-    }
-
-    // * Phase 6: resolve data flow
-    // (insert moves at edges between blocks if intervals have been split)
-
     // wrapper for Interval.splitChildAtOpId that performs a bailout in product mode
     // instead of returning null
     Interval splitChildAtOpId(Interval interval, int opId, LIRInstruction.OperandMode mode) {
@@ -1500,405 +597,59 @@
         throw new BailoutException("LinearScan: interval is null");
     }
 
-    void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
-        assert moveResolver.checkEmpty();
-        assert midBlock == null ||
-                        (midBlock.getPredecessorCount() == 1 && midBlock.getSuccessorCount() == 1 && midBlock.getPredecessors().get(0).equals(fromBlock) && midBlock.getSuccessors().get(0).equals(
-                                        toBlock));
-
-        int toBlockFirstInstructionId = getFirstLirInstructionId(toBlock);
-        int fromBlockLastInstructionId = getLastLirInstructionId(fromBlock) + 1;
-        int numOperands = operandSize();
-        BitSet liveAtEdge = blockData.get(toBlock).liveIn;
-
-        // visit all variables for which the liveAtEdge bit is set
-        for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) {
-            assert operandNum < numOperands : "live information set for not exisiting interval";
-            assert blockData.get(fromBlock).liveOut.get(operandNum) && blockData.get(toBlock).liveIn.get(operandNum) : "interval not live at this edge";
-
-            Interval fromInterval = splitChildAtOpId(intervalFor(operandNum), fromBlockLastInstructionId, LIRInstruction.OperandMode.DEF);
-            Interval toInterval = splitChildAtOpId(intervalFor(operandNum), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
-
-            if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
-                // need to insert move instruction
-                moveResolver.addMapping(fromInterval, toInterval);
-            }
-        }
-    }
-
-    void resolveFindInsertPos(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, MoveResolver moveResolver) {
-        if (fromBlock.getSuccessorCount() <= 1) {
-            if (Debug.isLogEnabled()) {
-                Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
-            }
-
-            List<LIRInstruction> instructions = ir.getLIRforBlock(fromBlock);
-            LIRInstruction instr = instructions.get(instructions.size() - 1);
-            if (instr instanceof StandardOp.JumpOp) {
-                // insert moves before branch
-                moveResolver.setInsertPosition(instructions, instructions.size() - 1);
-            } else {
-                moveResolver.setInsertPosition(instructions, instructions.size());
-            }
-
-        } else {
-            if (Debug.isLogEnabled()) {
-                Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
-            }
-
-            if (DetailedAsserts.getValue()) {
-                assert ir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
-
-                // because the number of predecessor edges matches the number of
-                // successor edges, blocks which are reached by switch statements
-                // may have be more than one predecessor but it will be guaranteed
-                // that all predecessors will be the same.
-                for (AbstractBlockBase<?> predecessor : toBlock.getPredecessors()) {
-                    assert fromBlock == predecessor : "all critical edges must be broken";
-                }
-            }
-
-            moveResolver.setInsertPosition(ir.getLIRforBlock(toBlock), 1);
-        }
-    }
-
-    /**
-     * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals that
-     * have been split.
-     */
-    void resolveDataFlow() {
-        try (Indent indent = Debug.logAndIndent("resolve data flow")) {
-
-            int numBlocks = blockCount();
-            MoveResolver moveResolver = createMoveResolver();
-            BitSet blockCompleted = new BitSet(numBlocks);
-            BitSet alreadyResolved = new BitSet(numBlocks);
-
-            for (AbstractBlockBase<?> block : sortedBlocks) {
-
-                // check if block has only one predecessor and only one successor
-                if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) {
-                    List<LIRInstruction> instructions = ir.getLIRforBlock(block);
-                    assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label";
-                    assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump";
-
-                    // check if block is empty (only label and branch)
-                    if (instructions.size() == 2) {
-                        AbstractBlockBase<?> pred = block.getPredecessors().iterator().next();
-                        AbstractBlockBase<?> sux = block.getSuccessors().iterator().next();
-
-                        // prevent optimization of two consecutive blocks
-                        if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) {
-                            if (Debug.isLogEnabled()) {
-                                Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId());
-                            }
-
-                            blockCompleted.set(block.getLinearScanNumber());
-
-                            // directly resolve between pred and sux (without looking
-                            // at the empty block
-                            // between)
-                            resolveCollectMappings(pred, sux, block, moveResolver);
-                            if (moveResolver.hasMappings()) {
-                                moveResolver.setInsertPosition(instructions, 1);
-                                moveResolver.resolveAndAppendMoves();
-                            }
-                        }
-                    }
-                }
-            }
-
-            for (AbstractBlockBase<?> fromBlock : sortedBlocks) {
-                if (!blockCompleted.get(fromBlock.getLinearScanNumber())) {
-                    alreadyResolved.clear();
-                    alreadyResolved.or(blockCompleted);
-
-                    for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) {
-
-                        // check for duplicate edges between the same blocks (can happen with switch
-                        // blocks)
-                        if (!alreadyResolved.get(toBlock.getLinearScanNumber())) {
-                            if (Debug.isLogEnabled()) {
-                                Debug.log("processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId());
-                            }
-
-                            alreadyResolved.set(toBlock.getLinearScanNumber());
-
-                            // collect all intervals that have been split between
-                            // fromBlock and toBlock
-                            resolveCollectMappings(fromBlock, toBlock, null, moveResolver);
-                            if (moveResolver.hasMappings()) {
-                                resolveFindInsertPos(fromBlock, toBlock, moveResolver);
-                                moveResolver.resolveAndAppendMoves();
-                            }
-                        }
-                    }
-                }
-            }
-
-        }
-    }
-
-    // * Phase 7: assign register numbers back to LIR
-    // (includes computation of debug information and oop maps)
-
     static StackSlotValue canonicalSpillOpr(Interval interval) {
         assert interval.spillSlot() != null : "canonical spill slot not set";
         return interval.spillSlot();
     }
 
-    /**
-     * Assigns the allocated location for an LIR instruction operand back into the instruction.
-     *
-     * @param operand an LIR instruction operand
-     * @param opId the id of the LIR instruction using {@code operand}
-     * @param mode the usage mode for {@code operand} by the instruction
-     * @return the location assigned for the operand
-     */
-    private Value colorLirOperand(Variable operand, int opId, OperandMode mode) {
+    boolean isMaterialized(AllocatableValue operand, int opId, OperandMode mode) {
         Interval interval = intervalFor(operand);
         assert interval != null : "interval must exist";
 
         if (opId != -1) {
-            if (DetailedAsserts.getValue()) {
-                AbstractBlockBase<?> block = blockForId(opId);
-                if (block.getSuccessorCount() <= 1 && opId == getLastLirInstructionId(block)) {
-                    /*
-                     * Check if spill moves could have been appended at the end of this block, but
-                     * before the branch instruction. So the split child information for this branch
-                     * would be incorrect.
-                     */
-                    LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1);
-                    if (instr instanceof StandardOp.JumpOp) {
-                        if (blockData.get(block).liveOut.get(operandNumber(operand))) {
-                            assert false : String.format(
-                                            "can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow) block=%s, instruction=%s, operand=%s",
-                                            block, instr, operand);
-                        }
-                    }
-                }
-            }
-
-            // operands are not changed when an interval is split during allocation,
-            // so search the right interval here
-            interval = splitChildAtOpId(interval, opId, mode);
-        }
-
-        if (isIllegal(interval.location()) && interval.canMaterialize()) {
-            assert mode != OperandMode.DEF;
-            return interval.getMaterializedValue();
-        }
-        return interval.location();
-    }
-
-    private boolean isMaterialized(AllocatableValue operand, int opId, OperandMode mode) {
-        Interval interval = intervalFor(operand);
-        assert interval != null : "interval must exist";
-
-        if (opId != -1) {
-            // operands are not changed when an interval is split during allocation,
-            // so search the right interval here
+            /*
+             * Operands are not changed when an interval is split during allocation, so search the
+             * right interval here.
+             */
             interval = splitChildAtOpId(interval, opId, mode);
         }
 
         return isIllegal(interval.location()) && interval.canMaterialize();
     }
 
-    protected IntervalWalker initIntervalWalker(IntervalPredicate predicate) {
-        // setup lists of potential oops for walking
-        Interval oopIntervals;
-        Interval nonOopIntervals;
-
-        oopIntervals = createUnhandledLists(predicate, null).first;
-
-        // intervals that have no oops inside need not to be processed.
-        // to ensure a walking until the last instruction id, add a dummy interval
-        // with a high operation id
-        nonOopIntervals = new Interval(Value.ILLEGAL, -1);
-        nonOopIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1);
-
-        return new IntervalWalker(this, oopIntervals, nonOopIntervals);
-    }
-
-    private boolean isCallerSave(Value operand) {
+    boolean isCallerSave(Value operand) {
         return attributes(asRegister(operand)).isCallerSave();
     }
 
-    /**
-     * @param op
-     * @param operand
-     * @param valueMode
-     * @param flags
-     * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet)
-     */
-    private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) {
-        if (isVirtualStackSlot(operand)) {
-            return operand;
-        }
-        int tempOpId = op.id();
-        OperandMode mode = OperandMode.USE;
-        AbstractBlockBase<?> block = blockForId(tempOpId);
-        if (block.getSuccessorCount() == 1 && tempOpId == getLastLirInstructionId(block)) {
-            // generating debug information for the last instruction of a block.
-            // if this instruction is a branch, spill moves are inserted before this branch
-            // and so the wrong operand would be returned (spill moves at block boundaries
-            // are not
-            // considered in the live ranges of intervals)
-            // Solution: use the first opId of the branch target block instead.
-            final LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1);
-            if (instr instanceof StandardOp.JumpOp) {
-                if (blockData.get(block).liveOut.get(operandNumber(operand))) {
-                    tempOpId = getFirstLirInstructionId(block.getSuccessors().iterator().next());
-                    mode = OperandMode.DEF;
-                }
-            }
-        }
-
-        // Get current location of operand
-        // The operand must be live because debug information is considered when building
-        // the intervals
-        // if the interval is not live, colorLirOperand will cause an assert on failure
-        Value result = colorLirOperand((Variable) operand, tempOpId, mode);
-        assert !hasCall(tempOpId) || isStackSlotValue(result) || isConstant(result) || !isCallerSave(result) : "cannot have caller-save register operands at calls";
-        return result;
-    }
-
-    private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) {
-        info.forEachState(op, this::debugInfoProcedure);
-    }
-
-    private void assignLocations(List<LIRInstruction> instructions) {
-        int numInst = instructions.size();
-        boolean hasDead = false;
-
-        InstructionValueProcedure assignProc = (op, operand, mode, flags) -> isVariable(operand) ? colorLirOperand((Variable) operand, op.id(), mode) : operand;
-        for (int j = 0; j < numInst; j++) {
-            final LIRInstruction op = instructions.get(j);
-            if (op == null) { // this can happen when spill-moves are removed in eliminateSpillMoves
-                hasDead = true;
-                continue;
-            }
-
-            // remove useless moves
-            MoveOp move = null;
-            if (op instanceof MoveOp) {
-                move = (MoveOp) op;
-                AllocatableValue result = move.getResult();
-                if (isVariable(result) && isMaterialized(result, op.id(), OperandMode.DEF)) {
-                    /*
-                     * This happens if a materializable interval is originally not spilled but then
-                     * kicked out in LinearScanWalker.splitForSpilling(). When kicking out such an
-                     * interval this move operation was already generated.
-                     */
-                    instructions.set(j, null);
-                    hasDead = true;
-                    continue;
-                }
-            }
-
-            op.forEachInput(assignProc);
-            op.forEachAlive(assignProc);
-            op.forEachTemp(assignProc);
-            op.forEachOutput(assignProc);
-
-            // compute reference map and debug information
-            op.forEachState((inst, state) -> computeDebugInfo(inst, state));
-
-            // remove useless moves
-            if (move != null) {
-                if (move.getInput().equals(move.getResult())) {
-                    instructions.set(j, null);
-                    hasDead = true;
-                }
-            }
-        }
-
-        if (hasDead) {
-            // Remove null values from the list.
-            instructions.removeAll(Collections.singleton(null));
-        }
-    }
-
-    private void assignLocations() {
-        try (Indent indent = Debug.logAndIndent("assign locations")) {
-            for (AbstractBlockBase<?> block : sortedBlocks) {
-                try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
-                    assignLocations(ir.getLIRforBlock(block));
-                }
-            }
-        }
-    }
-
-    private static final DebugTimer lifetimeTimer = Debug.timer("LinearScan_LifetimeAnalysis");
-    private static final DebugTimer registerAllocationTimer = Debug.timer("LinearScan_RegisterAllocation");
-    private static final DebugTimer optimizedSpillPositionTimer = Debug.timer("LinearScan_OptimizeSpillPosition");
-    private static final DebugTimer resolveDataFlowTimer = Debug.timer("LinearScan_ResolveDataFlow");
-    private static final DebugTimer eliminateSpillMoveTimer = Debug.timer("LinearScan_EliminateSpillMove");
-    private static final DebugTimer assignLocationsTimer = Debug.timer("LinearScan_AssignLocations");
-
-    void allocate() {
+    <B extends AbstractBlockBase<B>> void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
 
         /*
          * This is the point to enable debug logging for the whole register allocation.
          */
         try (Indent indent = Debug.logAndIndent("LinearScan allocate")) {
+            AllocationContext context = new AllocationContext(spillMoveFactory, registerAllocationConfig);
 
-            try (Scope s = Debug.scope("LifetimeAnalysis"); DebugCloseable a = lifetimeTimer.start()) {
-                numberInstructions();
-                printLir("Before register allocation", true);
-                computeLocalLiveSets();
-                computeGlobalLiveSets();
-                buildIntervals();
+            createLifetimeAnalysisPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
+
+            try (Scope s = Debug.scope("AfterLifetimeAnalysis", intervals)) {
                 sortIntervalsBeforeAllocation();
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
 
-            try (Scope s = Debug.scope("RegisterAllocation"); DebugCloseable a = registerAllocationTimer.start()) {
-                printIntervals("Before register allocation");
-                allocateRegisters();
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
+                createRegisterAllocationPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
 
-            if (Options.LSRAOptimizeSpillPosition.getValue()) {
-                try (Scope s = Debug.scope("OptimizeSpillPosition"); DebugCloseable a = optimizedSpillPositionTimer.start()) {
-                    optimizeSpillPosition();
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
+                if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) {
+                    createOptimizeSpillPositionPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
                 }
-            }
-
-            try (Scope s = Debug.scope("ResolveDataFlow"); DebugCloseable a = resolveDataFlowTimer.start()) {
-                resolveDataFlow();
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-
-            try (Scope s = Debug.scope("DebugInfo")) {
-                printIntervals("After register allocation");
-                printLir("After register allocation", true);
+                createResolveDataFlowPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
 
                 sortIntervalsAfterAllocation();
 
                 if (DetailedAsserts.getValue()) {
                     verify();
                 }
-
                 beforeSpillMoveElimination();
-
-                try (Scope s1 = Debug.scope("EliminateSpillMove"); DebugCloseable a = eliminateSpillMoveTimer.start()) {
-                    eliminateSpillMoves();
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
-                }
-                printLir("After spill move elimination", true);
-
-                try (Scope s1 = Debug.scope("AssignLocations"); DebugCloseable a = assignLocationsTimer.start()) {
-                    assignLocations();
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
-                }
+                createSpillMoveEliminationPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
+                createAssignLocationsPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
 
                 if (DetailedAsserts.getValue()) {
                     verifyIntervals();
@@ -1906,173 +657,34 @@
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
-
-            printLir("After register number assignment", true);
         }
     }
 
     protected void beforeSpillMoveElimination() {
     }
 
-    private static final DebugMetric betterSpillPos = Debug.metric("BetterSpillPosition");
-    private static final DebugMetric betterSpillPosWithLowerProbability = Debug.metric("BetterSpillPositionWithLowerProbability");
-
-    private void optimizeSpillPosition() {
-        LIRInsertionBuffer[] insertionBuffers = new LIRInsertionBuffer[ir.linearScanOrder().size()];
-        for (Interval interval : intervals) {
-            if (interval != null && interval.isSplitParent() && interval.spillState() == SpillState.SpillInDominator) {
-                AbstractBlockBase<?> defBlock = blockForId(interval.spillDefinitionPos());
-                AbstractBlockBase<?> spillBlock = null;
-                Interval firstSpillChild = null;
-                try (Indent indent = Debug.logAndIndent("interval %s (%s)", interval, defBlock)) {
-                    for (Interval splitChild : interval.getSplitChildren()) {
-                        if (isStackSlotValue(splitChild.location())) {
-                            if (firstSpillChild == null || splitChild.from() < firstSpillChild.from()) {
-                                firstSpillChild = splitChild;
-                            } else {
-                                assert firstSpillChild.from() < splitChild.from();
-                            }
-                            // iterate all blocks where the interval has use positions
-                            for (AbstractBlockBase<?> splitBlock : blocksForInterval(splitChild)) {
-                                if (dominates(defBlock, splitBlock)) {
-                                    if (Debug.isLogEnabled()) {
-                                        Debug.log("Split interval %s, block %s", splitChild, splitBlock);
-                                    }
-                                    if (spillBlock == null) {
-                                        spillBlock = splitBlock;
-                                    } else {
-                                        spillBlock = commonDominator(spillBlock, splitBlock);
-                                        assert spillBlock != null;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    if (spillBlock == null) {
-                        // no spill interval
-                        interval.setSpillState(SpillState.StoreAtDefinition);
-                    } else {
-                        // move out of loops
-                        if (defBlock.getLoopDepth() < spillBlock.getLoopDepth()) {
-                            spillBlock = moveSpillOutOfLoop(defBlock, spillBlock);
-                        }
+    protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() {
+        return new LinearScanLifetimeAnalysisPhase(this);
+    }
 
-                        /*
-                         * If the spill block is the begin of the first split child (aka the value
-                         * is on the stack) spill in the dominator.
-                         */
-                        assert firstSpillChild != null;
-                        if (!defBlock.equals(spillBlock) && spillBlock.equals(blockForId(firstSpillChild.from()))) {
-                            AbstractBlockBase<?> dom = spillBlock.getDominator();
-                            if (Debug.isLogEnabled()) {
-                                Debug.log("Spill block (%s) is the beginning of a spill child -> use dominator (%s)", spillBlock, dom);
-                            }
-                            spillBlock = dom;
-                        }
-
-                        if (!defBlock.equals(spillBlock)) {
-                            assert dominates(defBlock, spillBlock);
-                            betterSpillPos.increment();
-                            if (Debug.isLogEnabled()) {
-                                Debug.log("Better spill position found (Block %s)", spillBlock);
-                            }
-
-                            if (defBlock.probability() <= spillBlock.probability()) {
-                                // better spill block has the same probability -> do nothing
-                                interval.setSpillState(SpillState.StoreAtDefinition);
-                            } else {
-                                LIRInsertionBuffer insertionBuffer = insertionBuffers[spillBlock.getId()];
-                                if (insertionBuffer == null) {
-                                    insertionBuffer = new LIRInsertionBuffer();
-                                    insertionBuffers[spillBlock.getId()] = insertionBuffer;
-                                    insertionBuffer.init(ir.getLIRforBlock(spillBlock));
-                                }
-                                int spillOpId = getFirstLirInstructionId(spillBlock);
-                                // insert spill move
-                                AllocatableValue fromLocation = interval.getSplitChildAtOpId(spillOpId, OperandMode.DEF, this).location();
-                                AllocatableValue toLocation = canonicalSpillOpr(interval);
-                                LIRInstruction move = getSpillMoveFactory().createMove(toLocation, fromLocation);
-                                move.setId(DOMINATOR_SPILL_MOVE_ID);
-                                /*
-                                 * We can use the insertion buffer directly because we always insert
-                                 * at position 1.
-                                 */
-                                insertionBuffer.append(1, move);
-
-                                betterSpillPosWithLowerProbability.increment();
-                                interval.setSpillDefinitionPos(spillOpId);
-                            }
-                        } else {
-                            // definition is the best choice
-                            interval.setSpillState(SpillState.StoreAtDefinition);
-                        }
-                    }
-                }
-            }
-        }
-        for (LIRInsertionBuffer insertionBuffer : insertionBuffers) {
-            if (insertionBuffer != null) {
-                assert insertionBuffer.initialized() : "Insertion buffer is nonnull but not initialized!";
-                insertionBuffer.finish();
-            }
-        }
+    protected LinearScanRegisterAllocationPhase createRegisterAllocationPhase() {
+        return new LinearScanRegisterAllocationPhase(this);
     }
 
-    /**
-     * Iterate over all {@link AbstractBlockBase blocks} of an interval.
-     */
-    private class IntervalBlockIterator implements Iterator<AbstractBlockBase<?>> {
-
-        Range range;
-        AbstractBlockBase<?> block;
-
-        public IntervalBlockIterator(Interval interval) {
-            range = interval.first();
-            block = blockForId(range.from);
-        }
-
-        public AbstractBlockBase<?> next() {
-            AbstractBlockBase<?> currentBlock = block;
-            int nextBlockIndex = block.getLinearScanNumber() + 1;
-            if (nextBlockIndex < sortedBlocks.size()) {
-                block = sortedBlocks.get(nextBlockIndex);
-                if (range.to <= getFirstLirInstructionId(block)) {
-                    range = range.next;
-                    if (range == Range.EndMarker) {
-                        block = null;
-                    } else {
-                        block = blockForId(range.from);
-                    }
-                }
-            } else {
-                block = null;
-            }
-            return currentBlock;
-        }
-
-        public boolean hasNext() {
-            return block != null;
-        }
+    protected LinearScanOptimizeSpillPositionPhase createOptimizeSpillPositionPhase() {
+        return new LinearScanOptimizeSpillPositionPhase(this);
     }
 
-    private Iterable<AbstractBlockBase<?>> blocksForInterval(Interval interval) {
-        return new Iterable<AbstractBlockBase<?>>() {
-            public Iterator<AbstractBlockBase<?>> iterator() {
-                return new IntervalBlockIterator(interval);
-            }
-        };
+    protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() {
+        return new LinearScanResolveDataFlowPhase(this);
     }
 
-    private static AbstractBlockBase<?> moveSpillOutOfLoop(AbstractBlockBase<?> defBlock, AbstractBlockBase<?> spillBlock) {
-        int defLoopDepth = defBlock.getLoopDepth();
-        for (AbstractBlockBase<?> block = spillBlock.getDominator(); !defBlock.equals(block); block = block.getDominator()) {
-            assert block != null : "spill block not dominated by definition block?";
-            if (block.getLoopDepth() <= defLoopDepth) {
-                assert block.getLoopDepth() == defLoopDepth : "Cannot spill an interval outside of the loop where it is defined!";
-                return block;
-            }
-        }
-        return defBlock;
+    protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() {
+        return new LinearScanEliminateSpillMovePhase(this);
+    }
+
+    protected LinearScanAssignLocationsPhase createAssignLocationsPhase() {
+        return new LinearScanAssignLocationsPhase(this);
     }
 
     void printIntervals(String label) {
@@ -2229,14 +841,18 @@
                         iw.walkBefore(op.id());
                         boolean checkLive = true;
 
-                        // Make sure none of the fixed registers is live across an
-                        // oopmap since we can't handle that correctly.
+                        /*
+                         * Make sure none of the fixed registers is live across an oopmap since we
+                         * can't handle that correctly.
+                         */
                         if (checkLive) {
                             for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) {
                                 if (interval.currentTo() > op.id() + 1) {
-                                    // This interval is live out of this op so make sure
-                                    // that this interval represents some value that's
-                                    // referenced by this op either as an input or output.
+                                    /*
+                                     * This interval is live out of this op so make sure that this
+                                     * interval represents some value that's referenced by this op
+                                     * either as an input or output.
+                                     */
                                     checkConsumer.curInterval = interval;
                                     checkConsumer.ok = false;
 
@@ -2255,37 +871,4 @@
         }
     }
 
-    /**
-     * Returns a value for a interval definition, which can be used for re-materialization.
-     *
-     * @param op An instruction which defines a value
-     * @param operand The destination operand of the instruction
-     * @param interval The interval for this defined value.
-     * @return Returns the value which is moved to the instruction and which can be reused at all
-     *         reload-locations in case the interval of this instruction is spilled. Currently this
-     *         can only be a {@link JavaConstant}.
-     */
-    public static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) {
-        if (op instanceof MoveOp) {
-            MoveOp move = (MoveOp) op;
-            if (move.getInput() instanceof JavaConstant) {
-                /*
-                 * Check if the interval has any uses which would accept an stack location (priority
-                 * == ShouldHaveRegister). Rematerialization of such intervals can result in a
-                 * degradation, because rematerialization always inserts a constant load, even if
-                 * the value is not needed in a register.
-                 */
-                Interval.UsePosList usePosList = interval.usePosList();
-                int numUsePos = usePosList.size();
-                for (int useIdx = 0; useIdx < numUsePos; useIdx++) {
-                    Interval.RegisterPriority priority = usePosList.registerPriority(useIdx);
-                    if (priority == Interval.RegisterPriority.ShouldHaveRegister) {
-                        return null;
-                    }
-                }
-                return (JavaConstant) move.getInput();
-            }
-        }
-        return null;
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanAssignLocationsPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.*;
+import com.oracle.graal.lir.phases.*;
+
+/**
+ * Phase 7: Assign register numbers back to LIR.
+ */
+final class LinearScanAssignLocationsPhase extends AllocationPhase {
+
+    private final LinearScan allocator;
+
+    LinearScanAssignLocationsPhase(LinearScan allocator) {
+        this.allocator = allocator;
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        assignLocations();
+    }
+
+    /**
+     * Assigns the allocated location for an LIR instruction operand back into the instruction.
+     *
+     * @param operand an LIR instruction operand
+     * @param opId the id of the LIR instruction using {@code operand}
+     * @param mode the usage mode for {@code operand} by the instruction
+     * @return the location assigned for the operand
+     */
+    private Value colorLirOperand(Variable operand, int opId, OperandMode mode) {
+        Interval interval = allocator.intervalFor(operand);
+        assert interval != null : "interval must exist";
+
+        if (opId != -1) {
+            if (DetailedAsserts.getValue()) {
+                AbstractBlockBase<?> block = allocator.blockForId(opId);
+                if (block.getSuccessorCount() <= 1 && opId == allocator.getLastLirInstructionId(block)) {
+                    /*
+                     * Check if spill moves could have been appended at the end of this block, but
+                     * before the branch instruction. So the split child information for this branch
+                     * would be incorrect.
+                     */
+                    LIRInstruction instr = allocator.ir.getLIRforBlock(block).get(allocator.ir.getLIRforBlock(block).size() - 1);
+                    if (instr instanceof StandardOp.JumpOp) {
+                        if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) {
+                            assert false : String.format(
+                                            "can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow) block=%s, instruction=%s, operand=%s",
+                                            block, instr, operand);
+                        }
+                    }
+                }
+            }
+
+            /*
+             * Operands are not changed when an interval is split during allocation, so search the
+             * right interval here.
+             */
+            interval = allocator.splitChildAtOpId(interval, opId, mode);
+        }
+
+        if (isIllegal(interval.location()) && interval.canMaterialize()) {
+            assert mode != OperandMode.DEF;
+            return interval.getMaterializedValue();
+        }
+        return interval.location();
+    }
+
+    /**
+     * @param op
+     * @param operand
+     * @param valueMode
+     * @param flags
+     * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet)
+     */
+    private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) {
+        if (isVirtualStackSlot(operand)) {
+            return operand;
+        }
+        int tempOpId = op.id();
+        OperandMode mode = OperandMode.USE;
+        AbstractBlockBase<?> block = allocator.blockForId(tempOpId);
+        if (block.getSuccessorCount() == 1 && tempOpId == allocator.getLastLirInstructionId(block)) {
+            /*
+             * Generating debug information for the last instruction of a block. If this instruction
+             * is a branch, spill moves are inserted before this branch and so the wrong operand
+             * would be returned (spill moves at block boundaries are not considered in the live
+             * ranges of intervals).
+             * 
+             * Solution: use the first opId of the branch target block instead.
+             */
+            final LIRInstruction instr = allocator.ir.getLIRforBlock(block).get(allocator.ir.getLIRforBlock(block).size() - 1);
+            if (instr instanceof StandardOp.JumpOp) {
+                if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) {
+                    tempOpId = allocator.getFirstLirInstructionId(block.getSuccessors().iterator().next());
+                    mode = OperandMode.DEF;
+                }
+            }
+        }
+
+        /*
+         * Get current location of operand. The operand must be live because debug information is
+         * considered when building the intervals if the interval is not live, colorLirOperand will
+         * cause an assert on failure.
+         */
+        Value result = colorLirOperand((Variable) operand, tempOpId, mode);
+        assert !allocator.hasCall(tempOpId) || isStackSlotValue(result) || isConstant(result) || !allocator.isCallerSave(result) : "cannot have caller-save register operands at calls";
+        return result;
+    }
+
+    private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) {
+        info.forEachState(op, this::debugInfoProcedure);
+    }
+
+    private void assignLocations(List<LIRInstruction> instructions) {
+        int numInst = instructions.size();
+        boolean hasDead = false;
+
+        InstructionValueProcedure assignProc = (op, operand, mode, flags) -> isVariable(operand) ? colorLirOperand((Variable) operand, op.id(), mode) : operand;
+        for (int j = 0; j < numInst; j++) {
+            final LIRInstruction op = instructions.get(j);
+            if (op == null) {
+                /*
+                 * this can happen when spill-moves are removed in eliminateSpillMoves
+                 */
+                hasDead = true;
+                continue;
+            }
+
+            // remove useless moves
+            MoveOp move = null;
+            if (op instanceof MoveOp) {
+                move = (MoveOp) op;
+                AllocatableValue result = move.getResult();
+                if (isVariable(result) && allocator.isMaterialized(result, op.id(), OperandMode.DEF)) {
+                    /*
+                     * This happens if a materializable interval is originally not spilled but then
+                     * kicked out in LinearScanWalker.splitForSpilling(). When kicking out such an
+                     * interval this move operation was already generated.
+                     */
+                    instructions.set(j, null);
+                    hasDead = true;
+                    continue;
+                }
+            }
+
+            op.forEachInput(assignProc);
+            op.forEachAlive(assignProc);
+            op.forEachTemp(assignProc);
+            op.forEachOutput(assignProc);
+
+            // compute reference map and debug information
+            op.forEachState((inst, state) -> computeDebugInfo(inst, state));
+
+            // remove useless moves
+            if (move != null) {
+                if (move.getInput().equals(move.getResult())) {
+                    instructions.set(j, null);
+                    hasDead = true;
+                }
+            }
+        }
+
+        if (hasDead) {
+            // Remove null values from the list.
+            instructions.removeAll(Collections.singleton(null));
+        }
+    }
+
+    private void assignLocations() {
+        try (Indent indent = Debug.logAndIndent("assign locations")) {
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+                try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
+                    assignLocations(allocator.ir.getLIRforBlock(block));
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.alloc.lsra.Interval.*;
+import com.oracle.graal.lir.alloc.lsra.LinearScan.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.*;
+import com.oracle.graal.lir.phases.*;
+
+class LinearScanEliminateSpillMovePhase extends AllocationPhase {
+
+    private static final IntervalPredicate mustStoreAtDefinition = new LinearScan.IntervalPredicate() {
+
+        @Override
+        public boolean apply(Interval i) {
+            return i.isSplitParent() && i.spillState() == SpillState.StoreAtDefinition;
+        }
+    };
+
+    protected final LinearScan allocator;
+
+    LinearScanEliminateSpillMovePhase(LinearScan allocator) {
+        this.allocator = allocator;
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        eliminateSpillMoves();
+    }
+
+    /**
+     * @return the index of the first instruction that is of interest for
+     *         {@link #eliminateSpillMoves()}
+     */
+    protected int firstInstructionOfInterest() {
+        // skip the first because it is always a label
+        return 1;
+    }
+
+    // called once before assignment of register numbers
+    void eliminateSpillMoves() {
+        try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves")) {
+
+            /*
+             * collect all intervals that must be stored after their definition. The list is sorted
+             * by Interval.spillDefinitionPos.
+             */
+            Interval interval;
+            interval = allocator.createUnhandledLists(mustStoreAtDefinition, null).first;
+            if (DetailedAsserts.getValue()) {
+                checkIntervals(interval);
+            }
+
+            LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer();
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+                try (Indent indent1 = Debug.logAndIndent("Handle %s", block)) {
+                    List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block);
+                    int numInst = instructions.size();
+
+                    // iterate all instructions of the block.
+                    for (int j = firstInstructionOfInterest(); j < numInst; j++) {
+                        LIRInstruction op = instructions.get(j);
+                        int opId = op.id();
+
+                        if (opId == -1) {
+                            MoveOp move = (MoveOp) op;
+                            /*
+                             * Remove move from register to stack if the stack slot is guaranteed to
+                             * be correct. Only moves that have been inserted by LinearScan can be
+                             * removed.
+                             */
+                            if (canEliminateSpillMove(block, move)) {
+                                /*
+                                 * Move target is a stack slot that is always correct, so eliminate
+                                 * instruction.
+                                 */
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", allocator.operandNumber(move.getInput()), move.getInput(),
+                                                    allocator.operandNumber(move.getResult()), move.getResult(), block);
+                                }
+
+                                // null-instructions are deleted by assignRegNum
+                                instructions.set(j, null);
+                            }
+
+                        } else {
+                            /*
+                             * Insert move from register to stack just after the beginning of the
+                             * interval.
+                             */
+                            assert interval == Interval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order";
+                            assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval";
+
+                            while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) {
+                                if (!interval.canMaterialize()) {
+                                    if (!insertionBuffer.initialized()) {
+                                        /*
+                                         * prepare insertion buffer (appended when all instructions
+                                         * in the block are processed)
+                                         */
+                                        insertionBuffer.init(instructions);
+                                    }
+
+                                    AllocatableValue fromLocation = interval.location();
+                                    AllocatableValue toLocation = LinearScan.canonicalSpillOpr(interval);
+                                    if (!fromLocation.equals(toLocation)) {
+
+                                        assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" +
+                                                        interval.spillState();
+                                        assert isStackSlotValue(toLocation) : "to operand must be a stack slot";
+
+                                        LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
+                                        insertionBuffer.append(j + 1, move);
+
+                                        if (Debug.isLogEnabled()) {
+                                            Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
+                                        }
+                                    }
+                                }
+                                interval = interval.next;
+                            }
+                        }
+                    } // end of instruction iteration
+
+                    if (insertionBuffer.initialized()) {
+                        insertionBuffer.finish();
+                    }
+                }
+            } // end of block iteration
+
+            assert interval == Interval.EndMarker : "missed an interval";
+        }
+    }
+
+    /**
+     * @param block The block {@code move} is located in.
+     * @param move Spill move.
+     */
+    protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) {
+        assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables: " + move;
+
+        Interval curInterval = allocator.intervalFor(move.getResult());
+
+        if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) {
+            assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location();
+            return true;
+        }
+        return false;
+    }
+
+    private static void checkIntervals(Interval interval) {
+        Interval prev = null;
+        Interval temp = interval;
+        while (temp != Interval.EndMarker) {
+            assert temp.spillDefinitionPos() > 0 : "invalid spill definition pos";
+            if (prev != null) {
+                assert temp.from() >= prev.from() : "intervals not sorted";
+                assert temp.spillDefinitionPos() >= prev.spillDefinitionPos() : "when intervals are sorted by from :  then they must also be sorted by spillDefinitionPos";
+            }
+
+            assert temp.spillSlot() != null || temp.canMaterialize() : "interval has no spill slot assigned";
+            assert temp.spillDefinitionPos() >= temp.from() : "invalid order";
+            assert temp.spillDefinitionPos() <= temp.from() + 2 : "only intervals defined once at their start-pos can be optimized";
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos());
+            }
+
+            prev = temp;
+            temp = temp.next;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,830 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
+import static com.oracle.graal.lir.debug.LIRGenerationDebugContext.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.compiler.common.util.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority;
+import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
+import com.oracle.graal.lir.alloc.lsra.LinearScan.BlockData;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.phases.*;
+
+class LinearScanLifetimeAnalysisPhase extends AllocationPhase {
+
+    protected final LinearScan allocator;
+
+    /**
+     * @param linearScan
+     */
+    LinearScanLifetimeAnalysisPhase(LinearScan linearScan) {
+        allocator = linearScan;
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        numberInstructions();
+        allocator.printLir("Before register allocation", true);
+        computeLocalLiveSets();
+        computeGlobalLiveSets();
+        buildIntervals();
+    }
+
+    /**
+     * Bit set for each variable that is contained in each loop.
+     */
+    BitMap2D intervalInLoop;
+
+    boolean isIntervalInLoop(int interval, int loop) {
+        return intervalInLoop.at(interval, loop);
+    }
+
+    /**
+     * Numbers all instructions in all blocks. The numbering follows the
+     * {@linkplain ComputeBlockOrder linear scan order}.
+     */
+    void numberInstructions() {
+
+        allocator.initIntervals();
+
+        ValueConsumer setVariableConsumer = (value, mode, flags) -> {
+            if (isVariable(value)) {
+                allocator.getOrCreateInterval(asVariable(value));
+            }
+        };
+
+        // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node.
+        int numInstructions = 0;
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+            numInstructions += allocator.ir.getLIRforBlock(block).size();
+        }
+
+        // initialize with correct length
+        allocator.initOpIdMaps(numInstructions);
+
+        int opId = 0;
+        int index = 0;
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+            allocator.initBlockData(block);
+
+            List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block);
+
+            int numInst = instructions.size();
+            for (int j = 0; j < numInst; j++) {
+                LIRInstruction op = instructions.get(j);
+                op.setId(opId);
+
+                allocator.putOpIdMaps(index, op, block);
+                assert allocator.instructionForId(opId) == op : "must match";
+
+                op.visitEachTemp(setVariableConsumer);
+                op.visitEachOutput(setVariableConsumer);
+
+                index++;
+                opId += 2; // numbering of lirOps by two
+            }
+        }
+        assert index == numInstructions : "must match";
+        assert (index << 1) == opId : "must match: " + (index << 1);
+    }
+
+    /**
+     * Computes local live sets (i.e. {@link BlockData#liveGen} and {@link BlockData#liveKill})
+     * separately for each block.
+     */
+    void computeLocalLiveSets() {
+        int liveSize = allocator.liveSetSize();
+
+        intervalInLoop = new BitMap2D(allocator.operandSize(), allocator.numLoops());
+
+        // iterate all blocks
+        for (final AbstractBlockBase<?> block : allocator.sortedBlocks) {
+            try (Indent indent = Debug.logAndIndent("compute local live sets for block %s", block)) {
+
+                final BitSet liveGen = new BitSet(liveSize);
+                final BitSet liveKill = new BitSet(liveSize);
+
+                List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block);
+                int numInst = instructions.size();
+
+                ValueConsumer useConsumer = (operand, mode, flags) -> {
+                    if (isVariable(operand)) {
+                        int operandNum = allocator.operandNumber(operand);
+                        if (!liveKill.get(operandNum)) {
+                            liveGen.set(operandNum);
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("liveGen for operand %d(%s)", operandNum, operand);
+                            }
+                        }
+                        if (block.getLoop() != null) {
+                            intervalInLoop.setBit(operandNum, block.getLoop().getIndex());
+                        }
+                    }
+
+                    if (DetailedAsserts.getValue()) {
+                        verifyInput(block, liveKill, operand);
+                    }
+                };
+                ValueConsumer stateConsumer = (operand, mode, flags) -> {
+                    if (LinearScan.isVariableOrRegister(operand)) {
+                        int operandNum = allocator.operandNumber(operand);
+                        if (!liveKill.get(operandNum)) {
+                            liveGen.set(operandNum);
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("liveGen in state for operand %d(%s)", operandNum, operand);
+                            }
+                        }
+                    }
+                };
+                ValueConsumer defConsumer = (operand, mode, flags) -> {
+                    if (isVariable(operand)) {
+                        int varNum = allocator.operandNumber(operand);
+                        liveKill.set(varNum);
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("liveKill for operand %d(%s)", varNum, operand);
+                        }
+                        if (block.getLoop() != null) {
+                            intervalInLoop.setBit(varNum, block.getLoop().getIndex());
+                        }
+                    }
+
+                    if (DetailedAsserts.getValue()) {
+                        /*
+                         * Fixed intervals are never live at block boundaries, so they need not be
+                         * processed in live sets. Process them only in debug mode so that this can
+                         * be checked
+                         */
+                        verifyTemp(liveKill, operand);
+                    }
+                };
+
+                // iterate all instructions of the block
+                for (int j = 0; j < numInst; j++) {
+                    final LIRInstruction op = instructions.get(j);
+
+                    try (Indent indent2 = Debug.logAndIndent("handle op %d", op.id())) {
+                        op.visitEachInput(useConsumer);
+                        op.visitEachAlive(useConsumer);
+                        /*
+                         * Add uses of live locals from interpreter's point of view for proper debug
+                         * information generation.
+                         */
+                        op.visitEachState(stateConsumer);
+                        op.visitEachTemp(defConsumer);
+                        op.visitEachOutput(defConsumer);
+                    }
+                } // end of instruction iteration
+
+                BlockData blockSets = allocator.getBlockData(block);
+                blockSets.liveGen = liveGen;
+                blockSets.liveKill = liveKill;
+                blockSets.liveIn = new BitSet(liveSize);
+                blockSets.liveOut = new BitSet(liveSize);
+
+                if (Debug.isLogEnabled()) {
+                    Debug.log("liveGen  B%d %s", block.getId(), blockSets.liveGen);
+                    Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill);
+                }
+
+            }
+        } // end of block iteration
+    }
+
+    private void verifyTemp(BitSet liveKill, Value operand) {
+        /*
+         * Fixed intervals are never live at block boundaries, so they need not be processed in live
+         * sets. Process them only in debug mode so that this can be checked
+         */
+        if (isRegister(operand)) {
+            if (allocator.isProcessed(operand)) {
+                liveKill.set(allocator.operandNumber(operand));
+            }
+        }
+    }
+
+    private void verifyInput(AbstractBlockBase<?> block, BitSet liveKill, Value operand) {
+        /*
+         * Fixed intervals are never live at block boundaries, so they need not be processed in live
+         * sets. This is checked by these assertions to be sure about it. The entry block may have
+         * incoming values in registers, which is ok.
+         */
+        if (isRegister(operand) && block != allocator.ir.getControlFlowGraph().getStartBlock()) {
+            if (allocator.isProcessed(operand)) {
+                assert liveKill.get(allocator.operandNumber(operand)) : "using fixed register that is not defined in this block";
+            }
+        }
+    }
+
+    /**
+     * Performs a backward dataflow analysis to compute global live sets (i.e.
+     * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block.
+     */
+    void computeGlobalLiveSets() {
+        try (Indent indent = Debug.logAndIndent("compute global live sets")) {
+            int numBlocks = allocator.blockCount();
+            boolean changeOccurred;
+            boolean changeOccurredInBlock;
+            int iterationCount = 0;
+            BitSet liveOut = new BitSet(allocator.liveSetSize()); // scratch set for calculations
+
+            /*
+             * Perform a backward dataflow analysis to compute liveOut and liveIn for each block.
+             * The loop is executed until a fixpoint is reached (no changes in an iteration).
+             */
+            do {
+                changeOccurred = false;
+
+                try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) {
+
+                    // iterate all blocks in reverse order
+                    for (int i = numBlocks - 1; i >= 0; i--) {
+                        AbstractBlockBase<?> block = allocator.blockAt(i);
+                        BlockData blockSets = allocator.getBlockData(block);
+
+                        changeOccurredInBlock = false;
+
+                        /* liveOut(block) is the union of liveIn(sux), for successors sux of block. */
+                        int n = block.getSuccessorCount();
+                        if (n > 0) {
+                            liveOut.clear();
+                            // block has successors
+                            if (n > 0) {
+                                for (AbstractBlockBase<?> successor : block.getSuccessors()) {
+                                    liveOut.or(allocator.getBlockData(successor).liveIn);
+                                }
+                            }
+
+                            if (!blockSets.liveOut.equals(liveOut)) {
+                                /*
+                                 * A change occurred. Swap the old and new live out sets to avoid
+                                 * copying.
+                                 */
+                                BitSet temp = blockSets.liveOut;
+                                blockSets.liveOut = liveOut;
+                                liveOut = temp;
+
+                                changeOccurred = true;
+                                changeOccurredInBlock = true;
+                            }
+                        }
+
+                        if (iterationCount == 0 || changeOccurredInBlock) {
+                            /*
+                             * liveIn(block) is the union of liveGen(block) with (liveOut(block) &
+                             * !liveKill(block)).
+                             * 
+                             * Note: liveIn has to be computed only in first iteration or if liveOut
+                             * has changed!
+                             */
+                            BitSet liveIn = blockSets.liveIn;
+                            liveIn.clear();
+                            liveIn.or(blockSets.liveOut);
+                            liveIn.andNot(blockSets.liveKill);
+                            liveIn.or(blockSets.liveGen);
+
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("block %d: livein = %s,  liveout = %s", block.getId(), liveIn, blockSets.liveOut);
+                            }
+                        }
+                    }
+                    iterationCount++;
+
+                    if (changeOccurred && iterationCount > 50) {
+                        throw new BailoutException("too many iterations in computeGlobalLiveSets");
+                    }
+                }
+            } while (changeOccurred);
+
+            if (DetailedAsserts.getValue()) {
+                verifyLiveness();
+            }
+
+            // check that the liveIn set of the first block is empty
+            AbstractBlockBase<?> startBlock = allocator.ir.getControlFlowGraph().getStartBlock();
+            if (allocator.getBlockData(startBlock).liveIn.cardinality() != 0) {
+                if (DetailedAsserts.getValue()) {
+                    reportFailure(numBlocks);
+                }
+                // bailout if this occurs in product mode.
+                throw new GraalInternalError("liveIn set of first block must be empty: " + allocator.getBlockData(startBlock).liveIn);
+            }
+        }
+    }
+
+    private void reportFailure(int numBlocks) {
+        try (Scope s = Debug.forceLog()) {
+            try (Indent indent = Debug.logAndIndent("report failure")) {
+
+                BitSet startBlockLiveIn = allocator.getBlockData(allocator.ir.getControlFlowGraph().getStartBlock()).liveIn;
+                try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) {
+                    for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
+                        Interval interval = allocator.intervalFor(operandNum);
+                        if (interval != null) {
+                            Value operand = interval.operand;
+                            Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getSourceForOperandFromDebugContext(operand));
+                        } else {
+                            Debug.log("var %d; missing operand", operandNum);
+                        }
+                    }
+                }
+
+                // print some additional information to simplify debugging
+                for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
+                    Interval interval = allocator.intervalFor(operandNum);
+                    Value operand = null;
+                    Object valueForOperandFromDebugContext = null;
+                    if (interval != null) {
+                        operand = interval.operand;
+                        valueForOperandFromDebugContext = getSourceForOperandFromDebugContext(operand);
+                    }
+                    try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, valueForOperandFromDebugContext)) {
+
+                        Deque<AbstractBlockBase<?>> definedIn = new ArrayDeque<>();
+                        HashSet<AbstractBlockBase<?>> usedIn = new HashSet<>();
+                        for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+                            if (allocator.getBlockData(block).liveGen.get(operandNum)) {
+                                usedIn.add(block);
+                                try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) {
+                                    for (LIRInstruction ins : allocator.ir.getLIRforBlock(block)) {
+                                        try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) {
+                                            ins.forEachState((liveStateOperand, mode, flags) -> {
+                                                Debug.log("operand=%s", liveStateOperand);
+                                                return liveStateOperand;
+                                            });
+                                        }
+                                    }
+                                }
+                            }
+                            if (allocator.getBlockData(block).liveKill.get(operandNum)) {
+                                definedIn.add(block);
+                                try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) {
+                                    for (LIRInstruction ins : allocator.ir.getLIRforBlock(block)) {
+                                        Debug.log("%d: %s", ins.id(), ins);
+                                    }
+                                }
+                            }
+                        }
+
+                        int[] hitCount = new int[numBlocks];
+
+                        while (!definedIn.isEmpty()) {
+                            AbstractBlockBase<?> block = definedIn.removeFirst();
+                            usedIn.remove(block);
+                            for (AbstractBlockBase<?> successor : block.getSuccessors()) {
+                                if (successor.isLoopHeader()) {
+                                    if (!block.isLoopEnd()) {
+                                        definedIn.add(successor);
+                                    }
+                                } else {
+                                    if (++hitCount[successor.getId()] == successor.getPredecessorCount()) {
+                                        definedIn.add(successor);
+                                    }
+                                }
+                            }
+                        }
+                        try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) {
+                            for (AbstractBlockBase<?> block : usedIn) {
+                                Debug.log("B%d", block.getId());
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private void verifyLiveness() {
+        /*
+         * Check that fixed intervals are not live at block boundaries (live set must be empty at
+         * fixed intervals).
+         */
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+            for (int j = 0; j <= allocator.maxRegisterNumber(); j++) {
+                assert !allocator.getBlockData(block).liveIn.get(j) : "liveIn  set of fixed register must be empty";
+                assert !allocator.getBlockData(block).liveOut.get(j) : "liveOut set of fixed register must be empty";
+                assert !allocator.getBlockData(block).liveGen.get(j) : "liveGen set of fixed register must be empty";
+            }
+        }
+    }
+
+    void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
+        if (!allocator.isProcessed(operand)) {
+            return;
+        }
+
+        Interval interval = allocator.getOrCreateInterval(operand);
+        if (!kind.equals(LIRKind.Illegal)) {
+            interval.setKind(kind);
+        }
+
+        interval.addRange(from, to);
+
+        // Register use position at even instruction id.
+        interval.addUsePos(to & ~1, registerPriority);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("add use: %s, from %d to %d (%s)", interval, from, to, registerPriority.name());
+        }
+    }
+
+    void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
+        if (!allocator.isProcessed(operand)) {
+            return;
+        }
+
+        Interval interval = allocator.getOrCreateInterval(operand);
+        if (!kind.equals(LIRKind.Illegal)) {
+            interval.setKind(kind);
+        }
+
+        interval.addRange(tempPos, tempPos + 1);
+        interval.addUsePos(tempPos, registerPriority);
+        interval.addMaterializationValue(null);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
+        }
+    }
+
+    void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
+        if (!allocator.isProcessed(operand)) {
+            return;
+        }
+        int defPos = op.id();
+
+        Interval interval = allocator.getOrCreateInterval(operand);
+        if (!kind.equals(LIRKind.Illegal)) {
+            interval.setKind(kind);
+        }
+
+        Range r = interval.first();
+        if (r.from <= defPos) {
+            /*
+             * Update the starting point (when a range is first created for a use, its start is the
+             * beginning of the current block until a def is encountered).
+             */
+            r.from = defPos;
+            interval.addUsePos(defPos, registerPriority);
+
+        } else {
+            /*
+             * Dead value - make vacuous interval also add register priority for dead intervals
+             */
+            interval.addRange(defPos, defPos + 1);
+            interval.addUsePos(defPos, registerPriority);
+            if (Debug.isLogEnabled()) {
+                Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
+            }
+        }
+
+        changeSpillDefinitionPos(interval, defPos);
+        if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) {
+            // detection of method-parameters and roundfp-results
+            interval.setSpillState(SpillState.StartInMemory);
+        }
+        interval.addMaterializationValue(getMaterializedValue(op, operand, interval));
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
+        }
+    }
+
+    /**
+     * Optimizes moves related to incoming stack based arguments. The interval for the destination
+     * of such moves is assigned the stack slot (which is in the caller's frame) as its spill slot.
+     */
+    void handleMethodArguments(LIRInstruction op) {
+        if (op instanceof MoveOp) {
+            MoveOp move = (MoveOp) op;
+            if (optimizeMethodArgument(move.getInput())) {
+                StackSlot slot = asStackSlot(move.getInput());
+                if (DetailedAsserts.getValue()) {
+                    assert op.id() > 0 : "invalid id";
+                    assert allocator.blockForId(op.id()).getPredecessorCount() == 0 : "move from stack must be in first block";
+                    assert isVariable(move.getResult()) : "result of move must be a variable";
+
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("found move from stack slot %s to %s", slot, move.getResult());
+                    }
+                }
+
+                Interval interval = allocator.intervalFor(move.getResult());
+                interval.setSpillSlot(slot);
+                interval.assignLocation(slot);
+            }
+        }
+    }
+
+    void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
+        if (flags.contains(OperandFlag.HINT) && LinearScan.isVariableOrRegister(targetValue)) {
+
+            op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> {
+                if (LinearScan.isVariableOrRegister(registerHint)) {
+                    Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint);
+                    Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue);
+
+                    /* hints always point from def to use */
+                    if (hintAtDef) {
+                        to.setLocationHint(from);
+                    } else {
+                        from.setLocationHint(to);
+                    }
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber);
+                    }
+
+                    return registerHint;
+                }
+                return null;
+            });
+        }
+    }
+
+    /**
+     * Eliminates moves from register to stack if the stack slot is known to be correct.
+     */
+    void changeSpillDefinitionPos(Interval interval, int defPos) {
+        assert interval.isSplitParent() : "can only be called for split parents";
+
+        switch (interval.spillState()) {
+            case NoDefinitionFound:
+                assert interval.spillDefinitionPos() == -1 : "must no be set before";
+                interval.setSpillDefinitionPos(defPos);
+                interval.setSpillState(SpillState.NoSpillStore);
+                break;
+
+            case NoSpillStore:
+                assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created";
+                if (defPos < interval.spillDefinitionPos() - 2) {
+                    // second definition found, so no spill optimization possible for this interval
+                    interval.setSpillState(SpillState.NoOptimization);
+                } else {
+                    // two consecutive definitions (because of two-operand LIR form)
+                    assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal";
+                }
+                break;
+
+            case NoOptimization:
+                // nothing to do
+                break;
+
+            default:
+                throw new BailoutException("other states not allowed at this time");
+        }
+    }
+
+    private static boolean optimizeMethodArgument(Value value) {
+        /*
+         * Object method arguments that are passed on the stack are currently not optimized because
+         * this requires that the runtime visits method arguments during stack walking.
+         */
+        return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && value.getKind() != Kind.Object;
+    }
+
+    /**
+     * Determines the register priority for an instruction's output/result operand.
+     */
+    private static RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
+        if (op instanceof MoveOp) {
+            MoveOp move = (MoveOp) op;
+            if (optimizeMethodArgument(move.getInput())) {
+                return RegisterPriority.None;
+            }
+        } else if (op instanceof LabelOp) {
+            LabelOp label = (LabelOp) op;
+            if (label.isPhiIn()) {
+                return RegisterPriority.None;
+            }
+        }
+
+        // all other operands require a register
+        return RegisterPriority.MustHaveRegister;
+    }
+
+    /**
+     * Determines the priority which with an instruction's input operand will be allocated a
+     * register.
+     */
+    private static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
+        if (flags.contains(OperandFlag.STACK)) {
+            return RegisterPriority.ShouldHaveRegister;
+        }
+        // all other operands require a register
+        return RegisterPriority.MustHaveRegister;
+    }
+
+    void buildIntervals() {
+
+        try (Indent indent = Debug.logAndIndent("build intervals")) {
+            InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, true);
+                }
+            };
+
+            InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            };
+
+            InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    RegisterPriority p = registerPriorityOfInputOperand(flags);
+                    int opId = op.id();
+                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                    addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            };
+
+            InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    int opId = op.id();
+                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                    RegisterPriority p = registerPriorityOfInputOperand(flags);
+                    addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            };
+
+            InstructionValueConsumer stateProc = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    int opId = op.id();
+                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                    addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind());
+                }
+            };
+
+            // create a list with all caller-save registers (cpu, fpu, xmm)
+            Register[] callerSaveRegs = allocator.regAllocConfig.getRegisterConfig().getCallerSaveRegisters();
+
+            // iterate all blocks in reverse order
+            for (int i = allocator.blockCount() - 1; i >= 0; i--) {
+
+                AbstractBlockBase<?> block = allocator.blockAt(i);
+                try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
+
+                    List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block);
+                    final int blockFrom = allocator.getFirstLirInstructionId(block);
+                    int blockTo = allocator.getLastLirInstructionId(block);
+
+                    assert blockFrom == instructions.get(0).id();
+                    assert blockTo == instructions.get(instructions.size() - 1).id();
+
+                    // Update intervals for operands live at the end of this block;
+                    BitSet live = allocator.getBlockData(block).liveOut;
+                    for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) {
+                        assert live.get(operandNum) : "should not stop here otherwise";
+                        AllocatableValue operand = allocator.intervalFor(operandNum).operand;
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("live in %d: %s", operandNum, operand);
+                        }
+
+                        addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, LIRKind.Illegal);
+
+                        /*
+                         * Add special use positions for loop-end blocks when the interval is used
+                         * anywhere inside this loop. It's possible that the block was part of a
+                         * non-natural loop, so it might have an invalid loop index.
+                         */
+                        if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().getIndex())) {
+                            allocator.intervalFor(operandNum).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd);
+                        }
+                    }
+
+                    /*
+                     * Iterate all instructions of the block in reverse order. definitions of
+                     * intervals are processed before uses.
+                     */
+                    for (int j = instructions.size() - 1; j >= 0; j--) {
+                        final LIRInstruction op = instructions.get(j);
+                        final int opId = op.id();
+
+                        try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) {
+
+                            // add a temp range for each register if operation destroys
+                            // caller-save registers
+                            if (op.destroysCallerSavedRegisters()) {
+                                for (Register r : callerSaveRegs) {
+                                    if (allocator.attributes(r).isAllocatable()) {
+                                        addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal);
+                                    }
+                                }
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("operation destroys all caller-save registers");
+                                }
+                            }
+
+                            op.visitEachOutput(outputConsumer);
+                            op.visitEachTemp(tempConsumer);
+                            op.visitEachAlive(aliveConsumer);
+                            op.visitEachInput(inputConsumer);
+
+                            /*
+                             * Add uses of live locals from interpreter's point of view for proper
+                             * debug information generation. Treat these operands as temp values (if
+                             * the live range is extended to a call site, the value would be in a
+                             * register at the call otherwise).
+                             */
+                            op.visitEachState(stateProc);
+
+                            // special steps for some instructions (especially moves)
+                            handleMethodArguments(op);
+
+                        }
+
+                    } // end of instruction iteration
+                }
+            } // end of block iteration
+
+            /*
+             * Add the range [0, 1] to all fixed intervals. the register allocator need not handle
+             * unhandled fixed intervals.
+             */
+            for (Interval interval : allocator.intervals()) {
+                if (interval != null && isRegister(interval.operand)) {
+                    interval.addRange(0, 1);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a value for a interval definition, which can be used for re-materialization.
+     *
+     * @param op An instruction which defines a value
+     * @param operand The destination operand of the instruction
+     * @param interval The interval for this defined value.
+     * @return Returns the value which is moved to the instruction and which can be reused at all
+     *         reload-locations in case the interval of this instruction is spilled. Currently this
+     *         can only be a {@link JavaConstant}.
+     */
+    static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) {
+        if (op instanceof MoveOp) {
+            MoveOp move = (MoveOp) op;
+            if (move.getInput() instanceof JavaConstant) {
+                /*
+                 * Check if the interval has any uses which would accept an stack location (priority
+                 * == ShouldHaveRegister). Rematerialization of such intervals can result in a
+                 * degradation, because rematerialization always inserts a constant load, even if
+                 * the value is not needed in a register.
+                 */
+                Interval.UsePosList usePosList = interval.usePosList();
+                int numUsePos = usePosList.size();
+                for (int useIdx = 0; useIdx < numUsePos; useIdx++) {
+                    Interval.RegisterPriority priority = usePosList.registerPriority(useIdx);
+                    if (priority == Interval.RegisterPriority.ShouldHaveRegister) {
+                        return null;
+                    }
+                }
+                return (JavaConstant) move.getInput();
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.compiler.common.cfg.AbstractControlFlowGraph.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.phases.*;
+
+final class LinearScanOptimizeSpillPositionPhase extends AllocationPhase {
+
+    private static final DebugMetric betterSpillPos = Debug.metric("BetterSpillPosition");
+    private static final DebugMetric betterSpillPosWithLowerProbability = Debug.metric("BetterSpillPositionWithLowerProbability");
+
+    private final LinearScan allocator;
+
+    LinearScanOptimizeSpillPositionPhase(LinearScan allocator) {
+        this.allocator = allocator;
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        optimizeSpillPosition();
+        allocator.printIntervals("After optimize spill position");
+    }
+
+    private void optimizeSpillPosition() {
+        LIRInsertionBuffer[] insertionBuffers = new LIRInsertionBuffer[allocator.ir.linearScanOrder().size()];
+        for (Interval interval : allocator.intervals()) {
+            if (interval != null && interval.isSplitParent() && interval.spillState() == SpillState.SpillInDominator) {
+                AbstractBlockBase<?> defBlock = allocator.blockForId(interval.spillDefinitionPos());
+                AbstractBlockBase<?> spillBlock = null;
+                Interval firstSpillChild = null;
+                try (Indent indent = Debug.logAndIndent("interval %s (%s)", interval, defBlock)) {
+                    for (Interval splitChild : interval.getSplitChildren()) {
+                        if (isStackSlotValue(splitChild.location())) {
+                            if (firstSpillChild == null || splitChild.from() < firstSpillChild.from()) {
+                                firstSpillChild = splitChild;
+                            } else {
+                                assert firstSpillChild.from() < splitChild.from();
+                            }
+                            // iterate all blocks where the interval has use positions
+                            for (AbstractBlockBase<?> splitBlock : blocksForInterval(splitChild)) {
+                                if (dominates(defBlock, splitBlock)) {
+                                    if (Debug.isLogEnabled()) {
+                                        Debug.log("Split interval %s, block %s", splitChild, splitBlock);
+                                    }
+                                    if (spillBlock == null) {
+                                        spillBlock = splitBlock;
+                                    } else {
+                                        spillBlock = commonDominator(spillBlock, splitBlock);
+                                        assert spillBlock != null;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    if (spillBlock == null) {
+                        // no spill interval
+                        interval.setSpillState(SpillState.StoreAtDefinition);
+                    } else {
+                        // move out of loops
+                        if (defBlock.getLoopDepth() < spillBlock.getLoopDepth()) {
+                            spillBlock = moveSpillOutOfLoop(defBlock, spillBlock);
+                        }
+
+                        /*
+                         * If the spill block is the begin of the first split child (aka the value
+                         * is on the stack) spill in the dominator.
+                         */
+                        assert firstSpillChild != null;
+                        if (!defBlock.equals(spillBlock) && spillBlock.equals(allocator.blockForId(firstSpillChild.from()))) {
+                            AbstractBlockBase<?> dom = spillBlock.getDominator();
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("Spill block (%s) is the beginning of a spill child -> use dominator (%s)", spillBlock, dom);
+                            }
+                            spillBlock = dom;
+                        }
+
+                        if (!defBlock.equals(spillBlock)) {
+                            assert dominates(defBlock, spillBlock);
+                            betterSpillPos.increment();
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("Better spill position found (Block %s)", spillBlock);
+                            }
+
+                            if (defBlock.probability() <= spillBlock.probability()) {
+                                // better spill block has the same probability -> do nothing
+                                interval.setSpillState(SpillState.StoreAtDefinition);
+                            } else {
+                                LIRInsertionBuffer insertionBuffer = insertionBuffers[spillBlock.getId()];
+                                if (insertionBuffer == null) {
+                                    insertionBuffer = new LIRInsertionBuffer();
+                                    insertionBuffers[spillBlock.getId()] = insertionBuffer;
+                                    insertionBuffer.init(allocator.ir.getLIRforBlock(spillBlock));
+                                }
+                                int spillOpId = allocator.getFirstLirInstructionId(spillBlock);
+                                // insert spill move
+                                AllocatableValue fromLocation = interval.getSplitChildAtOpId(spillOpId, OperandMode.DEF, allocator).location();
+                                AllocatableValue toLocation = LinearScan.canonicalSpillOpr(interval);
+                                LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
+                                move.setId(LinearScan.DOMINATOR_SPILL_MOVE_ID);
+                                /*
+                                 * We can use the insertion buffer directly because we always insert
+                                 * at position 1.
+                                 */
+                                insertionBuffer.append(1, move);
+
+                                betterSpillPosWithLowerProbability.increment();
+                                interval.setSpillDefinitionPos(spillOpId);
+                            }
+                        } else {
+                            // definition is the best choice
+                            interval.setSpillState(SpillState.StoreAtDefinition);
+                        }
+                    }
+                }
+            }
+        }
+        for (LIRInsertionBuffer insertionBuffer : insertionBuffers) {
+            if (insertionBuffer != null) {
+                assert insertionBuffer.initialized() : "Insertion buffer is nonnull but not initialized!";
+                insertionBuffer.finish();
+            }
+        }
+    }
+
+    /**
+     * Iterate over all {@link AbstractBlockBase blocks} of an interval.
+     */
+    private class IntervalBlockIterator implements Iterator<AbstractBlockBase<?>> {
+
+        Range range;
+        AbstractBlockBase<?> block;
+
+        public IntervalBlockIterator(Interval interval) {
+            range = interval.first();
+            block = allocator.blockForId(range.from);
+        }
+
+        public AbstractBlockBase<?> next() {
+            AbstractBlockBase<?> currentBlock = block;
+            int nextBlockIndex = block.getLinearScanNumber() + 1;
+            if (nextBlockIndex < allocator.sortedBlocks.size()) {
+                block = allocator.sortedBlocks.get(nextBlockIndex);
+                if (range.to <= allocator.getFirstLirInstructionId(block)) {
+                    range = range.next;
+                    if (range == Range.EndMarker) {
+                        block = null;
+                    } else {
+                        block = allocator.blockForId(range.from);
+                    }
+                }
+            } else {
+                block = null;
+            }
+            return currentBlock;
+        }
+
+        public boolean hasNext() {
+            return block != null;
+        }
+    }
+
+    private Iterable<AbstractBlockBase<?>> blocksForInterval(Interval interval) {
+        return new Iterable<AbstractBlockBase<?>>() {
+            public Iterator<AbstractBlockBase<?>> iterator() {
+                return new IntervalBlockIterator(interval);
+            }
+        };
+    }
+
+    private static AbstractBlockBase<?> moveSpillOutOfLoop(AbstractBlockBase<?> defBlock, AbstractBlockBase<?> spillBlock) {
+        int defLoopDepth = defBlock.getLoopDepth();
+        for (AbstractBlockBase<?> block = spillBlock.getDominator(); !defBlock.equals(block); block = block.getDominator()) {
+            assert block != null : "spill block not dominated by definition block?";
+            if (block.getLoopDepth() <= defLoopDepth) {
+                assert block.getLoopDepth() == defLoopDepth : "Cannot spill an interval outside of the loop where it is defined!";
+                return block;
+            }
+        }
+        return defBlock;
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -48,12 +48,15 @@
     });
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        final LinearScan allocator;
         if (LinearScanPhase.SSA_LSRA.getValue()) {
-            new SSALinearScan(target, lirGenRes, spillMoveFactory, new RegisterAllocationConfig(lirGenRes.getFrameMapBuilder().getRegisterConfig())).allocate();
+            allocator = new SSALinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig);
         } else {
-            new LinearScan(target, lirGenRes, spillMoveFactory, new RegisterAllocationConfig(lirGenRes.getFrameMapBuilder().getRegisterConfig())).allocate();
+            allocator = new LinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig);
         }
+        allocator.allocate(target, lirGenRes, codeEmittingOrder, linearScanOrder, spillMoveFactory, registerAllocationConfig);
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.*;
+import com.oracle.graal.lir.phases.*;
+
+final class LinearScanRegisterAllocationPhase extends AllocationPhase {
+
+    private final LinearScan allocator;
+
+    LinearScanRegisterAllocationPhase(LinearScan allocator) {
+        this.allocator = allocator;
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        allocator.printIntervals("Before register allocation");
+        allocateRegisters();
+        allocator.printIntervals("After register allocation");
+    }
+
+    void allocateRegisters() {
+        try (Indent indent = Debug.logAndIndent("allocate registers")) {
+            Interval precoloredIntervals;
+            Interval notPrecoloredIntervals;
+
+            Interval.Pair result = allocator.createUnhandledLists(LinearScan.IS_PRECOLORED_INTERVAL, LinearScan.IS_VARIABLE_INTERVAL);
+            precoloredIntervals = result.first;
+            notPrecoloredIntervals = result.second;
+
+            // allocate cpu registers
+            LinearScanWalker lsw;
+            if (OptimizingLinearScanWalker.Options.LSRAOptimization.getValue()) {
+                lsw = new OptimizingLinearScanWalker(allocator, precoloredIntervals, notPrecoloredIntervals);
+            } else {
+                lsw = new LinearScanWalker(allocator, precoloredIntervals, notPrecoloredIntervals);
+            }
+            lsw.walk();
+            lsw.finishAllocation();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.alloc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
+import com.oracle.graal.lir.phases.*;
+
+/**
+ * Phase 6: resolve data flow
+ *
+ * Insert moves at edges between blocks if intervals have been split.
+ */
+class LinearScanResolveDataFlowPhase extends AllocationPhase {
+
+    protected final LinearScan allocator;
+
+    LinearScanResolveDataFlowPhase(LinearScan allocator) {
+        this.allocator = allocator;
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        resolveDataFlow();
+    }
+
+    void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
+        assert moveResolver.checkEmpty();
+        assert midBlock == null ||
+                        (midBlock.getPredecessorCount() == 1 && midBlock.getSuccessorCount() == 1 && midBlock.getPredecessors().get(0).equals(fromBlock) && midBlock.getSuccessors().get(0).equals(
+                                        toBlock));
+
+        int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock);
+        int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1;
+        int numOperands = allocator.operandSize();
+        BitSet liveAtEdge = allocator.getBlockData(toBlock).liveIn;
+
+        // visit all variables for which the liveAtEdge bit is set
+        for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) {
+            assert operandNum < numOperands : "live information set for not exisiting interval";
+            assert allocator.getBlockData(fromBlock).liveOut.get(operandNum) && allocator.getBlockData(toBlock).liveIn.get(operandNum) : "interval not live at this edge";
+
+            Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(operandNum), fromBlockLastInstructionId, LIRInstruction.OperandMode.DEF);
+            Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(operandNum), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
+
+            if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
+                // need to insert move instruction
+                moveResolver.addMapping(fromInterval, toInterval);
+            }
+        }
+    }
+
+    void resolveFindInsertPos(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, MoveResolver moveResolver) {
+        if (fromBlock.getSuccessorCount() <= 1) {
+            if (Debug.isLogEnabled()) {
+                Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
+            }
+
+            List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(fromBlock);
+            LIRInstruction instr = instructions.get(instructions.size() - 1);
+            if (instr instanceof StandardOp.JumpOp) {
+                // insert moves before branch
+                moveResolver.setInsertPosition(instructions, instructions.size() - 1);
+            } else {
+                moveResolver.setInsertPosition(instructions, instructions.size());
+            }
+
+        } else {
+            if (Debug.isLogEnabled()) {
+                Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
+            }
+
+            if (DetailedAsserts.getValue()) {
+                assert allocator.ir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
+
+                /*
+                 * Because the number of predecessor edges matches the number of successor edges,
+                 * blocks which are reached by switch statements may have be more than one
+                 * predecessor but it will be guaranteed that all predecessors will be the same.
+                 */
+                for (AbstractBlockBase<?> predecessor : toBlock.getPredecessors()) {
+                    assert fromBlock == predecessor : "all critical edges must be broken";
+                }
+            }
+
+            moveResolver.setInsertPosition(allocator.ir.getLIRforBlock(toBlock), 1);
+        }
+    }
+
+    /**
+     * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals that
+     * have been split.
+     */
+    void resolveDataFlow() {
+        try (Indent indent = Debug.logAndIndent("resolve data flow")) {
+
+            int numBlocks = allocator.blockCount();
+            MoveResolver moveResolver = allocator.createMoveResolver();
+            BitSet blockCompleted = new BitSet(numBlocks);
+            BitSet alreadyResolved = new BitSet(numBlocks);
+
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
+
+                // check if block has only one predecessor and only one successor
+                if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) {
+                    List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block);
+                    assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label";
+                    assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump";
+
+                    // check if block is empty (only label and branch)
+                    if (instructions.size() == 2) {
+                        AbstractBlockBase<?> pred = block.getPredecessors().iterator().next();
+                        AbstractBlockBase<?> sux = block.getSuccessors().iterator().next();
+
+                        // prevent optimization of two consecutive blocks
+                        if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) {
+                            if (Debug.isLogEnabled()) {
+                                Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId());
+                            }
+
+                            blockCompleted.set(block.getLinearScanNumber());
+
+                            /*
+                             * Directly resolve between pred and sux (without looking at the empty
+                             * block between).
+                             */
+                            resolveCollectMappings(pred, sux, block, moveResolver);
+                            if (moveResolver.hasMappings()) {
+                                moveResolver.setInsertPosition(instructions, 1);
+                                moveResolver.resolveAndAppendMoves();
+                            }
+                        }
+                    }
+                }
+            }
+
+            for (AbstractBlockBase<?> fromBlock : allocator.sortedBlocks) {
+                if (!blockCompleted.get(fromBlock.getLinearScanNumber())) {
+                    alreadyResolved.clear();
+                    alreadyResolved.or(blockCompleted);
+
+                    for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) {
+
+                        /*
+                         * Check for duplicate edges between the same blocks (can happen with switch
+                         * blocks).
+                         */
+                        if (!alreadyResolved.get(toBlock.getLinearScanNumber())) {
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId());
+                            }
+
+                            alreadyResolved.set(toBlock.getLinearScanNumber());
+
+                            // collect all intervals that have been split between
+                            // fromBlock and toBlock
+                            resolveCollectMappings(fromBlock, toBlock, null, moveResolver);
+                            if (moveResolver.hasMappings()) {
+                                resolveFindInsertPos(fromBlock, toBlock, moveResolver);
+                                moveResolver.resolveAndAppendMoves();
+                            }
+                        }
+                    }
+                }
+            }
+
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java	Thu May 28 17:44:05 2015 +0200
@@ -30,6 +30,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.common.util.*;
 import com.oracle.graal.debug.*;
@@ -50,6 +51,10 @@
 
     private MoveResolver moveResolver; // for ordering spill moves
 
+    private int minReg;
+
+    private int maxReg;
+
     /**
      * Only 10% of the lists in {@link #spillIntervals} are actually used. But when they are used,
      * they can grow quite long. The maximum length observed was 45 (all numbers taken from a
@@ -95,10 +100,22 @@
         }
     }
 
+    int maxRegisterNumber() {
+        return maxReg;
+    }
+
+    int minRegisterNumber() {
+        return minReg;
+    }
+
+    boolean isRegisterInRange(int reg) {
+        return reg >= minRegisterNumber() && reg <= maxRegisterNumber();
+    }
+
     void excludeFromUse(Interval i) {
         Value location = i.location();
         int i1 = asRegister(location).number;
-        if (i1 >= availableRegs[0].number && i1 <= availableRegs[availableRegs.length - 1].number) {
+        if (isRegisterInRange(i1)) {
             usePos[i1] = 0;
         }
     }
@@ -107,7 +124,7 @@
         if (usePos != -1) {
             assert usePos != 0 : "must use excludeFromUse to set usePos to 0";
             int i = asRegister(interval.location()).number;
-            if (i >= availableRegs[0].number && i <= availableRegs[availableRegs.length - 1].number) {
+            if (isRegisterInRange(i)) {
                 if (this.usePos[i] > usePos) {
                     this.usePos[i] = usePos;
                 }
@@ -126,7 +143,7 @@
     void setBlockPos(Interval i, int blockPos) {
         if (blockPos != -1) {
             int reg = asRegister(i.location()).number;
-            if (reg >= availableRegs[0].number && reg <= availableRegs[availableRegs.length - 1].number) {
+            if (isRegisterInRange(reg)) {
                 if (this.blockPos[reg] > blockPos) {
                     this.blockPos[reg] = blockPos;
                 }
@@ -483,7 +500,7 @@
 
                     allocator.assignSpillSlot(interval);
                     handleSpillSlot(interval);
-                    allocator.changeSpillState(interval, minSplitPos);
+                    changeSpillState(interval, minSplitPos);
 
                     // Also kick parent intervals out of register to memory when they have no use
                     // position. This avoids short interval in register surrounded by intervals in
@@ -529,7 +546,7 @@
                     Interval spilledPart = interval.split(optimalSplitPos, allocator);
                     allocator.assignSpillSlot(spilledPart);
                     handleSpillSlot(spilledPart);
-                    allocator.changeSpillState(spilledPart, optimalSplitPos);
+                    changeSpillState(spilledPart, optimalSplitPos);
 
                     if (!allocator.isBlockBegin(optimalSplitPos)) {
                         if (Debug.isLogEnabled()) {
@@ -551,6 +568,59 @@
         }
     }
 
+    // called during register allocation
+    private void changeSpillState(Interval interval, int spillPos) {
+        switch (interval.spillState()) {
+            case NoSpillStore: {
+                int defLoopDepth = allocator.blockForId(interval.spillDefinitionPos()).getLoopDepth();
+                int spillLoopDepth = allocator.blockForId(spillPos).getLoopDepth();
+
+                if (defLoopDepth < spillLoopDepth) {
+                    /*
+                     * The loop depth of the spilling position is higher then the loop depth at the
+                     * definition of the interval. Move write to memory out of loop.
+                     */
+                    if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) {
+                        // find best spill position in dominator the tree
+                        interval.setSpillState(SpillState.SpillInDominator);
+                    } else {
+                        // store at definition of the interval
+                        interval.setSpillState(SpillState.StoreAtDefinition);
+                    }
+                } else {
+                    /*
+                     * The interval is currently spilled only once, so for now there is no reason to
+                     * store the interval at the definition.
+                     */
+                    interval.setSpillState(SpillState.OneSpillStore);
+                }
+                break;
+            }
+
+            case OneSpillStore: {
+                if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) {
+                    // the interval is spilled more then once
+                    interval.setSpillState(SpillState.SpillInDominator);
+                } else {
+                    // It is better to store it to memory at the definition.
+                    interval.setSpillState(SpillState.StoreAtDefinition);
+                }
+                break;
+            }
+
+            case SpillInDominator:
+            case StoreAtDefinition:
+            case StartInMemory:
+            case NoOptimization:
+            case NoDefinitionFound:
+                // nothing to do
+                break;
+
+            default:
+                throw new BailoutException("other states not allowed at this time");
+        }
+    }
+
     /**
      * This is called for every interval that is assigned to a stack slot.
      */
@@ -643,8 +713,7 @@
             Register minFullReg = null;
             Register maxPartialReg = null;
 
-            for (int i = 0; i < availableRegs.length; ++i) {
-                Register availableReg = availableRegs[i];
+            for (Register availableReg : availableRegs) {
                 int number = availableReg.number;
                 if (usePos[number] >= intervalTo) {
                     // this register is free for the full interval
@@ -805,7 +874,10 @@
     }
 
     void initVarsForAlloc(Interval interval) {
-        availableRegs = allocator.regAllocConfig.getAllocatableRegisters(interval.kind().getPlatformKind());
+        AllocatableRegisters allocatableRegisters = allocator.regAllocConfig.getAllocatableRegisters(interval.kind().getPlatformKind());
+        availableRegs = allocatableRegisters.allocatableRegisters;
+        minReg = allocatableRegisters.minRegisterNumber;
+        maxReg = allocatableRegisters.maxRegisterNumber;
     }
 
     static boolean isMove(LIRInstruction op, Interval from, Interval to) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Thu May 28 17:44:05 2015 +0200
@@ -28,6 +28,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.*;
@@ -53,7 +54,8 @@
     }
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
         new Marker<B>(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build();
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Thu May 28 17:44:05 2015 +0200
@@ -198,7 +198,7 @@
 
         Value location = to.location();
         if (mightBeBlocked(location)) {
-            if ((valueBlocked(location) > 1 || (valueBlocked(location) == 1 && !location.equals(fromReg)))) {
+            if ((valueBlocked(location) > 1 || (valueBlocked(location) == 1 && !isMoveToSelf(fromReg, location)))) {
                 return false;
             }
         }
@@ -206,6 +206,18 @@
         return true;
     }
 
+    protected boolean isMoveToSelf(Value from, Value to) {
+        assert to != null;
+        if (to.equals(from)) {
+            return true;
+        }
+        if (from != null && isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) {
+            assert LIRKind.verifyMoveKinds(to.getLIRKind(), from.getLIRKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
+            return true;
+        }
+        return false;
+    }
+
     protected boolean mightBeBlocked(Value location) {
         return isRegister(location);
     }
@@ -226,7 +238,7 @@
 
     private void insertMove(Interval fromInterval, Interval toInterval) {
         assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert fromInterval.kind().equals(toInterval.kind()) : "move between different types";
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : "move between different types";
         assert insertIdx != -1 : "must setup insert position first";
 
         insertionBuffer.append(insertIdx, createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location()));
@@ -247,7 +259,7 @@
     }
 
     private void insertMove(Value fromOpr, Interval toInterval) {
-        assert fromOpr.getLIRKind().equals(toInterval.kind()) : format("move between different types %s %s", fromOpr.getLIRKind(), toInterval.kind());
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromOpr.getLIRKind()) : format("move between different types %s %s", fromOpr.getLIRKind(), toInterval.kind());
         assert insertIdx != -1 : "must setup insert position first";
 
         AllocatableValue toOpr = toInterval.operand;
@@ -409,8 +421,8 @@
         }
 
         assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert fromInterval.kind().equals(toInterval.kind()) || (fromInterval.kind().getPlatformKind().equals(toInterval.kind().getPlatformKind()) && toInterval.kind().isDerivedReference()) : String.format(
-                        "Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(), toInterval.kind(), fromInterval, toInterval);
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(), toInterval.kind(), fromInterval,
+                        toInterval);
         mappingFrom.add(fromInterval);
         mappingFromOpr.add(Value.ILLEGAL);
         mappingTo.add(toInterval);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinarScanResolveDataFlowPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.ssa.*;
+import com.oracle.graal.lir.ssa.SSAUtils.PhiValueVisitor;
+
+class SSALinarScanResolveDataFlowPhase extends LinearScanResolveDataFlowPhase {
+
+    private static final DebugMetric numPhiResolutionMoves = Debug.metric("SSA LSRA[numPhiResolutionMoves]");
+    private static final DebugMetric numStackToStackMoves = Debug.metric("SSA LSRA[numStackToStackMoves]");
+
+    SSALinarScanResolveDataFlowPhase(LinearScan allocator) {
+        super(allocator);
+    }
+
+    @Override
+    void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
+        super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver);
+
+        if (toBlock.getPredecessorCount() > 1) {
+            int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock);
+            int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1;
+
+            AbstractBlockBase<?> phiOutBlock = midBlock != null ? midBlock : fromBlock;
+            List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(phiOutBlock);
+            int phiOutIdx = SSAUtils.phiOutIndex(allocator.ir, phiOutBlock);
+            int phiOutId = midBlock != null ? fromBlockLastInstructionId : instructions.get(phiOutIdx).id();
+            assert phiOutId >= 0;
+
+            PhiValueVisitor visitor = new PhiValueVisitor() {
+
+                public void visit(Value phiIn, Value phiOut) {
+                    assert !isRegister(phiOut) : "phiOut is a register: " + phiOut;
+                    assert !isRegister(phiIn) : "phiIn is a register: " + phiIn;
+                    Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
+                    if (isConstant(phiOut)) {
+                        numPhiResolutionMoves.increment();
+                        moveResolver.addMapping(phiOut, toInterval);
+                    } else {
+                        Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), phiOutId, LIRInstruction.OperandMode.DEF);
+                        if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
+                            numPhiResolutionMoves.increment();
+                            if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) {
+                                moveResolver.addMapping(fromInterval, toInterval);
+                            } else {
+                                numStackToStackMoves.increment();
+                                moveResolver.addMapping(fromInterval, toInterval);
+                            }
+                        }
+                    }
+                }
+            };
+
+            SSAUtils.forEachPhiValuePair(allocator.ir, toBlock, phiOutBlock, visitor);
+            SSAUtils.removePhiOut(allocator.ir, phiOutBlock);
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScan.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScan.java	Thu May 28 17:44:05 2015 +0200
@@ -22,32 +22,17 @@
  */
 package com.oracle.graal.lir.alloc.lsra;
 
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRValueUtil.*;
-
-import java.util.*;
-
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.lir.ssa.*;
-import com.oracle.graal.lir.ssa.SSAUtils.PhiValueVisitor;
 
 final class SSALinearScan extends LinearScan {
 
-    private static final DebugMetric numPhiResolutionMoves = Debug.metric("SSA LSRA[numPhiResolutionMoves]");
-    private static final DebugMetric numStackToStackMoves = Debug.metric("SSA LSRA[numStackToStackMoves]");
-
     SSALinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig) {
         super(target, res, spillMoveFactory, regAllocConfig);
     }
@@ -60,50 +45,18 @@
     }
 
     @Override
-    protected int firstInstructionOfInterest() {
-        // also look at Labels as they define PHI values
-        return 0;
+    protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() {
+        return new SSALinearScanLifetimeAnalysisPhase(this);
     }
 
     @Override
-    void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
-        super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver);
-
-        if (toBlock.getPredecessorCount() > 1) {
-            int toBlockFirstInstructionId = getFirstLirInstructionId(toBlock);
-            int fromBlockLastInstructionId = getLastLirInstructionId(fromBlock) + 1;
-
-            AbstractBlockBase<?> phiOutBlock = midBlock != null ? midBlock : fromBlock;
-            List<LIRInstruction> instructions = ir.getLIRforBlock(phiOutBlock);
-            int phiOutIdx = SSAUtils.phiOutIndex(ir, phiOutBlock);
-            int phiOutId = midBlock != null ? fromBlockLastInstructionId : instructions.get(phiOutIdx).id();
-            assert phiOutId >= 0;
-
-            PhiValueVisitor visitor = new PhiValueVisitor() {
+    protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() {
+        return new SSALinarScanResolveDataFlowPhase(this);
+    }
 
-                public void visit(Value phiIn, Value phiOut) {
-                    Interval toInterval = splitChildAtOpId(intervalFor(phiIn), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
-                    if (isConstant(phiOut)) {
-                        numPhiResolutionMoves.increment();
-                        moveResolver.addMapping(phiOut, toInterval);
-                    } else {
-                        Interval fromInterval = splitChildAtOpId(intervalFor(phiOut), phiOutId, LIRInstruction.OperandMode.DEF);
-                        if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
-                            numPhiResolutionMoves.increment();
-                            if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) {
-                                moveResolver.addMapping(fromInterval, toInterval);
-                            } else {
-                                numStackToStackMoves.increment();
-                                moveResolver.addMapping(fromInterval, toInterval);
-                            }
-                        }
-                    }
-                }
-            };
-
-            SSAUtils.forEachPhiValuePair(ir, toBlock, phiOutBlock, visitor);
-            SSAUtils.removePhiOut(ir, phiOutBlock);
-        }
+    @Override
+    protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() {
+        return new SSALinearScanEliminateSpillMovePhase(this);
     }
 
     @Override
@@ -121,80 +74,4 @@
         }
     }
 
-    @Override
-    protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) {
-        // SSA Linear Scan might introduce moves to stack slots
-        assert isVariable(move.getResult()) || LinearScanPhase.SSA_LSRA.getValue() : "Move should not be produced in a non-SSA compilation: " + move;
-
-        Interval curInterval = intervalFor(move.getResult());
-
-        if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory() && !isPhiResolutionMove(block, move, curInterval)) {
-            assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location();
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
-        super.addRegisterHint(op, targetValue, mode, flags, hintAtDef);
-
-        if (hintAtDef && op instanceof LabelOp) {
-            LabelOp label = (LabelOp) op;
-
-            Interval to = getOrCreateInterval((AllocatableValue) targetValue);
-
-            SSAUtils.forEachPhiRegisterHint(ir, blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> {
-                if (isVariableOrRegister(registerHint)) {
-                    Interval from = getOrCreateInterval((AllocatableValue) registerHint);
-
-                    setHint(op, to, from);
-                    setHint(op, from, to);
-                }
-            });
-        }
-    }
-
-    private static void setHint(final LIRInstruction op, Interval target, Interval source) {
-        Interval currentHint = target.locationHint(false);
-        if (currentHint == null || currentHint.from() > target.from()) {
-            /*
-             * Update hint if there was none or if the hint interval starts after the hinted
-             * interval.
-             */
-            target.setLocationHint(source);
-            if (Debug.isLogEnabled()) {
-                Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), source.operandNumber, target.operandNumber);
-            }
-        }
-    }
-
-    private boolean isPhiResolutionMove(AbstractBlockBase<?> block, MoveOp move, Interval toInterval) {
-        if (!LinearScanPhase.SSA_LSRA.getValue()) {
-            return false;
-        }
-        if (!toInterval.isSplitParent()) {
-            return false;
-        }
-        if ((toInterval.from() & 1) == 1) {
-            // phi intervals start at even positions.
-            return false;
-        }
-        if (block.getSuccessorCount() != 1) {
-            return false;
-        }
-        LIRInstruction op = instructionForId(toInterval.from());
-        if (!(op instanceof LabelOp)) {
-            return false;
-        }
-        AbstractBlockBase<?> intStartBlock = blockForId(toInterval.from());
-        assert ir.getLIRforBlock(intStartBlock).get(0).equals(op);
-        if (!block.getSuccessors().get(0).equals(intStartBlock)) {
-            return false;
-        }
-        try (Indent indet = Debug.indent()) {
-            Debug.log("Is a move (%s) to phi interval %s", move, toInterval);
-        }
-        return true;
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanEliminateSpillMovePhase.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+
+public class SSALinearScanEliminateSpillMovePhase extends LinearScanEliminateSpillMovePhase {
+
+    SSALinearScanEliminateSpillMovePhase(LinearScan allocator) {
+        super(allocator);
+    }
+
+    @Override
+    protected int firstInstructionOfInterest() {
+        // also look at Labels as they define PHI values
+        return 0;
+    }
+
+    @Override
+    protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) {
+        // SSA Linear Scan might introduce moves to stack slots
+        assert isVariable(move.getResult()) || LinearScanPhase.SSA_LSRA.getValue() : "Move should not be produced in a non-SSA compilation: " + move;
+
+        Interval curInterval = allocator.intervalFor(move.getResult());
+
+        if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory() && !isPhiResolutionMove(block, move, curInterval)) {
+            assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location();
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isPhiResolutionMove(AbstractBlockBase<?> block, MoveOp move, Interval toInterval) {
+        if (!LinearScanPhase.SSA_LSRA.getValue()) {
+            return false;
+        }
+        if (!toInterval.isSplitParent()) {
+            return false;
+        }
+        if ((toInterval.from() & 1) == 1) {
+            // phi intervals start at even positions.
+            return false;
+        }
+        if (block.getSuccessorCount() != 1) {
+            return false;
+        }
+        LIRInstruction op = allocator.instructionForId(toInterval.from());
+        if (!(op instanceof LabelOp)) {
+            return false;
+        }
+        AbstractBlockBase<?> intStartBlock = allocator.blockForId(toInterval.from());
+        assert allocator.ir.getLIRforBlock(intStartBlock).get(0).equals(op);
+        if (!block.getSuccessors().get(0).equals(intStartBlock)) {
+            return false;
+        }
+        try (Indent indet = Debug.indent()) {
+            Debug.log("Is a move (%s) to phi interval %s", move, toInterval);
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanLifetimeAnalysisPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.ssa.*;
+
+public class SSALinearScanLifetimeAnalysisPhase extends LinearScanLifetimeAnalysisPhase {
+
+    SSALinearScanLifetimeAnalysisPhase(LinearScan linearScan) {
+        super(linearScan);
+    }
+
+    @Override
+    void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
+        super.addRegisterHint(op, targetValue, mode, flags, hintAtDef);
+
+        if (hintAtDef && op instanceof LabelOp) {
+            LabelOp label = (LabelOp) op;
+
+            Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue);
+
+            SSAUtils.forEachPhiRegisterHint(allocator.ir, allocator.blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> {
+                if (LinearScan.isVariableOrRegister(registerHint)) {
+                    Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint);
+
+                    setHint(op, to, from);
+                    setHint(op, from, to);
+                }
+            });
+        }
+    }
+
+    private static void setHint(final LIRInstruction op, Interval target, Interval source) {
+        Interval currentHint = target.locationHint(false);
+        if (currentHint == null || currentHint.from() > target.from()) {
+            /*
+             * Update hint if there was none or if the hint interval starts after the hinted
+             * interval.
+             */
+            target.setLocationHint(source);
+            if (Debug.isLogEnabled()) {
+                Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), source.operandNumber, target.operandNumber);
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Thu May 28 17:44:05 2015 +0200
@@ -38,6 +38,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.options.*;
 
 /**
  * Fills in a {@link CompilationResult} as its code is being assembled.
@@ -46,6 +47,11 @@
  */
 public class CompilationResultBuilder {
 
+    // @formatter:off
+    @Option(help = "Include the LIR as comments with the final assembly.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> PrintLIRWithAssembly = new OptionValue<>(false);
+    // @formatter:on
+
     private static class ExceptionInfo {
 
         public final int codeOffset;
@@ -353,12 +359,12 @@
     }
 
     private void emitBlock(AbstractBlockBase<?> block) {
-        if (Debug.isDumpEnabled()) {
+        if (Debug.isDumpEnabled() || PrintLIRWithAssembly.getValue()) {
             blockComment(String.format("block B%d %s", block.getId(), block.getLoop()));
         }
 
         for (LIRInstruction op : lir.getLIRforBlock(block)) {
-            if (Debug.isDumpEnabled()) {
+            if (Debug.isDumpEnabled() || PrintLIRWithAssembly.getValue()) {
                 blockComment(String.format("%d %s", op.id(), op));
             }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleVirtualStackSlot.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleVirtualStackSlot.java	Thu May 28 17:44:05 2015 +0200
@@ -30,8 +30,6 @@
  */
 public class SimpleVirtualStackSlot extends VirtualStackSlot {
 
-    private static final long serialVersionUID = 7654295701165421750L;
-
     public SimpleVirtualStackSlot(int id, LIRKind lirKind) {
         super(id, lirKind);
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/VirtualStackSlotRange.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/VirtualStackSlotRange.java	Thu May 28 17:44:05 2015 +0200
@@ -33,7 +33,6 @@
  */
 public class VirtualStackSlotRange extends VirtualStackSlot {
 
-    private static final long serialVersionUID = 5152592950118317121L;
     private final BitSet objects;
     private final int slots;
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -25,26 +25,29 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
 
 public abstract class AllocationPhase extends LIRPhase<AllocationPhase.AllocationContext> {
 
     public static final class AllocationContext {
         private final SpillMoveFactory spillMoveFactory;
+        private final RegisterAllocationConfig registerAllocationConfig;
 
-        public AllocationContext(SpillMoveFactory spillMoveFactory) {
+        public AllocationContext(SpillMoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) {
             this.spillMoveFactory = spillMoveFactory;
+            this.registerAllocationConfig = registerAllocationConfig;
         }
     }
 
     @Override
     protected final <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.spillMoveFactory);
+        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.spillMoveFactory, context.registerAllocationConfig);
     }
 
     protected abstract <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    SpillMoveFactory spillMoveFactory);
+                    SpillMoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig);
 
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Thu May 28 17:44:05 2015 +0200
@@ -30,6 +30,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
@@ -69,7 +70,8 @@
     private static final DebugTimer AssignSlotsTimer = Debug.timer("LSStackSlotAllocator[AssignSlots]");
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
         lirGenRes.buildFrameMap(this);
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Thu May 28 17:44:05 2015 +0200
@@ -28,6 +28,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
@@ -40,7 +41,8 @@
 public class SimpleStackSlotAllocator extends AllocationPhase implements StackSlotAllocator {
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
         lirGenRes.buildFrameMap(this);
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java	Thu May 28 17:44:05 2015 +0200
@@ -99,7 +99,7 @@
 
     @Override
     public String toString() {
-        return String.format("SI[%d-%d] k=%s o=%s l=%s h=%s", from, to, kind, operand, location, hint.getOperand());
+        return String.format("SI[%d-%d] k=%s o=%s l=%s h=%s", from, to, kind, operand, location, hint != null ? hint.getOperand() : "null");
     }
 
     public void setLocationHint(StackInterval locationHint) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedConvertedInductionVariable.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.loop;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+
+public class DerivedConvertedInductionVariable extends DerivedInductionVariable {
+
+    private final Stamp stamp;
+    private final ValueNode value;
+
+    public DerivedConvertedInductionVariable(LoopEx loop, InductionVariable base, Stamp stamp, ValueNode value) {
+        super(loop, base);
+        this.stamp = stamp;
+        this.value = value;
+    }
+
+    @Override
+    public ValueNode valueNode() {
+        return value;
+    }
+
+    @Override
+    public Direction direction() {
+        return base.direction();
+    }
+
+    @Override
+    public ValueNode initNode() {
+        return IntegerConvertNode.convert(base.initNode(), stamp, graph());
+    }
+
+    @Override
+    public ValueNode strideNode() {
+        return IntegerConvertNode.convert(base.strideNode(), stamp, graph());
+    }
+
+    @Override
+    public boolean isConstantInit() {
+        return base.isConstantInit();
+    }
+
+    @Override
+    public boolean isConstantStride() {
+        return base.isConstantStride();
+    }
+
+    @Override
+    public long constantInit() {
+        return base.constantInit();
+    }
+
+    @Override
+    public long constantStride() {
+        return base.constantStride();
+    }
+
+    @Override
+    public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp s) {
+        return base.extremumNode(assumePositiveTripCount, s);
+    }
+
+    @Override
+    public ValueNode exitValueNode() {
+        return IntegerConvertNode.convert(base.exitValueNode(), stamp, graph());
+    }
+
+    @Override
+    public boolean isConstantExtremum() {
+        return base.isConstantExtremum();
+    }
+
+    @Override
+    public long constantExtremum() {
+        return base.constantExtremum();
+    }
+
+    @Override
+    public void deleteUnusedNodes() {
+    }
+
+    @Override
+    public String toString() {
+        return String.format("DerivedConvertedInductionVariable base (%s) %s %s", base, value.getNodeClass().shortName(), stamp);
+    }
+}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Thu May 28 17:44:05 2015 +0200
@@ -42,7 +42,7 @@
 
     public DerivedScaledInductionVariable(LoopEx loop, InductionVariable base, NegateNode value) {
         super(loop, base);
-        this.scale = ConstantNode.forInt(-1, value.graph());
+        this.scale = ConstantNode.forIntegerStamp(value.stamp(), -1, value.graph());
         this.value = value;
     }
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -162,7 +162,7 @@
     public boolean detectCounted() {
         LoopBeginNode loopBegin = loopBegin();
         FixedNode next = loopBegin.next();
-        while (next instanceof FixedGuardNode || next instanceof ValueAnchorNode) {
+        while (next instanceof FixedGuardNode || next instanceof ValueAnchorNode || next instanceof InfopointNode) {
             next = ((FixedWithNextNode) next).next();
         }
         if (next instanceof IfNode) {
@@ -333,6 +333,16 @@
                     iv = new DerivedScaledInductionVariable(loop, baseIv, (NegateNode) op);
                 } else if ((scale = mul(loop, op, baseIvNode)) != null) {
                     iv = new DerivedScaledInductionVariable(loop, baseIv, scale, op);
+                } else {
+                    boolean isValidConvert = op instanceof PiNode || op instanceof SignExtendNode;
+                    if (!isValidConvert && op instanceof ZeroExtendNode) {
+                        IntegerStamp inputStamp = (IntegerStamp) ((ZeroExtendNode) op).getValue().stamp();
+                        isValidConvert = inputStamp.isPositive();
+                    }
+
+                    if (isValidConvert) {
+                        iv = new DerivedConvertedInductionVariable(loop, baseIv, op.stamp(), op);
+                    }
                 }
 
                 if (iv != null) {
@@ -368,7 +378,7 @@
         if (op instanceof LeftShiftNode) {
             LeftShiftNode shift = (LeftShiftNode) op;
             if (shift.getX() == base && shift.getY().isConstant()) {
-                return ConstantNode.forInt(1 << shift.getY().asJavaConstant().asInt(), base.graph());
+                return ConstantNode.forIntegerStamp(base.stamp(), 1 << shift.getY().asJavaConstant().asInt(), base.graph());
             }
         }
         return null;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.VirtualState.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.util.*;
 
 public class LoopFragmentInside extends LoopFragment {
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -123,8 +123,8 @@
                         if (modifiers.contains(FINAL)) {
                             throw new ElementException(field, "Input list field must not be final");
                         }
-                        if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) {
-                            throw new ElementException(field, "Input list field must be protected or package-private");
+                        if (modifiers.contains(PUBLIC)) {
+                            throw new ElementException(field, "Input list field must not be public");
                         }
                     } else {
                         if (!isAssignableWithErasure(field, Node) && field.getKind() == ElementKind.INTERFACE) {
@@ -133,8 +133,8 @@
                         if (modifiers.contains(FINAL)) {
                             throw new ElementException(field, "Input field must not be final");
                         }
-                        if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) {
-                            throw new ElementException(field, "Input field must be protected or package-private");
+                        if (modifiers.contains(PUBLIC)) {
+                            throw new ElementException(field, "Input field must not be public");
                         }
                     }
                 } else if (isSuccessor) {
@@ -152,8 +152,8 @@
                         if (modifiers.contains(FINAL)) {
                             throw new ElementException(field, "Successor field must not be final");
                         }
-                        if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) {
-                            throw new ElementException(field, "Successor field must be protected or package-private");
+                        if (modifiers.contains(PUBLIC)) {
+                            throw new ElementException(field, "Successor field must not be public");
                         }
                     }
 
@@ -167,12 +167,8 @@
                     if (isAssignableWithErasure(field, NodeSuccessorList)) {
                         throw new ElementException(field, "NodeSuccessorList field must be annotated with @" + Successor.getSimpleName());
                     }
-                    if (modifiers.contains(PUBLIC)) {
-                        if (!modifiers.contains(FINAL)) {
-                            throw new ElementException(field, "Data field must be final if public otherwise it must be protected");
-                        }
-                    } else if (!modifiers.contains(PROTECTED)) {
-                        throw new ElementException(field, "Data field must be protected");
+                    if (modifiers.contains(PUBLIC) && !modifiers.contains(FINAL)) {
+                        throw new ElementException(field, "Data field must be final if public");
                     }
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMemoryCheckpoint.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes;
-
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Provides an implementation of {@link StateSplit}.
- */
-@NodeInfo
-public abstract class AbstractMemoryCheckpoint extends AbstractStateSplit implements MemoryCheckpoint {
-
-    public static final NodeClass<AbstractMemoryCheckpoint> TYPE = NodeClass.create(AbstractMemoryCheckpoint.class);
-
-    protected AbstractMemoryCheckpoint(NodeClass<? extends AbstractMemoryCheckpoint> c, Stamp stamp) {
-        this(c, stamp, null);
-    }
-
-    protected AbstractMemoryCheckpoint(NodeClass<? extends AbstractMemoryCheckpoint> c, Stamp stamp, FrameState stateAfter) {
-        super(c, stamp, stateAfter);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java	Thu May 28 17:44:05 2015 +0200
@@ -31,10 +31,14 @@
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
-public abstract class DirectCallTargetNode extends LoweredCallTargetNode {
+public class DirectCallTargetNode extends LoweredCallTargetNode {
 
     public static final NodeClass<DirectCallTargetNode> TYPE = NodeClass.create(DirectCallTargetNode.class);
 
+    public DirectCallTargetNode(List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) {
+        this(TYPE, arguments, returnStamp, signature, target, callType, invokeKind);
+    }
+
     protected DirectCallTargetNode(NodeClass<? extends DirectCallTargetNode> c, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target,
                     CallingConvention.Type callType, InvokeKind invokeKind) {
         super(c, arguments, returnStamp, signature, target, callType, invokeKind);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Thu May 28 17:44:05 2015 +0200
@@ -117,6 +117,19 @@
                         bci == BytecodeFrame.INVALID_FRAMESTATE_BCI;
     }
 
+    /**
+     * Creates a placeholder frame state with a single element on the stack representing a return
+     * value. This allows the parsing of an intrinsic to communicate the returned value in a
+     * {@link StateSplit#stateAfter() stateAfter} to the inlining call site.
+     *
+     * @param bci this must be {@link BytecodeFrame#AFTER_BCI}
+     */
+    public FrameState(int bci, ValueNode returnValue) {
+        this(null, null, bci, 0, returnValue.getKind().getSlotCount(), 0, false, false, null, Collections.<EscapeObjectState> emptyList());
+        assert bci == BytecodeFrame.AFTER_BCI;
+        this.values.initialize(0, returnValue);
+    }
+
     public FrameState(FrameState outerFrameState, ResolvedJavaMethod method, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, ValueNode[] locks, List<MonitorIdNode> monitorIds,
                     boolean rethrowException, boolean duringCall) {
         this(outerFrameState, method, bci, locals.length, stackSize, locks.length, rethrowException, duringCall, monitorIds, Collections.<EscapeObjectState> emptyList());
@@ -153,6 +166,17 @@
         this.outerFrameState = x;
     }
 
+    public BytecodePosition toBytecodePosition() {
+        return toBytecodePosition(this);
+    }
+
+    public static BytecodePosition toBytecodePosition(FrameState fs) {
+        if (fs == null) {
+            return null;
+        }
+        return new BytecodePosition(toBytecodePosition(fs.outerFrameState()), fs.method(), fs.bci);
+    }
+
     /**
      * @see BytecodeFrame#rethrowException
      */
@@ -410,7 +434,11 @@
         String nl = CodeUtil.NEW_LINE;
         FrameState fs = frameState;
         while (fs != null) {
-            MetaUtil.appendLocation(sb, fs.method, fs.bci).append(nl);
+            MetaUtil.appendLocation(sb, fs.method, fs.bci);
+            if (BytecodeFrame.isPlaceholderBci(fs.bci)) {
+                sb.append("//").append(getPlaceholderBciName(fs.bci));
+            }
+            sb.append(nl);
             sb.append("locals: [");
             for (int i = 0; i < fs.localsSize(); i++) {
                 sb.append(i == 0 ? "" : ", ").append(fs.localAt(i) == null ? "_" : fs.localAt(i).toString(Verbosity.Id));
@@ -434,7 +462,11 @@
         if (verbosity == Verbosity.Debugger) {
             return toString(this);
         } else if (verbosity == Verbosity.Name) {
-            return super.toString(Verbosity.Name) + "@" + bci;
+            String res = super.toString(Verbosity.Name) + "@" + bci;
+            if (BytecodeFrame.isPlaceholderBci(bci)) {
+                res += "[" + getPlaceholderBciName(bci) + "]";
+            }
+            return res;
         } else {
             return super.toString(verbosity);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Thu May 28 17:44:05 2015 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.compiler.common.util.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.util.*;
 
 /**
  * Decoder for {@link EncodedGraph encoded graphs} produced by {@link GraphEncoder}. Support for
@@ -272,6 +271,13 @@
         LoopScope loopScope = new LoopScope(methodScope);
         FixedNode firstNode;
         if (startNode != null) {
+            /*
+             * The start node of a graph can be referenced as the guard for a GuardedNode. We
+             * register the previous block node, so that such guards are correctly anchored when
+             * doing inlining during graph decoding.
+             */
+            registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, AbstractBeginNode.prevBegin(startNode), false, false);
+
             firstNode = makeStubNode(methodScope, loopScope, GraphEncoder.FIRST_NODE_ORDER_ID);
             startNode.setNext(firstNode);
             loopScope.nodesToProcess.set(GraphEncoder.FIRST_NODE_ORDER_ID);
@@ -333,6 +339,10 @@
                         ((AbstractMergeNode) node).forwardEndCount() == 1) {
             AbstractMergeNode merge = (AbstractMergeNode) node;
             EndNode singleEnd = merge.forwardEndAt(0);
+
+            /* Nodes that would use this merge as the guard need to use the previous block. */
+            registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false);
+
             FixedNode next = makeStubNode(methodScope, loopScope, nodeOrderId + GraphEncoder.BEGIN_NEXT_ORDER_ID_OFFSET);
             singleEnd.replaceAtPredecessor(next);
 
@@ -409,7 +419,7 @@
             methodScope.unwindNode = (UnwindNode) node;
 
         } else {
-            simplifyFixedNode(methodScope, loopScope, nodeOrderId, node);
+            handleFixedNode(methodScope, loopScope, nodeOrderId, node);
         }
 
         return resultScope;
@@ -527,7 +537,7 @@
      * @param nodeOrderId The orderId of the node.
      * @param node The node to be simplified.
      */
-    protected void simplifyFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) {
+    protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) {
     }
 
     protected void handleProxyNodes(MethodScope methodScope, LoopScope loopScope, LoopExitNode loopExit) {
@@ -823,7 +833,13 @@
     protected Node decodeFloatingNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) {
         long readerByteIndex = methodScope.reader.getByteIndex();
         Node node = instantiateNode(methodScope, nodeOrderId);
-        assert !(node instanceof FixedNode);
+        if (node instanceof FixedNode) {
+            /*
+             * This is a severe error that will lead to a corrupted graph, so it is better not to
+             * continue decoding at all.
+             */
+            throw shouldNotReachHere("Not a floating node: " + node.getClass().getName());
+        }
 
         /* Read the properties of the node. */
         readProperties(methodScope, node);
@@ -1154,32 +1170,14 @@
         }
     }
 
+    /**
+     * Removes unnecessary nodes from the graph after decoding.
+     *
+     * @param methodScope The current method.
+     * @param start Marker for the begin of the current method in the graph.
+     */
     protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) {
         assert verifyEdges(methodScope);
-
-        for (Node node : methodScope.graph.getNewNodes(start)) {
-            if (node instanceof MergeNode) {
-                MergeNode mergeNode = (MergeNode) node;
-                if (mergeNode.forwardEndCount() == 1) {
-                    methodScope.graph.reduceTrivialMerge(mergeNode);
-                }
-            }
-        }
-
-        for (Node node : methodScope.graph.getNewNodes(start)) {
-            if (node instanceof BeginNode || node instanceof KillingBeginNode) {
-                if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) {
-                    GraphUtil.unlinkFixedNode((AbstractBeginNode) node);
-                    node.safeDelete();
-                }
-            }
-        }
-
-        for (Node node : methodScope.graph.getNewNodes(start)) {
-            if (!(node instanceof FixedNode) && node.hasNoUsages()) {
-                GraphUtil.killCFG(node);
-            }
-        }
     }
 
     protected boolean verifyEdges(MethodScope methodScope) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Thu May 28 17:44:05 2015 +0200
@@ -81,6 +81,15 @@
         this.negated = negateCondition;
     }
 
+    public static ValueNode createNullCheck(ValueNode object) {
+        ObjectStamp objectStamp = (ObjectStamp) object.stamp();
+        if (objectStamp.nonNull()) {
+            return object;
+        } else {
+            return new GuardingPiNode(object);
+        }
+    }
+
     @Override
     public void lower(LoweringTool tool) {
         GuardingNode guard = tool.createGuard(next(), condition, reason, action, negated);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/HeapAccess.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes;
-
-/**
- * Encapsulates properties of a node describing how it accesses the heap.
- */
-public interface HeapAccess {
-
-    /**
-     * The types of (write/read) barriers attached to stores.
-     */
-    public enum BarrierType {
-        /**
-         * Primitive stores which do not necessitate barriers.
-         */
-        NONE,
-        /**
-         * Array object stores which necessitate precise barriers.
-         */
-        PRECISE,
-        /**
-         * Field object stores which necessitate imprecise barriers.
-         */
-        IMPRECISE
-    }
-
-    /**
-     * Gets the write barrier type for that particular access.
-     */
-    BarrierType getBarrierType();
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Thu May 28 17:44:05 2015 +0200
@@ -31,11 +31,16 @@
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
-public abstract class IndirectCallTargetNode extends LoweredCallTargetNode {
+public class IndirectCallTargetNode extends LoweredCallTargetNode {
     public static final NodeClass<IndirectCallTargetNode> TYPE = NodeClass.create(IndirectCallTargetNode.class);
 
     @Input protected ValueNode computedAddress;
 
+    public IndirectCallTargetNode(ValueNode computedAddress, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType,
+                    InvokeKind invokeKind) {
+        this(TYPE, computedAddress, arguments, returnStamp, signature, target, callType, invokeKind);
+    }
+
     protected IndirectCallTargetNode(NodeClass<? extends IndirectCallTargetNode> c, ValueNode computedAddress, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature,
                     ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) {
         super(c, arguments, returnStamp, signature, target, callType, invokeKind);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Thu May 28 17:44:05 2015 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Thu May 28 17:44:05 2015 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Thu May 28 17:44:05 2015 +0200
@@ -25,7 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public final class KillingBeginNode extends AbstractBeginNode implements MemoryCheckpoint.Single {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Thu May 28 17:44:05 2015 +0200
@@ -55,4 +55,22 @@
     public static LogicNode or(LogicNode a, boolean negateA, LogicNode b, boolean negateB, double shortCircuitProbability) {
         return a.graph().unique(new ShortCircuitOrNode(a, negateA, b, negateB, shortCircuitProbability));
     }
+
+    public final boolean isTautology() {
+        if (this instanceof LogicConstantNode) {
+            LogicConstantNode logicConstantNode = (LogicConstantNode) this;
+            return logicConstantNode.getValue();
+        }
+
+        return false;
+    }
+
+    public final boolean isContradiction() {
+        if (this instanceof LogicConstantNode) {
+            LogicConstantNode logicConstantNode = (LogicConstantNode) this;
+            return !logicConstantNode.getValue();
+        }
+
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMap.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Maps a {@linkplain LocationIdentity location} to the last node that (potentially) wrote to the
- * location.
- */
-public interface MemoryMap {
-
-    /**
-     * Gets the last node that that (potentially) wrote to {@code locationIdentity}.
-     */
-    MemoryNode getLastLocationAccess(LocationIdentity locationIdentity);
-
-    /**
-     * Gets the location identities in the domain of this map.
-     */
-    Collection<LocationIdentity> getLocations();
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes;
-
-import static com.oracle.graal.api.meta.LocationIdentity.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-@NodeInfo(allowedUsageTypes = {InputType.Extension, InputType.Memory})
-public final class MemoryMapNode extends FloatingNode implements MemoryMap, MemoryNode, LIRLowerable {
-
-    public static final NodeClass<MemoryMapNode> TYPE = NodeClass.create(MemoryMapNode.class);
-    protected final List<LocationIdentity> locationIdentities;
-    @Input(InputType.Memory) NodeInputList<ValueNode> nodes;
-
-    private boolean checkOrder(Map<LocationIdentity, MemoryNode> mmap) {
-        for (int i = 0; i < locationIdentities.size(); i++) {
-            LocationIdentity locationIdentity = locationIdentities.get(i);
-            ValueNode n = nodes.get(i);
-            assertTrue(mmap.get(locationIdentity) == n, "iteration order of keys differs from values in input map");
-        }
-        return true;
-    }
-
-    public MemoryMapNode(Map<LocationIdentity, MemoryNode> mmap) {
-        super(TYPE, StampFactory.forVoid());
-        locationIdentities = new ArrayList<>(mmap.keySet());
-        nodes = new NodeInputList<>(this, mmap.values());
-        assert checkOrder(mmap);
-    }
-
-    public boolean isEmpty() {
-        if (locationIdentities.isEmpty()) {
-            return true;
-        }
-        if (locationIdentities.size() == 1) {
-            if (nodes.get(0) instanceof StartNode) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) {
-        if (locationIdentity.isImmutable()) {
-            return null;
-        } else {
-            int index = locationIdentities.indexOf(locationIdentity);
-            if (index == -1) {
-                index = locationIdentities.indexOf(any());
-            }
-            assert index != -1;
-            return (MemoryNode) nodes.get(index);
-        }
-    }
-
-    public Collection<LocationIdentity> getLocations() {
-        return locationIdentities;
-    }
-
-    public Map<LocationIdentity, MemoryNode> toMap() {
-        HashMap<LocationIdentity, MemoryNode> res = CollectionsFactory.newMap(locationIdentities.size());
-        for (int i = 0; i < nodes.size(); i++) {
-            res.put(locationIdentities.get(i), (MemoryNode) nodes.get(i));
-        }
-        return res;
-    }
-
-    public void generate(NodeLIRBuilderTool generator) {
-        // nothing to do...
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Memory {@code PhiNode}s merge memory dependencies at control flow merges.
- */
-@NodeInfo(nameTemplate = "\u03D5({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory})
-public final class MemoryPhiNode extends PhiNode implements MemoryNode {
-
-    public static final NodeClass<MemoryPhiNode> TYPE = NodeClass.create(MemoryPhiNode.class);
-    @Input(InputType.Memory) NodeInputList<ValueNode> values;
-    protected final LocationIdentity locationIdentity;
-
-    public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity) {
-        super(TYPE, StampFactory.forVoid(), merge);
-        this.locationIdentity = locationIdentity;
-        this.values = new NodeInputList<>(this);
-    }
-
-    public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity, ValueNode[] values) {
-        super(TYPE, StampFactory.forVoid(), merge);
-        this.locationIdentity = locationIdentity;
-        this.values = new NodeInputList<>(this, values);
-    }
-
-    public LocationIdentity getLocationIdentity() {
-        return locationIdentity;
-    }
-
-    @Override
-    public NodeInputList<ValueNode> values() {
-        return values;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java	Thu May 28 17:44:05 2015 +0200
@@ -25,6 +25,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimpleInfopointNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimpleInfopointNode.java	Thu May 28 17:44:05 2015 +0200
@@ -48,15 +48,7 @@
     }
 
     public void addCaller(BytecodePosition caller) {
-        this.position = relink(this.position, caller);
-    }
-
-    private static BytecodePosition relink(BytecodePosition position, BytecodePosition link) {
-        if (position.getCaller() == null) {
-            return new BytecodePosition(link, position.getMethod(), position.getBCI());
-        } else {
-            return new BytecodePosition(relink(position.getCaller(), link), position.getMethod(), position.getBCI());
-        }
+        this.position = position.addCaller(caller);
     }
 
     @Override
@@ -65,4 +57,21 @@
             graph().removeFixed(this);
         }
     }
+
+    public void setPosition(BytecodePosition position) {
+        this.position = position;
+    }
+
+    @Override
+    public boolean verify() {
+        BytecodePosition pos = position;
+        if (pos != null) {
+            // Verify that the outermost position belongs to this graph.
+            while (pos.getCaller() != null) {
+                pos = pos.getCaller();
+            }
+            assert pos.getMethod().equals(graph().method());
+        }
+        return super.verify();
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java	Thu May 28 17:44:05 2015 +0200
@@ -79,6 +79,30 @@
     protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) {
         GraphUtil.normalizeLoops(methodScope.graph);
         super.cleanupGraph(methodScope, start);
+
+        for (Node node : methodScope.graph.getNewNodes(start)) {
+            if (node instanceof MergeNode) {
+                MergeNode mergeNode = (MergeNode) node;
+                if (mergeNode.forwardEndCount() == 1) {
+                    methodScope.graph.reduceTrivialMerge(mergeNode);
+                }
+            }
+        }
+
+        for (Node node : methodScope.graph.getNewNodes(start)) {
+            if (node instanceof BeginNode || node instanceof KillingBeginNode) {
+                if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) {
+                    GraphUtil.unlinkFixedNode((AbstractBeginNode) node);
+                    node.safeDelete();
+                }
+            }
+        }
+
+        for (Node node : methodScope.graph.getNewNodes(start)) {
+            if (!(node instanceof FixedNode) && node.hasNoUsages()) {
+                GraphUtil.killCFG(node);
+            }
+        }
     }
 
     @Override
@@ -91,7 +115,7 @@
     }
 
     @Override
-    protected void simplifyFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) {
+    protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) {
         if (node instanceof IfNode) {
             IfNode ifNode = (IfNode) node;
             if (ifNode.condition() instanceof LogicNegationNode) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Thu May 28 17:44:05 2015 +0200
@@ -25,7 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 
 /**
  * The start node of a graph.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu May 28 17:44:05 2015 +0200
@@ -24,6 +24,7 @@
 
 import java.util.*;
 import java.util.concurrent.atomic.*;
+import java.util.function.*;
 
 import com.oracle.graal.api.meta.Assumptions.Assumption;
 import com.oracle.graal.api.meta.*;
@@ -115,9 +116,10 @@
     private final Assumptions assumptions;
 
     /**
-     * The methods that were inlined while constructing this graph.
+     * Records the methods that were inlined while constructing this graph along with how many times
+     * each method was inlined.
      */
-    private Set<ResolvedJavaMethod> inlinedMethods = new HashSet<>();
+    private Map<ResolvedJavaMethod, Integer> inlinedMethods = new HashMap<>();
 
     /**
      * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
@@ -217,17 +219,17 @@
         this.start = start;
     }
 
+    /**
+     * Creates a copy of this graph.
+     *
+     * @param newName the name of the copy, used for debugging purposes (can be null)
+     * @param duplicationMapCallback consumer of the duplication map created during the copying
+     */
     @Override
-    public StructuredGraph copy() {
-        return copy(name);
-    }
-
-    public StructuredGraph copy(String newName, ResolvedJavaMethod newMethod) {
-        return copy(newName, newMethod, AllowAssumptions.from(assumptions != null), isInlinedMethodRecordingEnabled());
-    }
-
-    public StructuredGraph copy(String newName, ResolvedJavaMethod newMethod, AllowAssumptions allowAssumptions, boolean enableInlinedMethodRecording) {
-        StructuredGraph copy = new StructuredGraph(newName, newMethod, graphId, entryBCI, allowAssumptions);
+    protected Graph copy(String newName, Consumer<Map<Node, Node>> duplicationMapCallback) {
+        AllowAssumptions allowAssumptions = AllowAssumptions.from(assumptions != null);
+        boolean enableInlinedMethodRecording = isInlinedMethodRecordingEnabled();
+        StructuredGraph copy = new StructuredGraph(newName, method, graphId, entryBCI, allowAssumptions);
         if (allowAssumptions == AllowAssumptions.YES && assumptions != null) {
             copy.assumptions.record(assumptions);
         }
@@ -239,15 +241,13 @@
         copy.hasValueProxies = hasValueProxies;
         Map<Node, Node> replacements = Node.newMap();
         replacements.put(start, copy.start);
-        copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements);
+        Map<Node, Node> duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements);
+        if (duplicationMapCallback != null) {
+            duplicationMapCallback.accept(duplicates);
+        }
         return copy;
     }
 
-    @Override
-    public StructuredGraph copy(String newName) {
-        return copy(newName, method);
-    }
-
     public ParameterNode getParameter(int index) {
         for (ParameterNode param : getNodes(ParameterNode.TYPE)) {
             if (param.index() == index) {
@@ -516,12 +516,12 @@
     }
 
     /**
-     * Disables recording of methods inlined while constructing this graph. This can be done at most
+     * Disables method inlining recording while constructing this graph. This can be done at most
      * once and must be done before any inlined methods are recorded.
      */
     public void disableInlinedMethodRecording() {
-        assert inlinedMethods != null : "cannot disable inlined method recording more than once";
-        assert inlinedMethods.isEmpty() : "cannot disable inlined method recording once methods have been recorded";
+        assert inlinedMethods != null : "cannot disable method inlining recording more than once";
+        assert inlinedMethods.isEmpty() : "cannot disable method inlining recording once methods have been recorded";
         inlinedMethods = null;
     }
 
@@ -532,11 +532,69 @@
     /**
      * Gets the methods that were inlined while constructing this graph.
      *
-     * @return {@code null} if inlined method recording has been
+     * @return {@code null} if method inlining recording has been
      *         {@linkplain #disableInlinedMethodRecording() disabled}
      */
     public Set<ResolvedJavaMethod> getInlinedMethods() {
-        return inlinedMethods;
+        return inlinedMethods == null ? null : inlinedMethods.keySet();
+    }
+
+    /**
+     * If method inlining recording has not been {@linkplain #disableInlinedMethodRecording()
+     * disabled}, records that {@code inlinedMethod} was inlined to this graph. Otherwise, this
+     * method does nothing.
+     */
+    public void recordInlinedMethod(ResolvedJavaMethod inlinedMethod) {
+        if (inlinedMethods != null) {
+            Integer count = inlinedMethods.get(inlinedMethod);
+            if (count != null) {
+                inlinedMethods.put(inlinedMethod, count + 1);
+            } else {
+                inlinedMethods.put(inlinedMethod, 1);
+            }
+        }
+    }
+
+    /**
+     * If method inlining recording has not been {@linkplain #disableInlinedMethodRecording()
+     * disabled}, updates the {@linkplain #getInlinedMethods() inlined methods} of this graph with
+     * the inlined methods of another graph. Otherwise, this method does nothing.
+     */
+    public void updateInlinedMethods(StructuredGraph other) {
+        if (inlinedMethods != null) {
+            assert this != other;
+            Map<ResolvedJavaMethod, Integer> otherInlinedMethods = other.inlinedMethods;
+            if (otherInlinedMethods != null) {
+                for (Map.Entry<ResolvedJavaMethod, Integer> e : otherInlinedMethods.entrySet()) {
+                    ResolvedJavaMethod key = e.getKey();
+                    Integer count = inlinedMethods.get(key);
+                    if (count != null) {
+                        inlinedMethods.put(key, count + e.getValue());
+                    } else {
+                        inlinedMethods.put(key, e.getValue());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the input bytecode {@linkplain ResolvedJavaMethod#getCodeSize() size} from which this
+     * graph is constructed. This ignores how many bytecodes in each constituent method are actually
+     * parsed (which may be none for methods whose IR is retrieved from a cache or less than the
+     * full amount for any given method due to profile guided branch pruning). If method inlining
+     * recording has been {@linkplain #disableInlinedMethodRecording() disabled} for this graph,
+     * bytecode counts for inlined methods are not included in the returned value.
+     */
+    public int getBytecodeSize() {
+        int res = method.getCodeSize();
+        if (inlinedMethods != null) {
+            for (Map.Entry<ResolvedJavaMethod, Integer> e : inlinedMethods.entrySet()) {
+                int inlinedBytes = e.getValue() * e.getKey().getCodeSize();
+                res += inlinedBytes;
+            }
+        }
+        return res;
     }
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * 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,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 
 public class ValueNodeUtil {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Thu May 28 17:44:05 2015 +0200
@@ -59,6 +59,10 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.meet(values()));
+        Stamp valuesStamp = StampTool.meet(values());
+        if (stamp.isCompatible(valuesStamp)) {
+            valuesStamp = stamp.join(valuesStamp);
+        }
+        return updateStamp(valuesStamp);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Thu May 28 17:44:05 2015 +0200
@@ -31,11 +31,15 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "/")
-public final class IntegerDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public class IntegerDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
     public static final NodeClass<IntegerDivNode> TYPE = NodeClass.create(IntegerDivNode.class);
 
     public IntegerDivNode(ValueNode x, ValueNode y) {
-        super(TYPE, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), x, y);
+        this(TYPE, x, y);
+    }
+
+    protected IntegerDivNode(NodeClass<? extends IntegerDivNode> c, ValueNode x, ValueNode y) {
+        super(c, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Thu May 28 17:44:05 2015 +0200
@@ -92,6 +92,8 @@
             return new FloatEqualsNode(newX, newY);
         } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
             return new IntegerEqualsNode(newX, newY);
+        } else if (newX.stamp() instanceof AbstractPointerStamp && newY.stamp() instanceof AbstractPointerStamp) {
+            return new IntegerEqualsNode(newX, newY);
         }
         throw GraalInternalError.shouldNotReachHere();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Thu May 28 17:44:05 2015 +0200
@@ -31,11 +31,15 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "%")
-public final class IntegerRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public class IntegerRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
     public static final NodeClass<IntegerRemNode> TYPE = NodeClass.create(IntegerRemNode.class);
 
     public IntegerRemNode(ValueNode x, ValueNode y) {
-        super(TYPE, IntegerStamp.OPS.getRem().foldStamp(x.stamp(), y.stamp()), x, y);
+        this(TYPE, x, y);
+    }
+
+    protected IntegerRemNode(NodeClass<? extends IntegerRemNode> c, ValueNode x, ValueNode y) {
+        super(c, IntegerStamp.OPS.getRem().foldStamp(x.stamp(), y.stamp()), x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowableArithmeticNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowableArithmeticNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,4 +28,14 @@
  * result.
  */
 public interface NarrowableArithmeticNode {
+
+    /**
+     * Check whether this operation can be narrowed to {@code resultBits} bit without loss of
+     * precision.
+     *
+     * @param resultBits
+     */
+    default boolean isNarrowable(int resultBits) {
+        return true;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Thu May 28 17:44:05 2015 +0200
@@ -37,7 +37,7 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "|")
-public final class OrNode extends BinaryArithmeticNode<Or> implements BinaryCommutative<ValueNode> {
+public final class OrNode extends BinaryArithmeticNode<Or> implements BinaryCommutative<ValueNode>, NarrowableArithmeticNode {
 
     public static final NodeClass<OrNode> TYPE = NodeClass.create(OrNode.class);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Thu May 28 17:44:05 2015 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp.Shr;
 import com.oracle.graal.graph.*;
@@ -98,4 +99,19 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitShr(builder.operand(getX()), builder.operand(getY())));
     }
+
+    @Override
+    public boolean isNarrowable(int resultBits) {
+        if (super.isNarrowable(resultBits)) {
+            /*
+             * For signed right shifts, the narrow can be done before the shift if the cut off bits
+             * are all equal to the sign bit of the input. That's equivalent to the condition that
+             * the input is in the signed range of the narrow type.
+             */
+            IntegerStamp inputStamp = (IntegerStamp) getX().stamp();
+            return CodeUtil.minValue(resultBits) <= inputStamp.lowerBound() && inputStamp.upperBound() <= CodeUtil.maxValue(resultBits);
+        } else {
+            return false;
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Thu May 28 17:44:05 2015 +0200
@@ -25,6 +25,7 @@
 import java.io.*;
 import java.util.function.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp;
@@ -38,7 +39,7 @@
  * The {@code ShiftOp} class represents shift operations.
  */
 @NodeInfo
-public abstract class ShiftNode<OP> extends BinaryNode implements ArithmeticLIRLowerable {
+public abstract class ShiftNode<OP> extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     @SuppressWarnings("rawtypes") public static final NodeClass<ShiftNode> TYPE = NodeClass.create(ShiftNode.class);
 
@@ -82,4 +83,18 @@
         return getOp(getX()).getShiftAmountMask(stamp());
     }
 
+    public boolean isNarrowable(int resultBits) {
+        assert CodeUtil.isPowerOf2(resultBits);
+        int narrowMask = resultBits - 1;
+        int wideMask = getShiftAmountMask();
+        assert (wideMask & narrowMask) == narrowMask : String.format("wideMask %x should be wider than narrowMask %x", wideMask, narrowMask);
+
+        /*
+         * Shifts are special because narrowing them also changes the implicit mask of the shift
+         * amount. We can narrow only if (y & wideMask) == (y & narrowMask) for all possible values
+         * of y.
+         */
+        IntegerStamp yStamp = (IntegerStamp) getY().stamp();
+        return (yStamp.upMask() & (wideMask & ~narrowMask)) == 0;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java	Thu May 28 17:44:05 2015 +0200
@@ -34,7 +34,7 @@
  * Square root.
  */
 @NodeInfo
-public final class SqrtNode extends UnaryArithmeticNode<Sqrt> implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
+public final class SqrtNode extends UnaryArithmeticNode<Sqrt> implements ArithmeticLIRLowerable {
 
     public static final NodeClass<SqrtNode> TYPE = NodeClass.create(SqrtNode.class);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Thu May 28 17:44:05 2015 +0200
@@ -31,12 +31,16 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "|/|")
-public final class UnsignedDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public class UnsignedDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
 
     public static final NodeClass<UnsignedDivNode> TYPE = NodeClass.create(UnsignedDivNode.class);
 
     public UnsignedDivNode(ValueNode x, ValueNode y) {
-        super(TYPE, x.stamp().unrestricted(), x, y);
+        this(TYPE, x, y);
+    }
+
+    protected UnsignedDivNode(NodeClass<? extends UnsignedDivNode> c, ValueNode x, ValueNode y) {
+        super(c, x.stamp().unrestricted(), x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Thu May 28 17:44:05 2015 +0200
@@ -31,12 +31,16 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "|%|")
-public final class UnsignedRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public class UnsignedRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
 
     public static final NodeClass<UnsignedRemNode> TYPE = NodeClass.create(UnsignedRemNode.class);
 
     public UnsignedRemNode(ValueNode x, ValueNode y) {
-        super(TYPE, x.stamp().unrestricted(), x, y);
+        this(TYPE, x, y);
+    }
+
+    protected UnsignedRemNode(NodeClass<? extends UnsignedRemNode> c, ValueNode x, ValueNode y) {
+        super(c, x.stamp().unrestricted(), x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Thu May 28 17:44:05 2015 +0200
@@ -87,4 +87,18 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitUShr(builder.operand(getX()), builder.operand(getY())));
     }
+
+    @Override
+    public boolean isNarrowable(int resultBits) {
+        if (super.isNarrowable(resultBits)) {
+            /*
+             * For unsigned right shifts, the narrow can be done before the shift if the cut off
+             * bits are all zero.
+             */
+            IntegerStamp inputStamp = (IntegerStamp) getX().stamp();
+            return (inputStamp.upMask() & ~(resultBits - 1)) == 0;
+        } else {
+            return false;
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Thu May 28 17:44:05 2015 +0200
@@ -37,7 +37,7 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "^")
-public final class XorNode extends BinaryArithmeticNode<Xor> implements BinaryCommutative<ValueNode> {
+public final class XorNode extends BinaryArithmeticNode<Xor> implements BinaryCommutative<ValueNode>, NarrowableArithmeticNode {
 
     public static final NodeClass<XorNode> TYPE = NodeClass.create(XorNode.class);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 
 public final class Block extends AbstractBlockBase<Block> {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -305,20 +305,52 @@
         }
     }
 
-    private static void computeLoopBlocks(Block block, Loop<Block> loop) {
-        if (block.getLoop() == loop) {
-            return;
-        }
-        assert block.loop == loop.getParent();
-        block.loop = loop;
+    private static void computeLoopBlocks(Block ablock, Loop<Block> aloop) {
+        final int process = 0;
+        final int stepOut = 1;
+        class Frame {
+            final Iterator<Block> blocks;
+            final Loop<Block> loop;
+            final Frame parent;
 
-        assert !loop.getBlocks().contains(block);
-        loop.getBlocks().add(block);
+            public Frame(Iterator<Block> blocks, Loop<Block> loop, Frame parent) {
+                this.blocks = blocks;
+                this.loop = loop;
+                this.parent = parent;
+            }
+        }
+        int state = process;
+        Frame c = new Frame(Arrays.asList(ablock).iterator(), aloop, null);
+        while (c != null) {
+            int nextState = state;
+            if (state == process) {
+                Loop<Block> loop = c.loop;
+                Block block = c.blocks.next();
+                if (block.getLoop() == loop) {
+                    nextState = stepOut;
+                } else {
+                    assert block.loop == loop.getParent();
+                    block.loop = c.loop;
 
-        if (block != loop.getHeader()) {
-            for (Block pred : block.getPredecessors()) {
-                computeLoopBlocks(pred, loop);
+                    assert !c.loop.getBlocks().contains(block);
+                    c.loop.getBlocks().add(block);
+
+                    if (block != c.loop.getHeader()) {
+                        c = new Frame(block.getPredecessors().iterator(), loop, c);
+                    } else {
+                        nextState = stepOut;
+                    }
+                }
+            } else if (state == stepOut) {
+                if (c.blocks.hasNext()) {
+                    nextState = process;
+                } else {
+                    c = c.parent;
+                }
+            } else {
+                GraalInternalError.shouldNotReachHere();
             }
+            state = nextState;
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-
-@NodeInfo(allowedUsageTypes = {InputType.Memory})
-public abstract class AbstractWriteNode extends FixedAccessNode implements StateSplit, MemoryCheckpoint.Single, MemoryAccess, GuardingNode {
-
-    public static final NodeClass<AbstractWriteNode> TYPE = NodeClass.create(AbstractWriteNode.class);
-    @Input ValueNode value;
-    @OptionalInput(InputType.State) FrameState stateAfter;
-    @OptionalInput(InputType.Memory) Node lastLocationAccess;
-
-    protected final boolean initialization;
-
-    public FrameState stateAfter() {
-        return stateAfter;
-    }
-
-    public void setStateAfter(FrameState x) {
-        assert x == null || x.isAlive() : "frame state must be in a graph";
-        updateUsages(stateAfter, x);
-        stateAfter = x;
-    }
-
-    public boolean hasSideEffect() {
-        return true;
-    }
-
-    public ValueNode value() {
-        return value;
-    }
-
-    /**
-     * Returns whether this write is the initialization of the written location. If it is true, the
-     * old value of the memory location is either uninitialized or zero. If it is false, the memory
-     * location is guaranteed to contain a valid value or zero.
-     */
-    public boolean isInitialization() {
-        return initialization;
-    }
-
-    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) {
-        this(c, object, value, location, barrierType, false);
-    }
-
-    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) {
-        super(c, object, location, StampFactory.forVoid(), barrierType);
-        this.value = value;
-        this.initialization = initialization;
-    }
-
-    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) {
-        super(c, object, location, StampFactory.forVoid(), guard, barrierType, false, null);
-        this.value = value;
-        this.initialization = initialization;
-    }
-
-    @Override
-    public boolean isAllowedUsageType(InputType type) {
-        return (type == InputType.Guard && getNullCheck()) ? true : super.isAllowedUsageType(type);
-    }
-
-    @Override
-    public LocationIdentity getLocationIdentity() {
-        return location().getLocationIdentity();
-    }
-
-    public MemoryNode getLastLocationAccess() {
-        return (MemoryNode) lastLocationAccess;
-    }
-
-    public void setLastLocationAccess(MemoryNode lla) {
-        Node newLla = ValueNodeUtil.asNode(lla);
-        updateUsages(lastLocationAccess, newLla);
-        lastLocationAccess = newLla;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.nodes.*;
-
-public interface Access extends GuardedNode, HeapAccess {
-
-    ValueNode object();
-
-    LocationNode accessLocation();
-
-    boolean canNullCheck();
-
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.memory.*;
 
 /**
  * Base class for nodes that modify a range of an array.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * 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,6 +27,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Accesses a value at an memory address specified by an {@linkplain #object object} and a
- * {@linkplain #accessLocation() location}. The access does not include a null check on the object.
- */
-@NodeInfo
-public abstract class FixedAccessNode extends DeoptimizingFixedWithNextNode implements Access {
-    public static final NodeClass<FixedAccessNode> TYPE = NodeClass.create(FixedAccessNode.class);
-
-    @OptionalInput(InputType.Guard) protected GuardingNode guard;
-    @Input protected ValueNode object;
-    @Input(InputType.Association) protected ValueNode location;
-    protected boolean nullCheck;
-    protected BarrierType barrierType;
-
-    public ValueNode object() {
-        return object;
-    }
-
-    protected void setObject(ValueNode x) {
-        updateUsages(object, x);
-        object = x;
-    }
-
-    public LocationNode location() {
-        return (LocationNode) location;
-    }
-
-    public LocationNode accessLocation() {
-        return (LocationNode) location;
-    }
-
-    public boolean getNullCheck() {
-        return nullCheck;
-    }
-
-    public void setNullCheck(boolean check) {
-        this.nullCheck = check;
-    }
-
-    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, ValueNode object, ValueNode location, Stamp stamp) {
-        this(c, object, location, stamp, BarrierType.NONE);
-    }
-
-    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
-        this(c, object, location, stamp, null, barrierType, false, null);
-    }
-
-    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck,
-                    FrameState stateBefore) {
-        super(c, stamp, stateBefore);
-        this.object = object;
-        this.location = location;
-        this.guard = guard;
-        this.barrierType = barrierType;
-        this.nullCheck = nullCheck;
-    }
-
-    @Override
-    public boolean canDeoptimize() {
-        return nullCheck;
-    }
-
-    @Override
-    public GuardingNode getGuard() {
-        return guard;
-    }
-
-    @Override
-    public void setGuard(GuardingNode guard) {
-        updateUsagesInterface(this.guard, guard);
-        this.guard = guard;
-    }
-
-    @Override
-    public BarrierType getBarrierType() {
-        return barrierType;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * An {@link FixedAccessNode} that can be converted to a {@link FloatingAccessNode}.
- */
-@NodeInfo
-public abstract class FloatableAccessNode extends FixedAccessNode {
-    public static final NodeClass<FloatableAccessNode> TYPE = NodeClass.create(FloatableAccessNode.class);
-
-    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, ValueNode object, ValueNode location, Stamp stamp) {
-        super(c, object, location, stamp);
-    }
-
-    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
-        super(c, object, location, stamp, guard, barrierType, false, null);
-    }
-
-    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck,
-                    FrameState stateBefore) {
-        super(c, object, location, stamp, guard, barrierType, nullCheck, stateBefore);
-    }
-
-    public abstract FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess);
-
-    protected boolean forceFixed;
-
-    public void setForceFixed(boolean flag) {
-        this.forceFixed = flag;
-    }
-
-    /**
-     * AccessNodes can float only if their location identities are not ANY_LOCATION. Furthermore, in
-     * case G1 is enabled any access (read) to the java.lang.ref.Reference.referent field which has
-     * an attached write barrier with pre-semantics can not also float.
-     */
-    public boolean canFloat() {
-        return !forceFixed && location().getLocationIdentity().isSingle() && getBarrierType() == BarrierType.NONE;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-
-@NodeInfo
-public abstract class FloatingAccessNode extends FloatingGuardedNode implements Access, MemoryAccess {
-    public static final NodeClass<FloatingAccessNode> TYPE = NodeClass.create(FloatingAccessNode.class);
-
-    @Input ValueNode object;
-    @Input(InputType.Association) LocationNode location;
-    protected BarrierType barrierType;
-
-    public ValueNode object() {
-        return object;
-    }
-
-    public LocationNode location() {
-        return location;
-    }
-
-    public LocationNode accessLocation() {
-        return location;
-    }
-
-    public LocationIdentity getLocationIdentity() {
-        return location.getLocationIdentity();
-    }
-
-    protected FloatingAccessNode(NodeClass<? extends FloatingAccessNode> c, ValueNode object, LocationNode location, Stamp stamp) {
-        super(c, stamp);
-        this.object = object;
-        this.location = location;
-    }
-
-    protected FloatingAccessNode(NodeClass<? extends FloatingAccessNode> c, ValueNode object, LocationNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
-        super(c, stamp, guard);
-        this.object = object;
-        this.location = location;
-        this.barrierType = barrierType;
-    }
-
-    @Override
-    public BarrierType getBarrierType() {
-        return barrierType;
-    }
-
-    public boolean canNullCheck() {
-        return true;
-    }
-
-    public abstract FixedAccessNode asFixedNode();
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * A floating read of a value from memory specified in terms of an object base and an object
- * relative location. This node does not null check the object.
- */
-@NodeInfo
-public final class FloatingReadNode extends FloatingAccessNode implements LIRLowerable, Canonicalizable {
-    public static final NodeClass<FloatingReadNode> TYPE = NodeClass.create(FloatingReadNode.class);
-
-    @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess;
-
-    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp) {
-        this(object, location, lastLocationAccess, stamp, null, BarrierType.NONE);
-    }
-
-    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard) {
-        this(object, location, lastLocationAccess, stamp, guard, BarrierType.NONE);
-    }
-
-    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
-        super(TYPE, object, location, stamp, guard, barrierType);
-        this.lastLocationAccess = lastLocationAccess;
-    }
-
-    public MemoryNode getLastLocationAccess() {
-        return lastLocationAccess;
-    }
-
-    public void setLastLocationAccess(MemoryNode newlla) {
-        updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(newlla));
-        lastLocationAccess = newlla;
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
-        LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp());
-        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, null));
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
-            return new FloatingReadNode(((PiNode) object()).getOriginalNode(), location(), getLastLocationAccess(), stamp(), getGuard(), getBarrierType());
-        }
-        return ReadNode.canonicalizeRead(this, location(), object(), tool);
-    }
-
-    @Override
-    public FixedAccessNode asFixedNode() {
-        return graph().add(new ReadNode(object(), accessLocation(), stamp(), getGuard(), getBarrierType()));
-    }
-
-    @Override
-    public boolean verify() {
-        MemoryNode lla = getLastLocationAccess();
-        assert lla != null || getLocationIdentity().isImmutable() : "lastLocationAccess of " + this + " shouldn't be null for mutable location identity " + getLocationIdentity();
-        return super.verify();
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -47,10 +48,7 @@
     protected int bci = BytecodeFrame.UNKNOWN_BCI;
 
     public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
-        super(TYPE, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
-        this.arguments = new NodeInputList<>(this, arguments);
-        this.descriptor = descriptor;
-        this.foreignCalls = foreignCalls;
+        this(TYPE, foreignCalls, descriptor, arguments);
     }
 
     public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
@@ -67,9 +65,9 @@
         this.foreignCalls = foreignCalls;
     }
 
-    protected ForeignCallNode(NodeClass<? extends ForeignCallNode> c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
-        super(c, stamp);
-        this.arguments = new NodeInputList<>(this);
+    protected ForeignCallNode(NodeClass<? extends ForeignCallNode> c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
+        super(c, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
+        this.arguments = new NodeInputList<>(this, arguments);
         this.descriptor = descriptor;
         this.foreignCalls = foreignCalls;
     }
@@ -107,6 +105,12 @@
     }
 
     @Override
+    public void setStateAfter(FrameState x) {
+        assert hasSideEffect() || x == null;
+        super.setStateAfter(x);
+    }
+
+    @Override
     public FrameState stateDuring() {
         return stateDuring;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java	Thu May 28 17:44:05 2015 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java	Thu May 28 17:44:05 2015 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Thu May 28 17:44:05 2015 +0200
@@ -65,7 +65,7 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
+        if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
             return;
         }
         tool.getLowerer().lower(this, tool);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Thu May 28 17:44:05 2015 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * This interface marks nodes that access some memory location, and that have an edge to the last
- * node that kills this location.
- */
-public interface MemoryAccess {
-
-    LocationIdentity getLocationIdentity();
-
-    MemoryNode getLastLocationAccess();
-
-    /**
-     * @param lla the {@link MemoryNode} that represents the last kill of the location
-     */
-    void setLastLocationAccess(MemoryNode lla);
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAnchorNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodeinfo.StructuralInput.Memory;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-@NodeInfo(allowedUsageTypes = {InputType.Memory})
-public final class MemoryAnchorNode extends FixedWithNextNode implements LIRLowerable, MemoryNode, Canonicalizable {
-
-    public static final NodeClass<MemoryAnchorNode> TYPE = NodeClass.create(MemoryAnchorNode.class);
-
-    public MemoryAnchorNode() {
-        super(TYPE, StampFactory.forVoid());
-    }
-
-    public void generate(NodeLIRBuilderTool generator) {
-        // Nothing to emit, since this node is used for structural purposes only.
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        return tool.allUsagesAvailable() && hasNoUsages() ? null : this;
-    }
-
-    @NodeIntrinsic
-    public static native Memory anchor();
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * This interface marks subclasses of {@link FixedNode} that kill a set of memory locations
- * represented by location identities (i.e. change a value at one or more locations that belong to
- * these location identities).
- */
-public interface MemoryCheckpoint extends MemoryNode {
-
-    FixedNode asNode();
-
-    interface Single extends MemoryCheckpoint {
-
-        /**
-         * This method is used to determine which memory location is killed by this node. Returning
-         * the special value {@link LocationIdentity#any()} will kill all memory locations.
-         *
-         * @return the identity of the location killed by this node.
-         */
-        LocationIdentity getLocationIdentity();
-
-    }
-
-    interface Multi extends MemoryCheckpoint {
-
-        /**
-         * This method is used to determine which set of memory locations is killed by this node.
-         * Returning the special value {@link LocationIdentity#any()} will kill all memory
-         * locations.
-         *
-         * @return the identities of all locations killed by this node.
-         */
-        LocationIdentity[] getLocationIdentities();
-
-    }
-
-    public class TypeAssertion {
-
-        public static boolean correctType(Node node) {
-            return !(node instanceof MemoryCheckpoint) || (node instanceof MemoryCheckpoint.Single ^ node instanceof MemoryCheckpoint.Multi);
-        }
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * This interface marks nodes that are part of the memory graph.
- */
-public interface MemoryNode extends NodeInterface {
-
-    ValueNode asNode();
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorExit.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorExit.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.nodes.memory.*;
+
 /**
  * Denotes monitor unlocking transition.
  */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-
-/**
- * Reads an {@linkplain FixedAccessNode accessed} value.
- */
-@NodeInfo
-public final class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, PiPushable, Virtualizable, GuardingNode {
-
-    public static final NodeClass<ReadNode> TYPE = NodeClass.create(ReadNode.class);
-
-    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
-        super(TYPE, object, location, stamp, null, barrierType);
-    }
-
-    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
-        super(TYPE, object, location, stamp, guard, barrierType);
-    }
-
-    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
-        super(TYPE, object, location, stamp, guard, barrierType, nullCheck, stateBefore);
-    }
-
-    public ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType) {
-        /*
-         * Used by node intrinsics. Really, you can trust me on that! Since the initial value for
-         * location is a parameter, i.e., a ParameterNode, the constructor cannot use the declared
-         * type LocationNode.
-         */
-        super(TYPE, object, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType);
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
-        LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp());
-        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, gen.state(this)));
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (tool.allUsagesAvailable() && hasNoUsages()) {
-            if (getGuard() != null && !(getGuard() instanceof FixedNode)) {
-                // The guard is necessary even if the read goes away.
-                return new ValueAnchorNode((ValueNode) getGuard());
-            } else {
-                // Read without usages or guard can be safely removed.
-                return null;
-            }
-        }
-        if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
-            return new ReadNode(((PiNode) object()).getOriginalNode(), location(), stamp(), getGuard(), getBarrierType(), getNullCheck(), stateBefore());
-        }
-        if (!getNullCheck()) {
-            return canonicalizeRead(this, location(), object(), tool);
-        } else {
-            // if this read is a null check, then replacing it with the value is incorrect for
-            // guard-type usages
-            return this;
-        }
-    }
-
-    @Override
-    public FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess) {
-        return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), getGuard(), getBarrierType()));
-    }
-
-    @Override
-    public boolean isAllowedUsageType(InputType type) {
-        return (getNullCheck() && type == InputType.Guard) ? true : super.isAllowedUsageType(type);
-    }
-
-    public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool) {
-        MetaAccessProvider metaAccess = tool.getMetaAccess();
-        if (tool.canonicalizeReads()) {
-            if (metaAccess != null && object != null && object.isConstant() && !object.isNullConstant()) {
-                if ((location.getLocationIdentity().isImmutable()) && location instanceof ConstantLocationNode) {
-                    long displacement = ((ConstantLocationNode) location).getDisplacement();
-                    Constant constant = read.stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), object.asConstant(), displacement);
-                    if (constant != null) {
-                        return ConstantNode.forConstant(read.stamp(), constant, metaAccess);
-                    }
-                }
-            }
-            if (location.getLocationIdentity().equals(LocationIdentity.ARRAY_LENGTH_LOCATION)) {
-                ValueNode length = GraphUtil.arrayLength(object);
-                if (length != null) {
-                    // TODO Does this need a PiCastNode to the positive range?
-                    return length;
-                }
-            }
-        }
-        return read;
-    }
-
-    @Override
-    public boolean push(PiNode parent) {
-        if (!(location() instanceof ConstantLocationNode && parent.stamp() instanceof ObjectStamp && parent.object().stamp() instanceof ObjectStamp)) {
-            return false;
-        }
-
-        ObjectStamp piStamp = (ObjectStamp) parent.stamp();
-        ResolvedJavaType receiverType = piStamp.type();
-        if (receiverType == null) {
-            return false;
-        }
-        ConstantLocationNode constantLocationNode = (ConstantLocationNode) location();
-        ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(constantLocationNode.getDisplacement(), constantLocationNode.getKind());
-        if (field == null) {
-            // field was not declared by receiverType
-            return false;
-        }
-
-        ObjectStamp valueStamp = (ObjectStamp) parent.object().stamp();
-        ResolvedJavaType valueType = StampTool.typeOrNull(valueStamp);
-        if (valueType != null && field.getDeclaringClass().isAssignableFrom(valueType)) {
-            if (piStamp.nonNull() == valueStamp.nonNull() && piStamp.alwaysNull() == valueStamp.alwaysNull()) {
-                replaceFirstInput(parent, parent.object());
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        throw GraalInternalError.shouldNotReachHere("unexpected ReadNode before PEA");
-    }
-
-    public boolean canNullCheck() {
-        return true;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Thu May 28 17:44:05 2015 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Thu May 28 17:44:05 2015 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.LocationNode.Location;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * Writes a given {@linkplain #value() value} a {@linkplain FixedAccessNode memory location}.
- */
-@NodeInfo
-public final class WriteNode extends AbstractWriteNode implements LIRLowerable, Simplifiable, Virtualizable {
-
-    public static final NodeClass<WriteNode> TYPE = NodeClass.create(WriteNode.class);
-
-    public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) {
-        super(TYPE, object, value, location, barrierType);
-    }
-
-    public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) {
-        super(TYPE, object, value, location, barrierType, initialization);
-    }
-
-    public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) {
-        super(TYPE, object, value, location, barrierType, guard, initialization);
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
-        LIRKind writeKind = gen.getLIRGeneratorTool().getLIRKind(value().stamp());
-        gen.getLIRGeneratorTool().emitStore(writeKind, address, gen.operand(value()), gen.state(this));
-    }
-
-    @Override
-    public void simplify(SimplifierTool tool) {
-        if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
-            setObject(((PiNode) object()).getOriginalNode());
-        }
-    }
-
-    @NodeIntrinsic
-    public static native void writeMemory(Object object, Object value, Location location, @ConstantNodeParameter BarrierType barrierType);
-
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        throw GraalInternalError.shouldNotReachHere("unexpected WriteNode before PEA");
-    }
-
-    public boolean canNullCheck() {
-        return true;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * 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,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 
 /**
  * The {@code AccessMonitorNode} is the base class of both monitor acquisition and release.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Thu May 28 17:44:05 2015 +0200
@@ -41,7 +41,7 @@
  * Implements a type check against a compile-time known type.
  */
 @NodeInfo
-public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Simplifiable, Lowerable, Virtualizable, ValueProxy {
+public class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Simplifiable, Lowerable, Virtualizable, ValueProxy {
 
     public static final NodeClass<CheckCastNode> TYPE = NodeClass.create(CheckCastNode.class);
     @Input protected ValueNode object;
@@ -55,7 +55,11 @@
     protected final boolean forStoreCheck;
 
     public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) {
-        super(TYPE, StampFactory.declaredTrusted(type));
+        this(TYPE, type, object, profile, forStoreCheck);
+    }
+
+    protected CheckCastNode(NodeClass<? extends CheckCastNode> c, ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) {
+        super(c, StampFactory.declaredTrusted(type));
         assert object.stamp() instanceof ObjectStamp : object + ":" + object.stamp();
         assert type != null;
         this.type = type;
@@ -178,7 +182,7 @@
         return this;
     }
 
-    private static ValueNode findSynonym(ResolvedJavaType type, ValueNode object) {
+    protected static ValueNode findSynonym(ResolvedJavaType type, ValueNode object) {
         ResolvedJavaType objectType = StampTool.typeOrNull(object);
         if (objectType != null && type.isAssignableFrom(objectType)) {
             // we don't have to check for null types here because they will also pass the
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * 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,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * 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,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Thu May 28 17:44:05 2015 +0200
@@ -36,14 +36,18 @@
  * The {@code InstanceOfNode} represents an instanceof test.
  */
 @NodeInfo
-public final class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
+public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
     public static final NodeClass<InstanceOfNode> TYPE = NodeClass.create(InstanceOfNode.class);
 
     protected final ResolvedJavaType type;
     protected JavaTypeProfile profile;
 
     public InstanceOfNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
-        super(TYPE, object);
+        this(TYPE, type, object, profile);
+    }
+
+    protected InstanceOfNode(NodeClass<? extends InstanceOfNode> c, ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
+        super(c, object);
         this.type = type;
         this.profile = profile;
         assert type != null;
@@ -128,7 +132,7 @@
                 return LogicConstantNode.contradiction();
             } else {
                 boolean superType = inputType.isAssignableFrom(type);
-                if (!superType && !isInterfaceOrArrayOfInterface(inputType) && !isInterfaceOrArrayOfInterface(type)) {
+                if (!superType && (type.asExactType() != null || (!isInterfaceOrArrayOfInterface(inputType) && !isInterfaceOrArrayOfInterface(type)))) {
                     return LogicConstantNode.contradiction();
                 }
                 // since the subtype comparison was only performed on a declared type we don't
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java	Thu May 28 17:44:05 2015 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Thu May 28 17:44:05 2015 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Thu May 28 17:44:05 2015 +0200
@@ -175,7 +175,7 @@
              * interface methods calls.
              */
             if (declaredReceiverType.isInterface()) {
-                tryCheckCastSingleImplementor(receiver, declaredReceiverType);
+                tryCheckCastSingleImplementor(graph().getAssumptions(), receiver, declaredReceiverType);
             }
 
             if (receiver instanceof UncheckedInterfaceProvider) {
@@ -184,14 +184,22 @@
                 if (uncheckedStamp != null) {
                     ResolvedJavaType uncheckedReceiverType = StampTool.typeOrNull(uncheckedStamp);
                     if (uncheckedReceiverType.isInterface()) {
-                        tryCheckCastSingleImplementor(receiver, uncheckedReceiverType);
+                        tryCheckCastSingleImplementor(graph().getAssumptions(), receiver, uncheckedReceiverType);
                     }
                 }
             }
         }
     }
 
-    private void tryCheckCastSingleImplementor(ValueNode receiver, ResolvedJavaType declaredReceiverType) {
+    private void tryCheckCastSingleImplementor(Assumptions assumptions, ValueNode receiver, ResolvedJavaType declaredReceiverType) {
+        if (assumptions == null) {
+            /*
+             * Even though we are not registering an assumption (see comment below), the
+             * optimization is only valid when speculative optimizations are enabled.
+             */
+            return;
+        }
+
         ResolvedJavaType singleImplementor = declaredReceiverType.getSingleImplementor();
         if (singleImplementor != null && !singleImplementor.equals(declaredReceiverType)) {
             ResolvedJavaMethod singleImplementorMethod = singleImplementor.resolveMethod(targetMethod(), invoke().getContextType(), true);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Thu May 28 17:44:05 2015 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Thu May 28 17:44:05 2015 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Thu May 28 17:44:05 2015 +0200
@@ -37,13 +37,17 @@
  * The {@code NewInstanceNode} represents the allocation of an instance class object.
  */
 @NodeInfo(nameTemplate = "New {p#instanceClass/s}")
-public final class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation {
+public class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation {
 
     public static final NodeClass<NewInstanceNode> TYPE = NodeClass.create(NewInstanceNode.class);
     protected final ResolvedJavaType instanceClass;
 
     public NewInstanceNode(ResolvedJavaType type, boolean fillContents) {
-        super(TYPE, StampFactory.exactNonNull(type), fillContents);
+        this(TYPE, type, fillContents);
+    }
+
+    protected NewInstanceNode(NodeClass<? extends NewInstanceNode> c, ResolvedJavaType type, boolean fillContents) {
+        super(c, StampFactory.exactNonNull(type), fillContents);
         assert !type.isArray() && !type.isInterface() && !type.isPrimitive();
         this.instanceClass = type;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Thu May 28 17:44:05 2015 +0200
@@ -33,7 +33,7 @@
  * The {@code NewMultiArrayNode} represents an allocation of a multi-dimensional object array.
  */
 @NodeInfo
-public final class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider {
+public class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider {
 
     public static final NodeClass<NewMultiArrayNode> TYPE = NodeClass.create(NewMultiArrayNode.class);
     @Input protected NodeInputList<ValueNode> dimensions;
@@ -52,7 +52,11 @@
     }
 
     public NewMultiArrayNode(ResolvedJavaType type, ValueNode[] dimensions) {
-        super(TYPE, StampFactory.exactNonNull(type));
+        this(TYPE, type, dimensions);
+    }
+
+    protected NewMultiArrayNode(NodeClass<? extends NewMultiArrayNode> c, ResolvedJavaType type, ValueNode[] dimensions) {
+        super(c, StampFactory.exactNonNull(type));
         this.type = type;
         this.dimensions = new NodeInputList<>(this, dimensions);
         assert dimensions.length > 0 && type.isArray();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Thu May 28 17:44:05 2015 +0200
@@ -68,10 +68,14 @@
         ObjectStamp objectStamp = (ObjectStamp) object.stamp();
         if (objectStamp.isExactType()) {
             return objectStamp.type().hasFinalizer();
-        } else if (objectStamp.type() != null && assumptions != null) {
+        } else if (objectStamp.type() != null) {
             AssumptionResult<Boolean> result = objectStamp.type().hasFinalizableSubclass();
-            assumptions.record(result);
-            return result.getResult();
+            if (result.isAssumptionFree()) {
+                return result.getResult();
+            } else if (assumptions != null) {
+                assumptions.record(result);
+                return result.getResult();
+            }
         }
         return true;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Thu May 28 17:44:05 2015 +0200
@@ -166,7 +166,7 @@
             if (objectType != null) {
                 ResolvedJavaType instanceofType = type;
                 if (instanceofType.equals(objectType)) {
-                    if (objectStamp.nonNull()) {
+                    if (objectStamp.nonNull() && (objectStamp.isExactType() || objectType.isFinal())) {
                         return TriState.TRUE;
                     }
                 } else {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/AbstractMemoryCheckpoint.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Provides an implementation of {@link StateSplit}.
+ */
+@NodeInfo
+public abstract class AbstractMemoryCheckpoint extends AbstractStateSplit implements MemoryCheckpoint {
+
+    public static final NodeClass<AbstractMemoryCheckpoint> TYPE = NodeClass.create(AbstractMemoryCheckpoint.class);
+
+    protected AbstractMemoryCheckpoint(NodeClass<? extends AbstractMemoryCheckpoint> c, Stamp stamp) {
+        this(c, stamp, null);
+    }
+
+    protected AbstractMemoryCheckpoint(NodeClass<? extends AbstractMemoryCheckpoint> c, Stamp stamp, FrameState stateAfter) {
+        super(c, stamp, stateAfter);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/AbstractWriteNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
+public abstract class AbstractWriteNode extends FixedAccessNode implements StateSplit, MemoryCheckpoint.Single, MemoryAccess, GuardingNode {
+
+    public static final NodeClass<AbstractWriteNode> TYPE = NodeClass.create(AbstractWriteNode.class);
+    @Input ValueNode value;
+    @OptionalInput(InputType.State) FrameState stateAfter;
+    @OptionalInput(InputType.Memory) Node lastLocationAccess;
+
+    protected final boolean initialization;
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    /**
+     * Returns whether this write is the initialization of the written location. If it is true, the
+     * old value of the memory location is either uninitialized or zero. If it is false, the memory
+     * location is guaranteed to contain a valid value or zero.
+     */
+    public boolean isInitialization() {
+        return initialization;
+    }
+
+    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) {
+        this(c, object, value, location, barrierType, false);
+    }
+
+    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) {
+        super(c, object, location, StampFactory.forVoid(), barrierType);
+        this.value = value;
+        this.initialization = initialization;
+    }
+
+    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) {
+        super(c, object, location, StampFactory.forVoid(), guard, barrierType, false, null);
+        this.value = value;
+        this.initialization = initialization;
+    }
+
+    @Override
+    public boolean isAllowedUsageType(InputType type) {
+        return (type == InputType.Guard && getNullCheck()) ? true : super.isAllowedUsageType(type);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return location().getLocationIdentity();
+    }
+
+    public MemoryNode getLastLocationAccess() {
+        return (MemoryNode) lastLocationAccess;
+    }
+
+    public void setLastLocationAccess(MemoryNode lla) {
+        Node newLla = ValueNodeUtil.asNode(lla);
+        updateUsages(lastLocationAccess, newLla);
+        lastLocationAccess = newLla;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/Access.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+public interface Access extends GuardedNode, HeapAccess {
+
+    ValueNode object();
+
+    LocationNode accessLocation();
+
+    boolean canNullCheck();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FixedAccessNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * Accesses a value at an memory address specified by an {@linkplain #object object} and a
+ * {@linkplain #accessLocation() location}. The access does not include a null check on the object.
+ */
+@NodeInfo
+public abstract class FixedAccessNode extends DeoptimizingFixedWithNextNode implements Access {
+    public static final NodeClass<FixedAccessNode> TYPE = NodeClass.create(FixedAccessNode.class);
+
+    @OptionalInput(InputType.Guard) protected GuardingNode guard;
+    @Input protected ValueNode object;
+    @Input(InputType.Association) protected ValueNode location;
+    protected boolean nullCheck;
+    protected BarrierType barrierType;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    protected void setObject(ValueNode x) {
+        updateUsages(object, x);
+        object = x;
+    }
+
+    public LocationNode location() {
+        return (LocationNode) location;
+    }
+
+    public LocationNode accessLocation() {
+        return (LocationNode) location;
+    }
+
+    public boolean getNullCheck() {
+        return nullCheck;
+    }
+
+    public void setNullCheck(boolean check) {
+        this.nullCheck = check;
+    }
+
+    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, ValueNode object, ValueNode location, Stamp stamp) {
+        this(c, object, location, stamp, BarrierType.NONE);
+    }
+
+    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
+        this(c, object, location, stamp, null, barrierType, false, null);
+    }
+
+    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck,
+                    FrameState stateBefore) {
+        super(c, stamp, stateBefore);
+        this.object = object;
+        this.location = location;
+        this.guard = guard;
+        this.barrierType = barrierType;
+        this.nullCheck = nullCheck;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return nullCheck;
+    }
+
+    @Override
+    public GuardingNode getGuard() {
+        return guard;
+    }
+
+    @Override
+    public void setGuard(GuardingNode guard) {
+        updateUsagesInterface(this.guard, guard);
+        this.guard = guard;
+    }
+
+    @Override
+    public BarrierType getBarrierType() {
+        return barrierType;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatableAccessNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * An {@link FixedAccessNode} that can be converted to a {@link FloatingAccessNode}.
+ */
+@NodeInfo
+public abstract class FloatableAccessNode extends FixedAccessNode {
+    public static final NodeClass<FloatableAccessNode> TYPE = NodeClass.create(FloatableAccessNode.class);
+
+    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, ValueNode object, ValueNode location, Stamp stamp) {
+        super(c, object, location, stamp);
+    }
+
+    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(c, object, location, stamp, guard, barrierType, false, null);
+    }
+
+    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck,
+                    FrameState stateBefore) {
+        super(c, object, location, stamp, guard, barrierType, nullCheck, stateBefore);
+    }
+
+    public abstract FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess);
+
+    protected boolean forceFixed;
+
+    public void setForceFixed(boolean flag) {
+        this.forceFixed = flag;
+    }
+
+    /**
+     * AccessNodes can float only if their location identities are not ANY_LOCATION. Furthermore, in
+     * case G1 is enabled any access (read) to the java.lang.ref.Reference.referent field which has
+     * an attached write barrier with pre-semantics can not also float.
+     */
+    public boolean canFloat() {
+        return !forceFixed && location().getLocationIdentity().isSingle() && getBarrierType() == BarrierType.NONE;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatingAccessNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+@NodeInfo
+public abstract class FloatingAccessNode extends FloatingGuardedNode implements Access, MemoryAccess {
+    public static final NodeClass<FloatingAccessNode> TYPE = NodeClass.create(FloatingAccessNode.class);
+
+    @Input ValueNode object;
+    @Input(InputType.Association) LocationNode location;
+    protected BarrierType barrierType;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public LocationNode location() {
+        return location;
+    }
+
+    public LocationNode accessLocation() {
+        return location;
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return location.getLocationIdentity();
+    }
+
+    protected FloatingAccessNode(NodeClass<? extends FloatingAccessNode> c, ValueNode object, LocationNode location, Stamp stamp) {
+        super(c, stamp);
+        this.object = object;
+        this.location = location;
+    }
+
+    protected FloatingAccessNode(NodeClass<? extends FloatingAccessNode> c, ValueNode object, LocationNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(c, stamp, guard);
+        this.object = object;
+        this.location = location;
+        this.barrierType = barrierType;
+    }
+
+    @Override
+    public BarrierType getBarrierType() {
+        return barrierType;
+    }
+
+    public boolean canNullCheck() {
+        return true;
+    }
+
+    public abstract FixedAccessNode asFixedNode();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatingReadNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * A floating read of a value from memory specified in terms of an object base and an object
+ * relative location. This node does not null check the object.
+ */
+@NodeInfo
+public final class FloatingReadNode extends FloatingAccessNode implements LIRLowerable, Canonicalizable {
+    public static final NodeClass<FloatingReadNode> TYPE = NodeClass.create(FloatingReadNode.class);
+
+    @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess;
+
+    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp) {
+        this(object, location, lastLocationAccess, stamp, null, BarrierType.NONE);
+    }
+
+    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard) {
+        this(object, location, lastLocationAccess, stamp, guard, BarrierType.NONE);
+    }
+
+    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(TYPE, object, location, stamp, guard, barrierType);
+        this.lastLocationAccess = lastLocationAccess;
+    }
+
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    public void setLastLocationAccess(MemoryNode newlla) {
+        updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(newlla));
+        lastLocationAccess = newlla;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
+        LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp());
+        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, null));
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
+            return new FloatingReadNode(((PiNode) object()).getOriginalNode(), location(), getLastLocationAccess(), stamp(), getGuard(), getBarrierType());
+        }
+        return ReadNode.canonicalizeRead(this, location(), object(), tool);
+    }
+
+    @Override
+    public FixedAccessNode asFixedNode() {
+        return graph().add(new ReadNode(object(), accessLocation(), stamp(), getGuard(), getBarrierType()));
+    }
+
+    @Override
+    public boolean verify() {
+        MemoryNode lla = getLastLocationAccess();
+        assert lla != null || getLocationIdentity().isImmutable() : "lastLocationAccess of " + this + " shouldn't be null for mutable location identity " + getLocationIdentity();
+        return super.verify();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/HeapAccess.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+/**
+ * Encapsulates properties of a node describing how it accesses the heap.
+ */
+public interface HeapAccess {
+
+    /**
+     * The types of (write/read) barriers attached to stores.
+     */
+    public enum BarrierType {
+        /**
+         * Primitive stores which do not necessitate barriers.
+         */
+        NONE,
+        /**
+         * Array object stores which necessitate precise barriers.
+         */
+        PRECISE,
+        /**
+         * Field object stores which necessitate imprecise barriers.
+         */
+        IMPRECISE
+    }
+
+    /**
+     * Gets the write barrier type for that particular access.
+     */
+    BarrierType getBarrierType();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryAccess.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * This interface marks nodes that access some memory location, and that have an edge to the last
+ * node that kills this location.
+ */
+public interface MemoryAccess {
+
+    LocationIdentity getLocationIdentity();
+
+    MemoryNode getLastLocationAccess();
+
+    /**
+     * @param lla the {@link MemoryNode} that represents the last kill of the location
+     */
+    void setLastLocationAccess(MemoryNode lla);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryAnchorNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodeinfo.StructuralInput.Memory;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
+public final class MemoryAnchorNode extends FixedWithNextNode implements LIRLowerable, MemoryNode, Canonicalizable {
+
+    public static final NodeClass<MemoryAnchorNode> TYPE = NodeClass.create(MemoryAnchorNode.class);
+
+    public MemoryAnchorNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    public void generate(NodeLIRBuilderTool generator) {
+        // Nothing to emit, since this node is used for structural purposes only.
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        return tool.allUsagesAvailable() && hasNoUsages() ? null : this;
+    }
+
+    @NodeIntrinsic
+    public static native Memory anchor();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryCheckpoint.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * This interface marks subclasses of {@link FixedNode} that kill a set of memory locations
+ * represented by location identities (i.e. change a value at one or more locations that belong to
+ * these location identities).
+ */
+public interface MemoryCheckpoint extends MemoryNode {
+
+    FixedNode asNode();
+
+    interface Single extends MemoryCheckpoint {
+
+        /**
+         * This method is used to determine which memory location is killed by this node. Returning
+         * the special value {@link LocationIdentity#any()} will kill all memory locations.
+         *
+         * @return the identity of the location killed by this node.
+         */
+        LocationIdentity getLocationIdentity();
+
+    }
+
+    interface Multi extends MemoryCheckpoint {
+
+        /**
+         * This method is used to determine which set of memory locations is killed by this node.
+         * Returning the special value {@link LocationIdentity#any()} will kill all memory
+         * locations.
+         *
+         * @return the identities of all locations killed by this node.
+         */
+        LocationIdentity[] getLocationIdentities();
+
+    }
+
+    public class TypeAssertion {
+
+        public static boolean correctType(Node node) {
+            return !(node instanceof MemoryCheckpoint) || (node instanceof MemoryCheckpoint.Single ^ node instanceof MemoryCheckpoint.Multi);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryMap.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Maps a {@linkplain LocationIdentity location} to the last node that (potentially) wrote to the
+ * location.
+ */
+public interface MemoryMap {
+
+    /**
+     * Gets the last node that that (potentially) wrote to {@code locationIdentity}.
+     */
+    MemoryNode getLastLocationAccess(LocationIdentity locationIdentity);
+
+    /**
+     * Gets the location identities in the domain of this map.
+     */
+    Collection<LocationIdentity> getLocations();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryMapNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo(allowedUsageTypes = {InputType.Extension, InputType.Memory})
+public final class MemoryMapNode extends FloatingNode implements MemoryMap, MemoryNode, LIRLowerable {
+
+    public static final NodeClass<MemoryMapNode> TYPE = NodeClass.create(MemoryMapNode.class);
+    protected final List<LocationIdentity> locationIdentities;
+    @Input(InputType.Memory) NodeInputList<ValueNode> nodes;
+
+    private boolean checkOrder(Map<LocationIdentity, MemoryNode> mmap) {
+        for (int i = 0; i < locationIdentities.size(); i++) {
+            LocationIdentity locationIdentity = locationIdentities.get(i);
+            ValueNode n = nodes.get(i);
+            assertTrue(mmap.get(locationIdentity) == n, "iteration order of keys differs from values in input map");
+        }
+        return true;
+    }
+
+    public MemoryMapNode(Map<LocationIdentity, MemoryNode> mmap) {
+        super(TYPE, StampFactory.forVoid());
+        locationIdentities = new ArrayList<>(mmap.keySet());
+        nodes = new NodeInputList<>(this, mmap.values());
+        assert checkOrder(mmap);
+    }
+
+    public boolean isEmpty() {
+        if (locationIdentities.isEmpty()) {
+            return true;
+        }
+        if (locationIdentities.size() == 1) {
+            if (nodes.get(0) instanceof StartNode) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) {
+        if (locationIdentity.isImmutable()) {
+            return null;
+        } else {
+            int index = locationIdentities.indexOf(locationIdentity);
+            if (index == -1) {
+                index = locationIdentities.indexOf(any());
+            }
+            assert index != -1;
+            return (MemoryNode) nodes.get(index);
+        }
+    }
+
+    public Collection<LocationIdentity> getLocations() {
+        return locationIdentities;
+    }
+
+    public Map<LocationIdentity, MemoryNode> toMap() {
+        HashMap<LocationIdentity, MemoryNode> res = CollectionsFactory.newMap(locationIdentities.size());
+        for (int i = 0; i < nodes.size(); i++) {
+            res.put(locationIdentities.get(i), (MemoryNode) nodes.get(i));
+        }
+        return res;
+    }
+
+    public void generate(NodeLIRBuilderTool generator) {
+        // nothing to do...
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * This interface marks nodes that are part of the memory graph.
+ */
+public interface MemoryNode extends NodeInterface {
+
+    ValueNode asNode();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryPhiNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Memory {@code PhiNode}s merge memory dependencies at control flow merges.
+ */
+@NodeInfo(nameTemplate = "\u03D5({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory})
+public final class MemoryPhiNode extends PhiNode implements MemoryNode {
+
+    public static final NodeClass<MemoryPhiNode> TYPE = NodeClass.create(MemoryPhiNode.class);
+    @Input(InputType.Memory) NodeInputList<ValueNode> values;
+    protected final LocationIdentity locationIdentity;
+
+    public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity) {
+        super(TYPE, StampFactory.forVoid(), merge);
+        this.locationIdentity = locationIdentity;
+        this.values = new NodeInputList<>(this);
+    }
+
+    public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity, ValueNode[] values) {
+        super(TYPE, StampFactory.forVoid(), merge);
+        this.locationIdentity = locationIdentity;
+        this.values = new NodeInputList<>(this, values);
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    @Override
+    public NodeInputList<ValueNode> values() {
+        return values;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/ReadNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+
+/**
+ * Reads an {@linkplain FixedAccessNode accessed} value.
+ */
+@NodeInfo
+public final class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, PiPushable, Virtualizable, GuardingNode {
+
+    public static final NodeClass<ReadNode> TYPE = NodeClass.create(ReadNode.class);
+
+    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
+        super(TYPE, object, location, stamp, null, barrierType);
+    }
+
+    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(TYPE, object, location, stamp, guard, barrierType);
+    }
+
+    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
+        super(TYPE, object, location, stamp, guard, barrierType, nullCheck, stateBefore);
+    }
+
+    public ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType) {
+        /*
+         * Used by node intrinsics. Really, you can trust me on that! Since the initial value for
+         * location is a parameter, i.e., a ParameterNode, the constructor cannot use the declared
+         * type LocationNode.
+         */
+        super(TYPE, object, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
+        LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp());
+        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, gen.state(this)));
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            if (getGuard() != null && !(getGuard() instanceof FixedNode)) {
+                // The guard is necessary even if the read goes away.
+                return new ValueAnchorNode((ValueNode) getGuard());
+            } else {
+                // Read without usages or guard can be safely removed.
+                return null;
+            }
+        }
+        if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
+            return new ReadNode(((PiNode) object()).getOriginalNode(), location(), stamp(), getGuard(), getBarrierType(), getNullCheck(), stateBefore());
+        }
+        if (!getNullCheck()) {
+            return canonicalizeRead(this, location(), object(), tool);
+        } else {
+            // if this read is a null check, then replacing it with the value is incorrect for
+            // guard-type usages
+            return this;
+        }
+    }
+
+    @Override
+    public FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess) {
+        return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), getGuard(), getBarrierType()));
+    }
+
+    @Override
+    public boolean isAllowedUsageType(InputType type) {
+        return (getNullCheck() && type == InputType.Guard) ? true : super.isAllowedUsageType(type);
+    }
+
+    public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool) {
+        MetaAccessProvider metaAccess = tool.getMetaAccess();
+        if (tool.canonicalizeReads()) {
+            if (metaAccess != null && object != null && object.isConstant() && !object.isNullConstant() && location instanceof ConstantLocationNode) {
+                long displacement = ((ConstantLocationNode) location).getDisplacement();
+                if ((location.getLocationIdentity().isImmutable())) {
+                    Constant constant = read.stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), object.asConstant(), displacement);
+                    if (constant != null) {
+                        return ConstantNode.forConstant(read.stamp(), constant, metaAccess);
+                    }
+                }
+
+                Constant constant = tool.getConstantReflection().readConstantArrayElementForOffset(object.asJavaConstant(), displacement);
+                if (constant != null) {
+                    return ConstantNode.forConstant(read.stamp(), constant, metaAccess);
+                }
+            }
+            if (location.getLocationIdentity().equals(LocationIdentity.ARRAY_LENGTH_LOCATION)) {
+                ValueNode length = GraphUtil.arrayLength(object);
+                if (length != null) {
+                    // TODO Does this need a PiCastNode to the positive range?
+                    return length;
+                }
+            }
+        }
+        return read;
+    }
+
+    @Override
+    public boolean push(PiNode parent) {
+        if (!(location() instanceof ConstantLocationNode && parent.stamp() instanceof ObjectStamp && parent.object().stamp() instanceof ObjectStamp)) {
+            return false;
+        }
+
+        ObjectStamp piStamp = (ObjectStamp) parent.stamp();
+        ResolvedJavaType receiverType = piStamp.type();
+        if (receiverType == null) {
+            return false;
+        }
+        ConstantLocationNode constantLocationNode = (ConstantLocationNode) location();
+        ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(constantLocationNode.getDisplacement(), constantLocationNode.getKind());
+        if (field == null) {
+            // field was not declared by receiverType
+            return false;
+        }
+
+        ObjectStamp valueStamp = (ObjectStamp) parent.object().stamp();
+        ResolvedJavaType valueType = StampTool.typeOrNull(valueStamp);
+        if (valueType != null && field.getDeclaringClass().isAssignableFrom(valueType)) {
+            if (piStamp.nonNull() == valueStamp.nonNull() && piStamp.alwaysNull() == valueStamp.alwaysNull()) {
+                replaceFirstInput(parent, parent.object());
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        throw GraalInternalError.shouldNotReachHere("unexpected ReadNode before PEA");
+    }
+
+    public boolean canNullCheck() {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/WriteNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.memory;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.Location;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Writes a given {@linkplain #value() value} a {@linkplain FixedAccessNode memory location}.
+ */
+@NodeInfo
+public final class WriteNode extends AbstractWriteNode implements LIRLowerable, Simplifiable, Virtualizable {
+
+    public static final NodeClass<WriteNode> TYPE = NodeClass.create(WriteNode.class);
+
+    public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) {
+        super(TYPE, object, value, location, barrierType);
+    }
+
+    public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) {
+        super(TYPE, object, value, location, barrierType, initialization);
+    }
+
+    public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) {
+        super(TYPE, object, value, location, barrierType, guard, initialization);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
+        LIRKind writeKind = gen.getLIRGeneratorTool().getLIRKind(value().stamp());
+        gen.getLIRGeneratorTool().emitStore(writeKind, address, gen.operand(value()), gen.state(this));
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
+            setObject(((PiNode) object()).getOriginalNode());
+        }
+    }
+
+    @NodeIntrinsic
+    public static native void writeMemory(Object object, Object value, Location location, @ConstantNodeParameter BarrierType barrierType);
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        throw GraalInternalError.shouldNotReachHere("unexpected WriteNode before PEA");
+    }
+
+    public boolean canNullCheck() {
+        return true;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryProxy.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryProxy.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 package com.oracle.graal.nodes.spi;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 
 public interface MemoryProxy extends Proxy, MemoryNode {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Thu May 28 17:44:05 2015 +0200
@@ -123,11 +123,6 @@
     Collection<ResolvedJavaMethod> getAllReplacements();
 
     /**
-     * Determines whether the replacement of this method is flagged as being inlined always.
-     */
-    boolean isForcedSubstitution(ResolvedJavaMethod methodAt);
-
-    /**
      * Register snippet templates.
      */
     void registerSnippetTemplateCache(SnippetTemplateCache snippetTemplates);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Thu May 28 17:44:05 2015 +0200
@@ -33,14 +33,18 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]")
-public final class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider {
+public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider {
 
     public static final NodeClass<VirtualArrayNode> TYPE = NodeClass.create(VirtualArrayNode.class);
     protected final ResolvedJavaType componentType;
     protected final int length;
 
     public VirtualArrayNode(ResolvedJavaType componentType, int length) {
-        super(TYPE, componentType.getArrayClass(), true);
+        this(TYPE, componentType, length);
+    }
+
+    protected VirtualArrayNode(NodeClass<? extends VirtualObjectNode> c, ResolvedJavaType componentType, int length) {
+        super(c, componentType.getArrayClass(), true);
         this.componentType = componentType;
         this.length = length;
     }
--- a/graal/com.oracle.graal.options.processor/src/com/oracle/graal/options/processor/GraalJars.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.options.processor/src/com/oracle/graal/options/processor/GraalJars.java	Thu May 28 17:44:05 2015 +0200
@@ -1,10 +1,3 @@
-package com.oracle.graal.options.processor;
-
-import java.io.*;
-import java.util.*;
-import java.util.stream.*;
-import java.util.zip.*;
-
 /*
  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -27,6 +20,13 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+package com.oracle.graal.options.processor;
+
+import java.io.*;
+import java.util.*;
+import java.util.stream.*;
+import java.util.zip.*;
+
 public class GraalJars implements Iterable<ZipEntry> {
     private final List<ZipFile> jars = new ArrayList<>(2);
 
@@ -60,4 +60,4 @@
         }
         return null;
     }
-}
\ No newline at end of file
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -134,9 +134,6 @@
     }
 
     private void visitDeoptBegin(AbstractBeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, StructuredGraph graph) {
-        if (!deoptAction.doesInvalidateCompilation()) {
-            return;
-        }
         if (deoptBegin instanceof AbstractMergeNode) {
             AbstractMergeNode mergeNode = (AbstractMergeNode) deoptBegin;
             Debug.log("Visiting %s", mergeNode);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -36,6 +36,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.util.*;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu May 28 17:44:05 2015 +0200
@@ -53,12 +53,6 @@
 public class InliningUtil {
 
     private static final String inliningDecisionsScopeString = "InliningDecisions";
-    /**
-     * Meters the size (in bytecodes) of all methods processed during compilation (i.e., top level
-     * and all inlined methods), irrespective of how many bytecodes in each method are actually
-     * parsed (which may be none for methods whose IR is retrieved from a cache).
-     */
-    public static final DebugMetric InlinedBytecodes = Debug.metric("InlinedBytecodes");
 
     /**
      * Print a HotSpot-style inlining message to the console.
@@ -321,7 +315,7 @@
             unwindNode = (UnwindNode) duplicates.get(unwindNode);
         }
 
-        finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph.getInlinedMethods(), canonicalizedNodes);
+        finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph, canonicalizedNodes);
 
         GraphUtil.killCFG(invokeNode);
 
@@ -329,7 +323,7 @@
     }
 
     public static ValueNode finishInlining(Invoke invoke, StructuredGraph graph, FixedNode firstNode, List<ReturnNode> returnNodes, UnwindNode unwindNode, Assumptions inlinedAssumptions,
-                    Set<ResolvedJavaMethod> inlinedMethods, List<Node> canonicalizedNodes) {
+                    StructuredGraph inlineGraph, List<Node> canonicalizedNodes) {
         FixedNode invokeNode = invoke.asNode();
         FrameState stateAfter = invoke.stateAfter();
         assert stateAfter == null || stateAfter.isAlive();
@@ -401,9 +395,7 @@
         }
 
         // Copy inlined methods from inlinee to caller
-        if (inlinedMethods != null && graph.getInlinedMethods() != null) {
-            graph.getInlinedMethods().addAll(inlinedMethods);
-        }
+        graph.updateInlinedMethods(inlineGraph);
 
         return returnValue;
     }
@@ -427,11 +419,18 @@
     }
 
     public static BytecodePosition processSimpleInfopoint(Invoke invoke, SimpleInfopointNode infopointNode, BytecodePosition incomingPos) {
-        BytecodePosition pos = incomingPos != null ? incomingPos : new BytecodePosition(toBytecodePosition(invoke.stateAfter().outerFrameState()), invoke.asNode().graph().method(), invoke.bci());
+        BytecodePosition pos = processBytecodePosition(invoke, incomingPos);
         infopointNode.addCaller(pos);
+        assert infopointNode.verify();
         return pos;
     }
 
+    public static BytecodePosition processBytecodePosition(Invoke invoke, BytecodePosition incomingPos) {
+        assert invoke.stateAfter() != null;
+        assert incomingPos == null || incomingPos.equals(InliningUtil.processBytecodePosition(invoke, null)) : incomingPos + " " + InliningUtil.processBytecodePosition(invoke, null);
+        return incomingPos != null ? incomingPos : new BytecodePosition(FrameState.toBytecodePosition(invoke.stateAfter().outerFrameState()), invoke.stateAfter().method(), invoke.bci());
+    }
+
     public static void processMonitorId(FrameState stateAfter, MonitorIdNode monitorIdNode) {
         if (stateAfter != null) {
             int callerLockDepth = stateAfter.nestedLockDepth();
@@ -439,13 +438,6 @@
         }
     }
 
-    private static BytecodePosition toBytecodePosition(FrameState fs) {
-        if (fs == null) {
-            return null;
-        }
-        return new BytecodePosition(toBytecodePosition(fs.outerFrameState()), fs.method(), fs.bci);
-    }
-
     protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map<Node, Node> duplicates, FrameState stateAtExceptionEdge, boolean alwaysDuplicateStateAfter) {
         FrameState stateAtReturn = invoke.stateAfter();
         FrameState outerFrameState = null;
@@ -468,14 +460,28 @@
         Kind invokeReturnKind = invoke.asNode().getKind();
 
         if (frameState.bci == BytecodeFrame.AFTER_BCI) {
+            FrameState stateAfterReturn = stateAtReturn;
+            if (frameState.method() == null) {
+                // This is a frame state for a side effect within an intrinsic
+                // that was parsed for post-parse intrinsification
+                for (Node usage : frameState.usages()) {
+                    if (usage instanceof ForeignCallNode) {
+                        // A foreign call inside an intrinsic needs to have
+                        // the BCI of the invoke being intrinsified
+                        ForeignCallNode foreign = (ForeignCallNode) usage;
+                        foreign.setBci(invoke.bci());
+                    }
+                }
+            }
+
             /*
              * pop return kind from invoke's stateAfter and replace with this frameState's return
              * value (top of stack)
              */
-            FrameState stateAfterReturn = stateAtReturn;
-            if (invokeReturnKind != Kind.Void && (alwaysDuplicateStateAfter || (frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)))) {
+            if (frameState.stackSize() > 0 && (alwaysDuplicateStateAfter || stateAfterReturn.stackAt(0) != frameState.stackAt(0))) {
                 stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0));
             }
+
             frameState.replaceAndDelete(stateAfterReturn);
             return stateAfterReturn;
         } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) {
@@ -527,8 +533,11 @@
                 // in the intrinsic code.
                 assert inlinedMethod.getAnnotation(MethodSubstitution.class) != null : "expected an intrinsic when inlinee frame state matches method of call target but does not match the method of the inlinee graph: " +
                                 frameState;
+            } else if (frameState.method().getName().equals(inlinedMethod.getName())) {
+                // This can happen for method substitutions.
             } else {
-                throw new AssertionError(frameState.toString());
+                throw new AssertionError(String.format("inlinedMethod=%s frameState.method=%s frameState=%s invoke.method=%s", inlinedMethod, frameState.method(), frameState,
+                                invoke.callTarget().targetMethod()));
             }
         }
         return true;
@@ -581,25 +590,26 @@
         ValueNode singleReturnValue = null;
         PhiNode returnValuePhi = null;
         for (ReturnNode returnNode : returnNodes) {
-            if (returnNode.result() != null) {
-                if (returnValuePhi == null && (singleReturnValue == null || singleReturnValue == returnNode.result())) {
+            ValueNode result = returnNode.result();
+            if (result != null) {
+                if (returnValuePhi == null && (singleReturnValue == null || singleReturnValue == result)) {
                     /* Only one return value, so no need yet for a phi node. */
-                    singleReturnValue = returnNode.result();
+                    singleReturnValue = result;
 
                 } else if (returnValuePhi == null) {
                     /* Found a second return value, so create phi node. */
-                    returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(returnNode.result().stamp().unrestricted(), merge));
+                    returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(result.stamp().unrestricted(), merge));
                     if (canonicalizedNodes != null) {
                         canonicalizedNodes.add(returnValuePhi);
                     }
                     for (int i = 0; i < merge.forwardEndCount(); i++) {
                         returnValuePhi.addInput(singleReturnValue);
                     }
-                    returnValuePhi.addInput(returnNode.result());
+                    returnValuePhi.addInput(result);
 
                 } else {
                     /* Multiple return values, just add to existing phi node. */
-                    returnValuePhi.addInput(returnNode.result());
+                    returnValuePhi.addInput(result);
                 }
             }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Thu May 28 17:44:05 2015 +0200
@@ -57,11 +57,8 @@
         Map<Node, Node> duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck, canonicalizeNodes);
         getInlinedParameterUsages(canonicalizeNodes, calleeGraph, duplicateMap);
 
-        InliningUtil.InlinedBytecodes.add(concrete.getCodeSize());
         StructuredGraph graph = invoke.asNode().graph();
-        if (graph.isInlinedMethodRecordingEnabled()) {
-            graph.getInlinedMethods().add(concrete);
-        }
+        graph.recordInlinedMethod(concrete);
         return canonicalizeNodes;
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Thu May 28 17:44:05 2015 +0200
@@ -61,7 +61,7 @@
     public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) {
         StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph(), invoke.bci());
         // TODO copying the graph is only necessary if it is modified or if it contains any invokes
-        this.graph = original.copy();
+        this.graph = (StructuredGraph) original.copy();
         specializeGraphToArguments(invoke, context, canonicalizer);
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java	Thu May 28 17:44:05 2015 +0200
@@ -78,9 +78,6 @@
             if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i), info.invoke().bci())) {
                 return false;
             }
-            if (!replacements.isForcedSubstitution(info.methodAt(i))) {
-                return false;
-            }
         }
         return true;
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Thu May 28 17:44:05 2015 +0200
@@ -117,7 +117,7 @@
             return "it is an abstract method";
         } else if (!method.getDeclaringClass().isInitialized()) {
             return "the method's class is not initialized";
-        } else if (!method.canBeInlined() && !context.getReplacements().isForcedSubstitution(method)) {
+        } else if (!method.canBeInlined()) {
             return "it is marked non-inlinable";
         } else if (countRecursiveInlining(method) > MaximumRecursiveInlining.getValue()) {
             return "it exceeds the maximum recursive inlining depth";
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java	Thu May 28 17:44:05 2015 +0200
@@ -70,6 +70,31 @@
         return false;
     }
 
+    /**
+     * Removes the first instance of the given phase class, looking recursively into inner phase
+     * suites.
+     */
+    public boolean removePhase(Class<? extends BasePhase<? super C>> phaseClass) {
+        ListIterator<BasePhase<? super C>> it = phases.listIterator();
+        while (it.hasNext()) {
+            BasePhase<? super C> phase = it.next();
+            if (phaseClass.isInstance(phase)) {
+                it.remove();
+                return true;
+            } else if (phase instanceof PhaseSuite) {
+                @SuppressWarnings("unchecked")
+                PhaseSuite<C> innerSuite = (PhaseSuite<C>) phase;
+                if (innerSuite.removePhase(phaseClass)) {
+                    if (innerSuite.phases.isEmpty()) {
+                        it.remove();
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     @Override
     protected void run(StructuredGraph graph, C context) {
         for (BasePhase<? super C> phase : phases) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java	Thu May 28 17:44:05 2015 +0200
@@ -30,7 +30,7 @@
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Thu May 28 17:44:05 2015 +0200
@@ -33,7 +33,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.phases.*;
 
 import edu.umd.cs.findbugs.annotations.*;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Thu May 28 17:44:05 2015 +0200
@@ -362,6 +362,9 @@
         } else if (obj instanceof Graph) {
             writeByte(PROPERTY_SUBGRAPH);
             writeGraph((Graph) obj);
+        } else if (obj instanceof CachedGraph) {
+            writeByte(PROPERTY_SUBGRAPH);
+            writeGraph(((CachedGraph<?>) obj).getReadonlyCopy());
         } else if (obj != null && obj.getClass().isArray()) {
             Class<?> componentType = obj.getClass().getComponentType();
             if (componentType.isPrimitive()) {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DynamicNewArrayTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DynamicNewArrayTest.java	Thu May 28 17:44:05 2015 +0200
@@ -55,6 +55,7 @@
     @Test
     public void test4() {
         test("dynamic", Boolean.class, -7);
+        test("dynamicSynchronized", Boolean.class, -7);
     }
 
     @Test
@@ -95,4 +96,8 @@
     public static Object dynamic(Class<?> elementType, int length) {
         return Array.newInstance(elementType, length);
     }
+
+    public static synchronized Object dynamicSynchronized(Class<?> elementType, int length) {
+        return Array.newInstance(elementType, length);
+    }
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Thu May 28 17:44:05 2015 +0200
@@ -412,4 +412,23 @@
         test("arrayCopyTypeName", (Object) new Object[]{"one", "two", "three"});
         test("arrayCopyTypeName", (Object) new String[]{"one", "two", "three"});
     }
+
+    public int conditionalInstantiation(Object o) {
+        int total = 0;
+        if (o instanceof CharSequence) {
+            if (o instanceof StringBuilder || o instanceof String) {
+                total = 9;
+            }
+            total += (o instanceof String ? 2 : 1);
+        }
+
+        return total;
+    }
+
+    @Test
+    public void testInstantiation() {
+        test("conditionalInstantiation", "foo");
+        test("conditionalInstantiation", new StringBuilder());
+        test("conditionalInstantiation", 1);
+    }
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Thu May 28 17:44:05 2015 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.word.*;
 
 /**
@@ -50,7 +49,7 @@
 
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null);
     }
 
     @Test
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PEGraphDecoderTest.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.memory.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.replacements.*;
+
+public class PEGraphDecoderTest extends GraalCompilerTest {
+
+    /**
+     * This method is intrinsified to a node with a guard dependency on the block it is in. The
+     * various tests ensure that this guard is correctly updated when blocks are merged during
+     * inlining.
+     */
+    private static native int readInt(Object obj, long offset);
+
+    private static boolean flag;
+    private static int value;
+
+    private static void invokeSimple() {
+        value = 111;
+    }
+
+    private static void invokeComplicated() {
+        if (flag) {
+            value = 0;
+        } else {
+            value = 42;
+        }
+    }
+
+    private static int readInt1(Object obj) {
+        return readInt(obj, 16);
+    }
+
+    private static int readInt2(Object obj) {
+        invokeSimple();
+        return readInt(obj, 16);
+    }
+
+    private static int readInt3(Object obj) {
+        invokeComplicated();
+        return readInt(obj, 16);
+    }
+
+    private static int readInt4(Object obj, int n) {
+        if (n > 0) {
+            invokeComplicated();
+        }
+        return readInt(obj, 16);
+    }
+
+    public static int doTest(Object obj) {
+        int result = 0;
+        result += readInt1(obj);
+        result += readInt2(obj);
+        result += readInt3(obj);
+        result += readInt4(obj, 2);
+        return result;
+    }
+
+    private static void registerPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, PEGraphDecoderTest.class);
+        r.register2("readInt", Object.class, long.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, MethodIdMap.Receiver unused, ValueNode obj, ValueNode offset) {
+                LocationNode location = b.add(new ConstantLocationNode(LocationIdentity.any(), offset.asJavaConstant().asLong()));
+                ReadNode read = b.addPush(Kind.Int, new ReadNode(obj, location, StampFactory.forKind(Kind.Int), BarrierType.NONE));
+                read.setGuard(AbstractBeginNode.prevBegin(read));
+                return true;
+            }
+        });
+    }
+
+    class InlineAll implements InlineInvokePlugin {
+        @Override
+        public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+            return new InlineInfo(method, false);
+        }
+    }
+
+    @Test
+    public void test() {
+        ResolvedJavaMethod testMethod = getResolvedJavaMethod(PEGraphDecoderTest.class, "doTest", Object.class);
+        StructuredGraph targetGraph = null;
+        try (Debug.Scope scope = Debug.scope("GraphPETest", testMethod)) {
+            GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault(getDefaultGraphBuilderPlugins());
+            registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins());
+            CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES, getTarget().arch);
+
+            targetGraph = new StructuredGraph(testMethod, AllowAssumptions.YES);
+            decoder.decode(targetGraph, testMethod, null, null, new InlineAll(), null);
+            Debug.dump(targetGraph, "Target Graph");
+            targetGraph.verify();
+
+            PhaseContext context = new PhaseContext(getProviders());
+            new CanonicalizerPhase().apply(targetGraph, context);
+            targetGraph.verify();
+
+        } catch (Throwable ex) {
+            if (targetGraph != null) {
+                Debug.dump(targetGraph, ex.toString());
+            }
+            Debug.handle(ex);
+        }
+    }
+}
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Thu May 28 17:44:05 2015 +0200
@@ -35,7 +35,6 @@
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.word.*;
 import com.oracle.graal.word.nodes.*;
 
@@ -56,7 +55,7 @@
 
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java	Thu May 28 17:44:05 2015 +0200
@@ -39,6 +39,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 
 public class SubstitutionsTest extends GraalCompilerTest {
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Thu May 28 17:44:05 2015 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.word.*;
 
 /**
@@ -45,7 +44,7 @@
 
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,240 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.replacements;
-
-import static com.oracle.graal.api.code.BytecodeFrame.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.graph.*;
-import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo;
-import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
-
-/**
- * This phase ensures that there's a single {@linkplain BytecodeFrame#AFTER_BCI collapsed frame
- * state} per path.
- *
- * Removes other frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes
- * in the graph, and replaces them with {@linkplain BytecodeFrame#INVALID_FRAMESTATE_BCI invalid
- * frame states}.
- *
- * The invalid frame states ensure that no deoptimization to a snippet frame state will happen.
- */
-public class CollapseFrameForSingleSideEffectPhase extends Phase {
-
-    private static class IterationState {
-        public final IterationState previous;
-        public final Node node;
-        public final Collection<IterationState> merge;
-        public final boolean invalid;
-
-        private IterationState(IterationState previous, Node node, Collection<IterationState> merge, boolean invalid) {
-            this.previous = previous;
-            this.node = node;
-            this.merge = merge;
-            this.invalid = invalid;
-        }
-
-        public IterationState() {
-            this(null, null, null, false);
-        }
-
-        public IterationState addSideEffect(StateSplit sideEffect) {
-            return new IterationState(this, sideEffect.asNode(), null, true);
-        }
-
-        public IterationState addBranch(AbstractBeginNode begin) {
-            return new IterationState(this, begin, null, this.invalid);
-        }
-
-        public static IterationState merge(AbstractMergeNode merge, Collection<IterationState> before, boolean invalid) {
-            return new IterationState(null, merge, before, invalid);
-        }
-
-        public void markAll(NodeBitMap set) {
-            IterationState state = this;
-            while (state != null && state.node != null && !set.contains(state.node)) {
-                set.mark(state.node);
-                if (state.merge != null) {
-                    for (IterationState branch : state.merge) {
-                        branch.markAll(set);
-                    }
-                }
-                state = state.previous;
-            }
-        }
-
-        public void markMasked(NodeBitMap unmasked, NodeBitMap masked) {
-            IterationState state = this;
-            while (state != null && state.node != null && !masked.contains(state.node)) {
-                if (state.node instanceof StateSplit) {
-                    unmasked.mark(state.node);
-                    StateSplit split = (StateSplit) state.node;
-                    if (split.hasSideEffect() && state.previous != null) {
-                        state.previous.markAll(masked);
-                        return;
-                    }
-                }
-
-                if (state.merge != null) {
-                    for (IterationState branch : state.merge) {
-                        branch.markMasked(unmasked, masked);
-                    }
-                }
-                state = state.previous;
-            }
-        }
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        CollapseFrameForSingleSideEffectClosure closure = new CollapseFrameForSingleSideEffectClosure();
-        ReentrantNodeIterator.apply(closure, graph.start(), new IterationState());
-        closure.finishProcessing(graph);
-    }
-
-    private static class CollapseFrameForSingleSideEffectClosure extends NodeIteratorClosure<IterationState> {
-
-        private List<IterationState> returnStates = new ArrayList<>();
-        private List<IterationState> unwindStates = new ArrayList<>();
-
-        @Override
-        protected IterationState processNode(FixedNode node, IterationState currentState) {
-            IterationState state = currentState;
-            if (node instanceof StateSplit) {
-                StateSplit stateSplit = (StateSplit) node;
-                FrameState frameState = stateSplit.stateAfter();
-                if (frameState != null) {
-                    if (stateSplit.hasSideEffect()) {
-                        setStateAfter(node.graph(), stateSplit, INVALID_FRAMESTATE_BCI, false);
-                        state = state.addSideEffect(stateSplit);
-                    } else if (currentState.invalid) {
-                        setStateAfter(node.graph(), stateSplit, INVALID_FRAMESTATE_BCI, false);
-                    } else if (stateSplit instanceof StartNode) {
-                        setStateAfter(node.graph(), stateSplit, BEFORE_BCI, false);
-                    } else {
-                        stateSplit.setStateAfter(null);
-                        if (frameState.hasNoUsages()) {
-                            GraphUtil.killWithUnusedFloatingInputs(frameState);
-                        }
-                    }
-                }
-            }
-            if (node instanceof ReturnNode) {
-                returnStates.add(currentState);
-            } else if (node instanceof UnwindNode) {
-                unwindStates.add(currentState);
-            }
-            return state;
-        }
-
-        @Override
-        protected IterationState merge(AbstractMergeNode merge, List<IterationState> states) {
-            boolean invalid = false;
-            for (IterationState state : states) {
-                if (state.invalid) {
-                    invalid = true;
-                    break;
-                }
-            }
-            return IterationState.merge(merge, states, invalid);
-        }
-
-        public void finishProcessing(StructuredGraph graph) {
-            NodeBitMap maskedSideEffects = new NodeBitMap(graph);
-            NodeBitMap returnSideEffects = new NodeBitMap(graph);
-            NodeBitMap unwindSideEffects = new NodeBitMap(graph);
-
-            for (IterationState returnState : returnStates) {
-                returnState.markMasked(returnSideEffects, maskedSideEffects);
-            }
-            for (IterationState unwindState : unwindStates) {
-                unwindState.markMasked(unwindSideEffects, maskedSideEffects);
-            }
-
-            for (Node returnSideEffect : returnSideEffects) {
-                if (!unwindSideEffects.contains(returnSideEffect) && !maskedSideEffects.contains(returnSideEffect)) {
-                    StateSplit split = (StateSplit) returnSideEffect;
-                    setStateAfter(graph, split, AFTER_BCI, true);
-                }
-            }
-
-            for (Node unwindSideEffect : unwindSideEffects) {
-                if (!returnSideEffects.contains(unwindSideEffect) && !maskedSideEffects.contains(unwindSideEffect)) {
-                    StateSplit split = (StateSplit) unwindSideEffect;
-                    setStateAfter(graph, split, AFTER_EXCEPTION_BCI, true);
-                }
-            }
-        }
-
-        @Override
-        protected IterationState afterSplit(AbstractBeginNode node, IterationState oldState) {
-            return oldState.addBranch(node);
-        }
-
-        @Override
-        protected Map<LoopExitNode, IterationState> processLoop(LoopBeginNode loop, IterationState initialState) {
-            LoopInfo<IterationState> info = ReentrantNodeIterator.processLoop(this, loop, initialState);
-
-            boolean isNowInvalid = initialState.invalid;
-            for (IterationState endState : info.endStates.values()) {
-                isNowInvalid |= endState.invalid;
-            }
-
-            if (isNowInvalid) {
-                setStateAfter(loop.graph(), loop, INVALID_FRAMESTATE_BCI, false);
-            }
-
-            IterationState endState = IterationState.merge(loop, info.endStates.values(), isNowInvalid);
-            return ReentrantNodeIterator.processLoop(this, loop, endState).exitStates;
-        }
-
-        /**
-         * Creates and sets a special frame state for a node. If the existing frame state is
-         * non-null and has no other usages, it is deleted via
-         * {@link GraphUtil#killWithUnusedFloatingInputs(Node)}.
-         *
-         * @param graph the graph context
-         * @param node the node whose frame state is updated
-         * @param bci {@link BytecodeFrame#BEFORE_BCI}, {@link BytecodeFrame#AFTER_EXCEPTION_BCI} or
-         *            {@link BytecodeFrame#INVALID_FRAMESTATE_BCI}
-         * @param replaceOnly only perform the update if the node currently has a non-null frame
-         *            state
-         */
-        private static void setStateAfter(StructuredGraph graph, StateSplit node, int bci, boolean replaceOnly) {
-            assert (bci == BEFORE_BCI && node instanceof StartNode) || bci == AFTER_BCI || bci == AFTER_EXCEPTION_BCI || bci == INVALID_FRAMESTATE_BCI;
-            FrameState currentStateAfter = node.stateAfter();
-            if (currentStateAfter != null || !replaceOnly) {
-                node.setStateAfter(graph.add(new FrameState(bci)));
-                if (currentStateAfter != null && currentStateAfter.hasNoUsages()) {
-                    GraphUtil.killWithUnusedFloatingInputs(currentStateAfter);
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Thu May 28 17:44:05 2015 +0200
@@ -73,9 +73,9 @@
     }
 
     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
-        if (b.parsingReplacement() && wordOperationPlugin.apply(b, method, args)) {
+        if (b.parsingIntrinsic() && wordOperationPlugin.apply(b, method, args)) {
             return true;
-        } else if (b.parsingReplacement()) {
+        } else if (b.parsingIntrinsic()) {
             NodeIntrinsic intrinsic = nodeIntrinsification.getIntrinsic(method);
             if (intrinsic != null) {
                 Signature sig = method.getSignature();
@@ -145,12 +145,18 @@
             b.add(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity()));
             return true;
         } else if (res instanceof ForeignCallNode) {
-            ForeignCallNode foreign = (ForeignCallNode) res;
-            foreign.setBci(b.bci());
+            /*
+             * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the
+             * case that the foreign call can deoptimize. As with all deoptimization, we need a
+             * state in a non-intrinsic method.
+             */
+            GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor();
+            if (nonIntrinsicAncestor != null) {
+                ForeignCallNode foreign = (ForeignCallNode) res;
+                foreign.setBci(nonIntrinsicAncestor.bci());
+            }
         }
 
-        res = b.add(res);
-
         boolean nonValueType = false;
         if (returnKind == Kind.Object && stamp instanceof ObjectStamp) {
             ResolvedJavaType type = ((ObjectStamp) stamp).type();
@@ -162,16 +168,10 @@
 
         if (returnKind != Kind.Void) {
             assert nonValueType || res.getKind().getStackKind() != Kind.Void;
-            b.push(returnKind.getStackKind(), res);
+            res = b.addPush(returnKind.getStackKind(), res);
         } else {
             assert res.getKind().getStackKind() == Kind.Void;
-        }
-
-        if (res instanceof StateSplit) {
-            StateSplit stateSplit = (StateSplit) res;
-            if (stateSplit.stateAfter() == null) {
-                stateSplit.setStateAfter(b.createStateAfter());
-            }
+            res = b.add(res);
         }
 
         return true;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java	Thu May 28 17:44:05 2015 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.replacements;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graphbuilderconf.*;
@@ -39,8 +39,9 @@
     public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
         InlineInfo inlineInfo = replacements.getInlineInfo(b, method, args, returnType);
         if (inlineInfo == null) {
-            if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
-                return new InlineInfo(method, false, false);
+            if (InlineDuringParsing.getValue() && method.hasBytecodes() && !method.isSynchronized() && method.getCode().length <= TrivialInliningSize.getValue() &&
+                            b.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
+                return new InlineInfo(method, false);
             }
         }
         return inlineInfo;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,11 +38,12 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
+import com.oracle.graal.nodes.memory.HeapAccess.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
@@ -143,13 +144,8 @@
         ValueNode object = storeField.isStatic() ? staticFieldBase(graph, field) : storeField.object();
         ValueNode value = implicitStoreConvert(graph, storeField.field().getKind(), storeField.value());
         ConstantLocationNode location = createFieldLocation(graph, field, false);
+        assert location != null;
 
-        if (location == null) {
-            /* Field has been eliminated, so no write necessary. */
-            assert !storeField.isVolatile() : "missing memory barriers";
-            graph.removeFixed(storeField);
-            return;
-        }
         WriteNode memoryWrite = graph.add(new WriteNode(object, value, location, fieldStoreBarrierType(storeField.field())));
         memoryWrite.setStateAfter(storeField.stateAfter());
         graph.replaceFixedWithFixed(storeField, memoryWrite);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Thu May 28 17:44:05 2015 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.replacements;
 
+import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*;
+
 import java.lang.reflect.*;
 import java.util.*;
 
@@ -89,7 +91,7 @@
     }
 
     public <T extends ValueNode> T changeToWord(T node) {
-        if (wordTypes.isWord(node)) {
+        if (wordTypes != null && wordTypes.isWord(node)) {
             node.setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(node)));
         }
         return node;
@@ -123,8 +125,13 @@
      * @param name the name of the invoked method
      * @param args the arguments to the invocation
      */
-    public InvokeNode createInvoke(Class<?> declaringClass, String name, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+    public InvokeNode createInvoke(Class<?> declaringClass, String name, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
         boolean isStatic = invokeKind == InvokeKind.Static;
+        ResolvedJavaMethod method = findMethod(declaringClass, name, isStatic);
+        return createInvoke(method, invokeKind, frameStateBuilder, bci, args);
+    }
+
+    public ResolvedJavaMethod findMethod(Class<?> declaringClass, String name, boolean isStatic) {
         ResolvedJavaMethod method = null;
         for (Method m : declaringClass.getDeclaredMethods()) {
             if (Modifier.isStatic(m.getModifiers()) == isStatic && m.getName().equals(name)) {
@@ -133,14 +140,14 @@
             }
         }
         assert method != null : "did not find method in " + declaringClass + " named " + name;
-        return createInvoke(method, invokeKind, frameStateBuilder, bci, args);
+        return method;
     }
 
     /**
      * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
      * arguments.
      */
-    public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+    public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
         assert method.isStatic() == (invokeKind == InvokeKind.Static);
         Signature signature = method.getSignature();
         JavaType returnType = signature.getReturnType(null);
@@ -152,7 +159,7 @@
             if (invoke.getKind() != Kind.Void) {
                 frameStateBuilder.push(returnType.getKind(), invoke);
             }
-            invoke.setStateAfter(frameStateBuilder.create(bci));
+            invoke.setStateAfter(frameStateBuilder.create(bci, invoke));
             if (invoke.getKind() != Kind.Void) {
                 frameStateBuilder.pop(returnType.getKind());
             }
@@ -179,12 +186,14 @@
         }
         int argIndex = 0;
         if (!isStatic) {
-            Kind expected = wordTypes.asKind(method.getDeclaringClass());
+            ResolvedJavaType expectedType = method.getDeclaringClass();
+            Kind expected = wordTypes == null ? expectedType.getKind() : wordTypes.asKind(expectedType);
             Kind actual = args[argIndex++].stamp().getStackKind();
             assert expected == actual : graph + ": wrong kind of value for receiver argument of call to " + method + " [" + actual + " != " + expected + "]";
         }
         for (int i = 0; i != signature.getParameterCount(false); i++) {
-            Kind expected = wordTypes.asKind(signature.getParameterType(i, method.getDeclaringClass())).getStackKind();
+            JavaType expectedType = signature.getParameterType(i, method.getDeclaringClass());
+            Kind expected = wordTypes == null ? expectedType.getKind().getStackKind() : wordTypes.asKind(expectedType).getStackKind();
             Kind actual = args[argIndex++].stamp().getStackKind();
             if (expected != actual) {
                 throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of call to " + method + " [" + actual + " != " + expected + "]");
@@ -219,7 +228,7 @@
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
 
         StructuredGraph calleeGraph = new StructuredGraph(method, AllowAssumptions.NO);
-        IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, null, IntrinsicContext.POST_PARSE_INLINE_BCI);
+        IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, INLINE_AFTER_PARSING);
         new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(calleeGraph);
 
         // Remove all frame states from inlinee
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Thu May 28 17:44:05 2015 +0200
@@ -96,7 +96,17 @@
     protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, Instantiation instantiation, Node usage, final StructuredGraph graph) {
         InstanceOfUsageReplacer replacer;
         if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitOrNode || usage instanceof GuardingPiNode || usage instanceof ConditionAnchorNode) {
-            replacer = new NonMaterializationUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, usage);
+            ValueNode trueValue = ConstantNode.forInt(1, graph);
+            ValueNode falseValue = ConstantNode.forInt(0, graph);
+            if (instantiation.isInitialized() && (trueValue != instantiation.trueValue || falseValue != instantiation.falseValue)) {
+                /*
+                 * This code doesn't really care what values are used so adopt the values from the
+                 * previous instantiation.
+                 */
+                trueValue = instantiation.trueValue;
+                falseValue = instantiation.falseValue;
+            }
+            replacer = new NonMaterializationUsageReplacer(instantiation, trueValue, falseValue, instanceOf, usage);
         } else {
             assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage;
             ConditionalNode c = (ConditionalNode) usage;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java	Thu May 28 17:44:05 2015 +0200
@@ -152,8 +152,10 @@
         return graph;
     }
 
-    public FrameState createStateAfter() {
-        return getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI));
+    public void setStateAfter(StateSplit sideEffect) {
+        assert sideEffect.hasSideEffect();
+        FrameState stateAfter = getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI));
+        sideEffect.setStateAfter(stateAfter);
     }
 
     public GraphBuilderContext getParent() {
@@ -180,11 +182,11 @@
         return 0;
     }
 
-    public boolean parsingReplacement() {
+    public boolean parsingIntrinsic() {
         return true;
     }
 
-    public Replacement getReplacement() {
+    public IntrinsicContext getIntrinsic() {
         throw GraalInternalError.shouldNotReachHere();
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandleInvocationPlugin.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.replacements.nodes.*;
+
+public class MethodHandleInvocationPlugin implements GenericInvocationPlugin {
+    private final MethodHandleAccessProvider methodHandleAccess;
+    private final GenericInvocationPlugin delegate;
+
+    public MethodHandleInvocationPlugin(MethodHandleAccessProvider methodHandleAccess, GenericInvocationPlugin delegate) {
+        this.methodHandleAccess = methodHandleAccess;
+        this.delegate = delegate;
+    }
+
+    @Override
+    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        IntrinsicMethod intrinsicMethod = methodHandleAccess.lookupMethodHandleIntrinsic(method);
+        if (intrinsicMethod != null) {
+            InvokeKind invokeKind = b.getInvokeKind();
+            if (invokeKind != InvokeKind.Static) {
+                args[0] = b.nullCheckedValue(args[0]);
+            }
+            JavaType invokeReturnType = b.getInvokeReturnType();
+            InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, method, b.bci(), invokeReturnType, args);
+            if (invoke == null) {
+                MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, method, b.bci(), invokeReturnType, args);
+                if (invokeReturnType.getKind() == Kind.Void) {
+                    b.add(methodHandleNode);
+                } else {
+                    b.addPush(methodHandleNode);
+                }
+            } else {
+                CallTargetNode callTarget = invoke.callTarget();
+                NodeInputList<ValueNode> argumentsList = callTarget.arguments();
+                ValueNode[] newArgs = argumentsList.toArray(new ValueNode[argumentsList.size()]);
+                for (ValueNode arg : newArgs) {
+                    b.recursiveAppend(arg);
+                }
+                b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), newArgs);
+            }
+            return true;
+        }
+        return delegate.apply(b, method, args);
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Thu May 28 17:44:05 2015 +0200
@@ -120,7 +120,7 @@
         return true;
     }
 
-    @SuppressWarnings("serial") public static final JavaConstant COULD_NOT_FOLD = new PrimitiveConstant(Kind.Illegal, 100) {
+    public static final JavaConstant COULD_NOT_FOLD = new PrimitiveConstant(Kind.Illegal, 100) {
         @Override
         public boolean equals(Object o) {
             return this == o;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Thu May 28 17:44:05 2015 +0200
@@ -23,13 +23,14 @@
 package com.oracle.graal.replacements;
 
 import static com.oracle.graal.compiler.common.GraalInternalError.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
 
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.graphbuilderconf.*;
@@ -97,6 +98,15 @@
         public boolean isInlinedMethod() {
             return caller != null;
         }
+
+        public BytecodePosition getBytecodePosition() {
+            if (bytecodePosition == null) {
+                ensureOuterStateDecoded(this);
+                ensureExceptionStateDecoded(this);
+                bytecodePosition = InliningUtil.processBytecodePosition(invokeData.invoke, null);
+            }
+            return bytecodePosition;
+        }
     }
 
     protected class PENonAppendGraphBuilderContext implements GraphBuilderContext {
@@ -139,7 +149,7 @@
         }
 
         @Override
-        public Replacement getReplacement() {
+        public IntrinsicContext getIntrinsic() {
             return null;
         }
 
@@ -169,7 +179,7 @@
         }
 
         @Override
-        public FrameState createStateAfter() {
+        public void setStateAfter(StateSplit stateSplit) {
             throw unimplemented();
         }
 
@@ -217,10 +227,11 @@
         }
 
         @Override
-        public FrameState createStateAfter() {
+        public void setStateAfter(StateSplit stateSplit) {
             Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
             getGraph().add(stateAfter);
-            return (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter);
+            FrameState fs = (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter);
+            stateSplit.setStateAfter(fs);
         }
 
         @Override
@@ -379,7 +390,7 @@
             if (graphBuilderContext.lastInstr != null) {
                 registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true);
                 invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode);
-                graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData));
+                graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(graphBuilderContext.lastInstr)));
             } else {
                 assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?";
                 invoke.asNode().replaceAtUsages(null);
@@ -411,7 +422,7 @@
         if (inlineInfo == null) {
             return false;
         }
-        assert !inlineInfo.isIntrinsic && !inlineInfo.isReplacement : "not supported";
+        assert !inlineInfo.isIntrinsic : "not supported";
 
         ResolvedJavaMethod inlineMethod = inlineInfo.methodToInline;
         EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod);
@@ -458,16 +469,16 @@
         ValueNode returnValue;
         List<ReturnNode> returnNodes = inlineScope.returnNodes;
         if (!returnNodes.isEmpty()) {
-            FixedNode n;
-            n = nodeAfterInvoke(methodScope, loopScope, invokeData);
             if (returnNodes.size() == 1) {
                 ReturnNode returnNode = returnNodes.get(0);
                 returnValue = returnNode.result();
+                FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(returnNode));
                 returnNode.replaceAndDelete(n);
             } else {
                 AbstractMergeNode merge = methodScope.graph.add(new MergeNode());
                 merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId));
                 returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
+                FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, merge);
                 merge.setNext(n);
             }
         } else {
@@ -484,17 +495,24 @@
             registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true);
         }
         if (inlineScope.exceptionPlaceholderNode != null) {
-            inlineScope.exceptionPlaceholderNode.replaceAndDelete(exceptionValue);
+            inlineScope.exceptionPlaceholderNode.replaceAtUsages(exceptionValue);
+            inlineScope.exceptionPlaceholderNode.safeDelete();
         }
         deleteInvoke(invoke);
 
         methodScope.inlineInvokePlugin.postInline(inlineMethod);
+
+        if (Debug.isDumpEnabled() && DumpDuringGraphBuilding.getValue()) {
+            Debug.dump(methodScope.graph, "Inline finished: " + inlineMethod.getDeclaringClass().getUnqualifiedName() + "." + inlineMethod.getName());
+        }
         return true;
     }
 
-    public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData) {
+    public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, AbstractBeginNode lastBlock) {
+        assert lastBlock.isAlive();
         FixedNode n;
         if (invokeData.invoke instanceof InvokeWithExceptionNode) {
+            registerNode(loopScope, invokeData.nextOrderId, lastBlock, false, false);
             n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId);
         } else {
             n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId);
@@ -518,6 +536,15 @@
     protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method);
 
     @Override
+    protected void handleFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) {
+        PEMethodScope methodScope = (PEMethodScope) s;
+        if (node instanceof SimpleInfopointNode && methodScope.isInlinedMethod()) {
+            InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.getBytecodePosition());
+        }
+        super.handleFixedNode(s, loopScope, nodeOrderId, node);
+    }
+
+    @Override
     protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) {
         PEMethodScope methodScope = (PEMethodScope) s;
 
@@ -590,11 +617,7 @@
         PEMethodScope methodScope = (PEMethodScope) s;
 
         if (methodScope.isInlinedMethod()) {
-            if (node instanceof SimpleInfopointNode) {
-                methodScope.bytecodePosition = InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.bytecodePosition);
-                return node;
-
-            } else if (node instanceof FrameState) {
+            if (node instanceof FrameState) {
                 FrameState frameState = (FrameState) node;
 
                 ensureOuterStateDecoded(methodScope);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -24,7 +24,8 @@
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*;
 import static java.lang.String.*;
 
@@ -45,7 +46,6 @@
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement;
 import com.oracle.graal.java.*;
 import com.oracle.graal.java.GraphBuilderPhase.Instance;
 import com.oracle.graal.nodes.*;
@@ -77,6 +77,10 @@
         this.graphBuilderPlugins = plugins;
     }
 
+    public GraphBuilderConfiguration.Plugins getGraphBuilderPlugins() {
+        return graphBuilderPlugins;
+    }
+
     protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) {
         return method.getAnnotation(Node.NodeIntrinsic.class) != null || method.getAnnotation(Word.Operation.class) != null || method.getAnnotation(Fold.class) != null;
     }
@@ -93,13 +97,13 @@
     public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
         ResolvedJavaMethod subst = getSubstitutionMethod(method);
         if (subst != null) {
-            if (b.parsingReplacement() || InlineDuringParsing.getValue() || InlineIntrinsicsDuringParsing.getValue()) {
+            if (b.parsingIntrinsic() || InlineDuringParsing.getValue() || InlineIntrinsicsDuringParsing.getValue()) {
                 // Forced inlining of intrinsics
-                return new InlineInfo(subst, true, true);
+                return new InlineInfo(subst, true);
             }
             return null;
         }
-        if (b.parsingReplacement()) {
+        if (b.parsingIntrinsic()) {
             assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName());
 
             assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
@@ -110,7 +114,7 @@
             }
 
             // Force inlining when parsing replacements
-            return new InlineInfo(method, true, true);
+            return new InlineInfo(method, true);
         } else {
             assert method.getAnnotation(NodeIntrinsic.class) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(),
                             method.format("%h.%n"), b);
@@ -119,10 +123,10 @@
     }
 
     public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
-        if (b.parsingReplacement()) {
-            Replacement replacement = b.getReplacement();
-            assert replacement.isCallToOriginal(method) : format("All non-recursive calls in the replacement %s must be inlined or intrinsified: found call to %s",
-                            replacement.getReplacementMethod().format("%H.%n(%p)"), method.format("%h.%n(%p)"));
+        if (b.parsingIntrinsic()) {
+            IntrinsicContext intrinsic = b.getIntrinsic();
+            assert intrinsic.isCallToOriginal(method) : format("All non-recursive calls in the intrinsic %s must be inlined or intrinsified: found call to %s",
+                            intrinsic.getIntrinsicMethod().format("%H.%n(%p)"), method.format("%h.%n(%p)"));
         }
     }
 
@@ -131,7 +135,6 @@
      */
     protected class ClassReplacements {
         public final Map<ResolvedJavaMethod, ResolvedJavaMethod> methodSubstitutions = CollectionsFactory.newMap();
-        public final Set<ResolvedJavaMethod> forcedSubstitutions = new HashSet<>();
 
         public ClassReplacements(Class<?>[] substitutionClasses, AtomicReference<ClassReplacements> ref) {
             for (Class<?> substitutionClass : substitutionClasses) {
@@ -168,10 +171,7 @@
                         if (originalMethods != null) {
                             for (Executable originalMethod : originalMethods) {
                                 if (originalMethod != null && (guard == null || guard.execute())) {
-                                    ResolvedJavaMethod original = registerMethodSubstitution(this, originalMethod, substituteMethod);
-                                    if (original != null && methodSubstitution.forced()) {
-                                        forcedSubstitutions.add(original);
-                                    }
+                                    registerMethodSubstitution(this, originalMethod, substituteMethod);
                                 }
                             }
                         }
@@ -299,9 +299,7 @@
         StructuredGraph graph = UseSnippetGraphCache ? graphs.get(method) : null;
         if (graph == null) {
             try (DebugCloseable a = SnippetPreparationTime.start()) {
-                FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal
-                                : FrameStateProcessing.CollapseFrameForSingleSideEffect;
-                StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, frameStateProcessing);
+                StructuredGraph newGraph = makeGraph(method, args, recursiveEntry);
                 Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount());
                 if (!UseSnippetGraphCache || args != null) {
                     return newGraph;
@@ -346,7 +344,7 @@
         }
         StructuredGraph graph = graphs.get(substitute);
         if (graph == null) {
-            graph = makeGraph(substitute, null, original, FrameStateProcessing.None);
+            graph = makeGraph(substitute, null, original);
             graph.freeze();
             graphs.putIfAbsent(substitute, graph);
             graph = graphs.get(substitute);
@@ -445,36 +443,18 @@
      * @param args
      * @param original the original method if {@code method} is a {@linkplain MethodSubstitution
      *            substitution} otherwise null
-     * @param frameStateProcessing controls how {@link FrameState FrameStates} should be handled.
      */
-    public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) {
+    public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original) {
         try (OverrideScope s = OptionValue.override(DeoptALot, false)) {
-            return createGraphMaker(method, original, frameStateProcessing).makeGraph(args);
+            return createGraphMaker(method, original).makeGraph(args);
         }
     }
 
     /**
      * Can be overridden to return an object that specializes various parts of graph preprocessing.
      */
-    protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) {
-        return new GraphMaker(this, substitute, original, frameStateProcessing);
-    }
-
-    /**
-     * Cache to speed up preprocessing of replacement graphs.
-     */
-    final ConcurrentMap<ResolvedJavaMethod, StructuredGraph> graphCache = new ConcurrentHashMap<>();
-
-    public enum FrameStateProcessing {
-        None,
-        /**
-         * @see CollapseFrameForSingleSideEffectPhase
-         */
-        CollapseFrameForSingleSideEffect,
-        /**
-         * Removes frame states from all nodes in the graph.
-         */
-        Removal
+    protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original) {
+        return new GraphMaker(this, substitute, original);
     }
 
     /**
@@ -496,26 +476,16 @@
          */
         protected final ResolvedJavaMethod substitutedMethod;
 
-        /**
-         * Controls how FrameStates are processed.
-         */
-        private FrameStateProcessing frameStateProcessing;
-
-        protected GraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod, FrameStateProcessing frameStateProcessing) {
+        protected GraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod) {
             this.replacements = replacements;
             this.method = substitute;
             this.substitutedMethod = substitutedMethod;
-            this.frameStateProcessing = frameStateProcessing;
         }
 
         public StructuredGraph makeGraph(Object[] args) {
             try (Scope s = Debug.scope("BuildSnippetGraph", method)) {
-                StructuredGraph graph = parseGraph(method, args);
-
-                if (args == null) {
-                    // Cannot have a finalized version of a graph in the cache
-                    graph = graph.copy();
-                }
+                assert method.hasBytecodes() : method;
+                StructuredGraph graph = buildInitialGraph(method, args);
 
                 finalizeGraph(graph);
 
@@ -536,18 +506,6 @@
             new ConvertDeoptimizeToGuardPhase().apply(graph, null);
             assert sideEffectCount == graph.getNodes().filter(e -> hasSideEffect(e)).count() : "deleted side effecting node";
 
-            switch (frameStateProcessing) {
-                case Removal:
-                    for (Node node : graph.getNodes()) {
-                        if (node instanceof StateSplit) {
-                            ((StateSplit) node).setStateAfter(null);
-                        }
-                    }
-                    break;
-                case CollapseFrameForSingleSideEffect:
-                    new CollapseFrameForSingleSideEffectPhase().apply(graph);
-                    break;
-            }
             new DeadCodeEliminationPhase(Required).apply(graph);
         }
 
@@ -580,21 +538,6 @@
             return false;
         }
 
-        private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, Object[] args) {
-            assert methodToParse.hasBytecodes() : methodToParse;
-            if (args != null) {
-                return buildInitialGraph(methodToParse, args);
-            }
-            StructuredGraph graph = replacements.graphCache.get(methodToParse);
-            if (graph == null) {
-                StructuredGraph newGraph = buildInitialGraph(methodToParse, args);
-                replacements.graphCache.putIfAbsent(methodToParse, newGraph);
-                graph = replacements.graphCache.get(methodToParse);
-                assert graph != null;
-            }
-            return graph;
-        }
-
         /**
          * Builds the initial graph for a snippet.
          */
@@ -614,7 +557,19 @@
                 if (args != null) {
                     plugins.setParameterPlugin(new ConstantBindingParameterPlugin(args, plugins.getParameterPlugin(), metaAccess, replacements.snippetReflection));
                 }
-                createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), config, OptimisticOptimizations.NONE).apply(graph);
+
+                IntrinsicContext initialIntrinsicContext = null;
+                if (method.getAnnotation(Snippet.class) == null) {
+                    // Post-parse inlined intrinsic
+                    initialIntrinsicContext = new IntrinsicContext(substitutedMethod, method, INLINE_AFTER_PARSING);
+                } else {
+                    // Snippet
+                    ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method;
+                    initialIntrinsicContext = new IntrinsicContext(original, method, INLINE_AFTER_PARSING);
+                }
+
+                createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialIntrinsicContext).apply(
+                                graph);
 
                 if (OptCanonicalizer.getValue()) {
                     new CanonicalizerPhase().apply(graph, new PhaseContext(replacements.providers));
@@ -626,17 +581,8 @@
         }
 
         protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
-                        OptimisticOptimizations optimisticOpts) {
-            ReplacementContext initialReplacementContext = null;
-            if (method.getAnnotation(Snippet.class) == null) {
-                // Late inlined intrinsic
-                initialReplacementContext = new IntrinsicContext(substitutedMethod, method, null, -1);
-            } else {
-                // Snippet
-                ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method;
-                initialReplacementContext = new ReplacementContext(original, method);
-            }
-            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext);
+                        OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
+            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
         }
     }
 
@@ -713,12 +659,6 @@
         return result;
     }
 
-    @Override
-    public boolean isForcedSubstitution(ResolvedJavaMethod method) {
-        ClassReplacements cr = getClassReplacements(method.getDeclaringClass().getName());
-        return cr != null && cr.forcedSubstitutions.contains(method);
-    }
-
     public boolean hasSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly, int callerBci) {
         if (!fromBytecodeOnly) {
             InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounterNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounterNode.java	Thu May 28 17:44:05 2015 +0200
@@ -22,9 +22,12 @@
  */
 package com.oracle.graal.replacements;
 
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
@@ -35,6 +38,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
+import com.oracle.graal.replacements.Snippet.ConstantParameter;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
@@ -85,6 +89,34 @@
         }
     }
 
+    /**
+     * When {@link #SnippetCounters} are enabled make sure {@link #SNIPPET_COUNTER_LOCATION} is part
+     * of the private locations.
+     *
+     * @param privateLocations
+     * @return a copy of privateLocations with any needed locations added
+     */
+    public static LocationIdentity[] addSnippetCounters(LocationIdentity[] privateLocations) {
+        if (SnippetCounters.getValue()) {
+            for (LocationIdentity location : privateLocations) {
+                if (location.equals(SNIPPET_COUNTER_LOCATION)) {
+                    return privateLocations;
+                }
+            }
+            LocationIdentity[] result = Arrays.copyOf(privateLocations, privateLocations.length + 1);
+            result[result.length - 1] = SnippetCounterNode.SNIPPET_COUNTER_LOCATION;
+            return result;
+        }
+        return privateLocations;
+    }
+
+    /**
+     * We do not want to use the {@link LocationIdentity} of the {@link SnippetCounter#value} field,
+     * so that the usage in snippets is always possible. If a method accesses the counter via the
+     * field and the snippet, the result might not be correct though.
+     */
+    public static final LocationIdentity SNIPPET_COUNTER_LOCATION = NamedLocationIdentity.mutable("SnippetCounter");
+
     static class SnippetCounterSnippets implements Snippets {
 
         @Fold
@@ -96,15 +128,8 @@
             }
         }
 
-        /**
-         * We do not want to use the {@link LocationIdentity} of the {@link SnippetCounter#value}
-         * field, so that the usage in snippets is always possible. If a method accesses the counter
-         * via the field and the snippet, the result might not be correct though.
-         */
-        protected static final LocationIdentity SNIPPET_COUNTER_LOCATION = NamedLocationIdentity.mutable("SnippetCounter");
-
         @Snippet
-        public static void add(SnippetCounter counter, int increment) {
+        public static void add(@ConstantParameter SnippetCounter counter, int increment) {
             long loadedValue = ObjectAccess.readLong(counter, countOffset(), SNIPPET_COUNTER_LOCATION);
             ObjectAccess.writeLong(counter, countOffset(), loadedValue + increment, SNIPPET_COUNTER_LOCATION);
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Thu May 28 17:44:05 2015 +0200
@@ -52,8 +52,8 @@
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.common.*;
@@ -87,6 +87,7 @@
     public abstract static class SnippetInfo {
 
         protected final ResolvedJavaMethod method;
+        protected ResolvedJavaMethod original;
         protected final LocationIdentity[] privateLocations;
 
         /**
@@ -150,7 +151,7 @@
 
         protected SnippetInfo(ResolvedJavaMethod method, LocationIdentity[] privateLocations) {
             this.method = method;
-            this.privateLocations = privateLocations;
+            this.privateLocations = SnippetCounterNode.addSnippetCounters(privateLocations);
             instantiationCounter = Debug.metric("SnippetInstantiationCount[%s]", method.getName());
             instantiationTimer = Debug.timer("SnippetInstantiationTime[%s]", method.getName());
             assert method.isStatic() : "snippet method must be static: " + method.format("%H.%n");
@@ -175,6 +176,10 @@
             return lazy().constantParameters.length;
         }
 
+        public void setOriginalMethod(ResolvedJavaMethod original) {
+            this.original = original;
+        }
+
         public boolean isConstantParameter(int paramIdx) {
             return lazy().constantParameters[paramIdx];
         }
@@ -190,6 +195,11 @@
             }
             return null;
         }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + ":" + method.format("%h.%n");
+        }
     }
 
     protected static class LazySnippetInfo extends SnippetInfo {
@@ -263,6 +273,7 @@
         }
 
         public Arguments addConst(String name, Object value) {
+            assert value != null;
             return addConst(name, value, null);
         }
 
@@ -560,7 +571,7 @@
         this.info = args.info;
 
         Object[] constantArgs = getConstantArgs(args);
-        StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, constantArgs);
+        StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, args.info.original, constantArgs);
         instantiationTimer = Debug.timer("SnippetTemplateInstantiationTime[%#s]", args);
         instantiationCounter = Debug.metric("SnippetTemplateInstantiationCount[%#s]", args);
 
@@ -781,6 +792,8 @@
         for (int i = 0; i < args.info.getParameterCount(); i++) {
             if (!args.info.isConstantParameter(i)) {
                 constantArgs[i] = null;
+            } else {
+                assert constantArgs[i] != null : "Can't pass raw null through as argument";
             }
         }
         return constantArgs;
@@ -1098,11 +1111,12 @@
             // rewire outgoing memory edges
             replaceMemoryUsages(replacee, new MemoryOutputMap(replacee, duplicates));
 
-            ReturnNode ret = (ReturnNode) duplicates.get(returnNode);
-            MemoryMapNode memoryMap = ret.getMemoryMap();
-            ret.setMemoryMap(null);
-            memoryMap.safeDelete();
-
+            if (returnNode != null) {
+                ReturnNode ret = (ReturnNode) duplicates.get(returnNode);
+                MemoryMapNode memoryMap = ret.getMemoryMap();
+                ret.setMemoryMap(null);
+                memoryMap.safeDelete();
+            }
             if (memoryAnchor != null) {
                 // rewire incoming memory edges
                 MemoryAnchorNode memoryDuplicate = (MemoryAnchorNode) duplicates.get(memoryAnchor);
@@ -1298,7 +1312,7 @@
      * Gets a copy of the specialized graph.
      */
     public StructuredGraph copySpecializedGraph() {
-        return snippet.copy();
+        return (StructuredGraph) snippet.copy();
     }
 
     /**
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Thu May 28 17:44:05 2015 +0200
@@ -84,6 +84,7 @@
         if (Options.UseBlackholeSubstitution.getValue()) {
             registerJMHBlackholePlugins(plugins);
         }
+        registerJFRThrowablePlugins(plugins);
     }
 
     private static final Field STRING_VALUE_FIELD;
@@ -459,7 +460,7 @@
         }
 
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-            if (b.parsingReplacement()) {
+            if (b.parsingIntrinsic()) {
                 ResolvedJavaMethod rootMethod = b.getGraph().method();
                 if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) {
                     // Disable invocation plugins for boxing snippets so that the
@@ -486,7 +487,7 @@
         }
 
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-            if (b.parsingReplacement()) {
+            if (b.parsingIntrinsic()) {
                 ResolvedJavaMethod rootMethod = b.getGraph().method();
                 if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) {
                     // Disable invocation plugins for unboxing snippets so that the
@@ -651,4 +652,18 @@
             }
         }
     }
+
+    private static void registerJFRThrowablePlugins(InvocationPlugins plugins) {
+        String name = "oracle.jrockit.jfr.jdkevents.ThrowableTracer";
+        Class<?> tracerClass = MethodSubstitutionPlugin.resolveClass(name, true);
+        if (tracerClass != null) {
+            Registration r = new Registration(plugins, tracerClass);
+            r.register2("traceThrowable", Throwable.class, String.class, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode throwable, ValueNode message) {
+                    b.add(new VirtualizableInvokeMacroNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), throwable, message));
+                    return true;
+                }
+            });
+        }
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,9 +34,9 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
 import com.oracle.graal.word.*;
 import com.oracle.graal.word.Word.Opcode;
 import com.oracle.graal.word.Word.Operation;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,44 +22,109 @@
  */
 package com.oracle.graal.replacements.nodes;
 
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 
 @NodeInfo
-public abstract class BasicArrayCopyNode extends MacroStateSplitNode implements Virtualizable {
+public class BasicArrayCopyNode extends AbstractMemoryCheckpoint implements Virtualizable, MemoryCheckpoint.Single, MemoryAccess, Lowerable, DeoptimizingNode.DeoptDuring {
 
     public static final NodeClass<BasicArrayCopyNode> TYPE = NodeClass.create(BasicArrayCopyNode.class);
 
-    public BasicArrayCopyNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
-        super(c, invokeKind, targetMethod, bci, returnType, arguments);
+    @Input protected ValueNode src;
+    @Input protected ValueNode srcPos;
+    @Input protected ValueNode dest;
+    @Input protected ValueNode destPos;
+    @Input protected ValueNode length;
+
+    @OptionalInput(InputType.State) FrameState stateDuring;
+
+    @OptionalInput(InputType.Memory) protected MemoryNode lastLocationAccess;
+
+    protected Kind elementKind;
+
+    protected int bci;
+
+    public BasicArrayCopyNode(NodeClass<? extends AbstractMemoryCheckpoint> type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, int bci) {
+        super(type, StampFactory.forKind(Kind.Void));
+        this.bci = bci;
+        this.src = src;
+        this.srcPos = srcPos;
+        this.dest = dest;
+        this.destPos = destPos;
+        this.length = length;
+        this.elementKind = elementKind != Kind.Illegal ? elementKind : null;
     }
 
-    protected ValueNode getSource() {
-        return arguments.get(0);
+    public BasicArrayCopyNode(NodeClass<? extends AbstractMemoryCheckpoint> type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind) {
+        super(type, StampFactory.forKind(Kind.Void));
+        this.bci = -6;
+        this.src = src;
+        this.srcPos = srcPos;
+        this.dest = dest;
+        this.destPos = destPos;
+        this.length = length;
+        this.elementKind = elementKind != Kind.Illegal ? elementKind : null;
+    }
+
+    public ValueNode getSource() {
+        return src;
     }
 
-    protected ValueNode getSourcePosition() {
-        return arguments.get(1);
+    public ValueNode getSourcePosition() {
+        return srcPos;
+    }
+
+    public ValueNode getDestination() {
+        return dest;
+    }
+
+    public ValueNode getDestinationPosition() {
+        return destPos;
+    }
+
+    public ValueNode getLength() {
+        return length;
+    }
+
+    public int getBci() {
+        return bci;
     }
 
-    protected ValueNode getDestination() {
-        return arguments.get(2);
+    public Kind getElementKind() {
+        return elementKind;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        if (elementKind != null) {
+            return NamedLocationIdentity.getArrayLocation(elementKind);
+        }
+        return any();
     }
 
-    protected ValueNode getDestinationPosition() {
-        return arguments.get(3);
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
     }
 
-    protected ValueNode getLength() {
-        return arguments.get(4);
+    public void setLastLocationAccess(MemoryNode lla) {
+        updateUsagesInterface(lastLocationAccess, lla);
+        lastLocationAccess = lla;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
     }
 
     private static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) {
@@ -89,16 +154,37 @@
         return true;
     }
 
+    /*
+     * Returns true if this copy doesn't require store checks. Trivially true for primitive arrays.
+     */
+    public boolean isExact() {
+        ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp());
+        ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp());
+        if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) {
+            return false;
+        }
+        if (srcType.getComponentType().getKind().isPrimitive() || getSource() == getDestination()) {
+            return true;
+        }
+
+        if (StampTool.isExactType(getDestination().stamp())) {
+            if (destType != null && destType.isAssignableFrom(srcType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public void virtualize(VirtualizerTool tool) {
         ValueNode sourcePosition = tool.getReplacedValue(getSourcePosition());
         ValueNode destinationPosition = tool.getReplacedValue(getDestinationPosition());
-        ValueNode length = tool.getReplacedValue(getLength());
+        ValueNode replacedLength = tool.getReplacedValue(getLength());
 
-        if (sourcePosition.isConstant() && destinationPosition.isConstant() && length.isConstant()) {
-            int srcPos = sourcePosition.asJavaConstant().asInt();
-            int destPos = destinationPosition.asJavaConstant().asInt();
-            int len = length.asJavaConstant().asInt();
+        if (sourcePosition.isConstant() && destinationPosition.isConstant() && replacedLength.isConstant()) {
+            int srcPosInt = sourcePosition.asJavaConstant().asInt();
+            int destPosInt = destinationPosition.asJavaConstant().asInt();
+            int len = replacedLength.asJavaConstant().asInt();
             State destState = tool.getObjectState(getDestination());
 
             if (destState != null && destState.getState() == EscapeState.Virtual) {
@@ -106,7 +192,7 @@
                 if (!(destVirtual instanceof VirtualArrayNode)) {
                     return;
                 }
-                if (len < 0 || !checkBounds(destPos, len, destVirtual)) {
+                if (len < 0 || !checkBounds(destPosInt, len, destVirtual)) {
                     return;
                 }
                 State srcState = tool.getObjectState(getSource());
@@ -121,18 +207,18 @@
                     if (((VirtualArrayNode) srcVirtual).componentType().getKind() != Kind.Object) {
                         return;
                     }
-                    if (!checkBounds(srcPos, len, srcVirtual)) {
+                    if (!checkBounds(srcPosInt, len, srcVirtual)) {
                         return;
                     }
-                    if (!checkEntryTypes(srcPos, len, srcState, destVirtual.type().getComponentType(), tool)) {
+                    if (!checkEntryTypes(srcPosInt, len, srcState, destVirtual.type().getComponentType(), tool)) {
                         return;
                     }
                     for (int i = 0; i < len; i++) {
-                        tool.setVirtualEntry(destState, destPos + i, srcState.getEntry(srcPos + i), false);
+                        tool.setVirtualEntry(destState, destPosInt + i, srcState.getEntry(srcPosInt + i), false);
                     }
                     tool.delete();
                     if (Debug.isLogEnabled()) {
-                        Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPos, getDestination(), destPos, len);
+                        Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPosInt, getDestination(), destPosInt, len);
                     }
                 } else {
                     ValueNode source = srcState == null ? tool.getReplacedValue(getSource()) : srcState.getMaterializedValue();
@@ -146,13 +232,31 @@
                         return;
                     }
                     for (int i = 0; i < len; i++) {
-                        LoadIndexedNode load = new LoadIndexedNode(source, ConstantNode.forInt(i + srcPos, graph()), destComponentType.getKind());
+                        LoadIndexedNode load = new LoadIndexedNode(source, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getKind());
                         tool.addNode(load);
-                        tool.setVirtualEntry(destState, destPos + i, load, false);
+                        tool.setVirtualEntry(destState, destPosInt + i, load, false);
                     }
                     tool.delete();
                 }
             }
         }
     }
+
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    public FrameState stateDuring() {
+        return stateDuring;
+    }
+
+    public void setStateDuring(FrameState stateDuring) {
+        updateUsages(this.stateDuring, stateDuring);
+        this.stateDuring = stateDuring;
+    }
+
+    public void computeStateDuring(FrameState currentStateAfter) {
+        FrameState newStateDuring = currentStateAfter.duplicateModifiedDuringCall(getBci(), asNode().getKind());
+        setStateDuring(newStateDuring);
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,8 +27,8 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Thu May 28 17:44:05 2015 +0200
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.api.code.BytecodeFrame.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
@@ -113,14 +112,7 @@
     protected StructuredGraph getLoweredSubstitutionGraph(LoweringTool tool) {
         StructuredGraph methodSubstitution = tool.getReplacements().getSubstitution(getTargetMethod(), true, bci);
         if (methodSubstitution != null) {
-            methodSubstitution = methodSubstitution.copy();
-            if (stateAfter() == null || stateAfter().bci == BytecodeFrame.AFTER_BCI) {
-                /*
-                 * handles the case of a MacroNode inside a snippet used for another MacroNode
-                 * lowering
-                 */
-                new CollapseFrameForSingleSideEffectPhase().apply(methodSubstitution);
-            }
+            methodSubstitution = (StructuredGraph) methodSubstitution.copy();
             return lowerReplacement(methodSubstitution, tool);
         }
         return null;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Thu May 28 17:44:05 2015 +0200
@@ -29,8 +29,8 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
 
 /**
  * This is an extension of {@link MacroNode} that is a {@link StateSplit} and a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MethodHandleNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.nodes;
+
+import java.lang.invoke.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
+import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+
+/**
+ * Node for invocation methods defined on the class {@link MethodHandle}.
+ */
+@NodeInfo
+public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable {
+    public static final NodeClass<MethodHandleNode> TYPE = NodeClass.create(MethodHandleNode.class);
+
+    protected final IntrinsicMethod intrinsicMethod;
+
+    public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, arguments);
+        this.intrinsicMethod = intrinsicMethod;
+    }
+
+    /**
+     * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an
+     * invocation on another method with possibly transformed arguments.
+     *
+     * @param assumptions object for recording any speculations made during the transformation
+     * @param methodHandleAccess objects for accessing the implementation internals of a
+     *            {@link MethodHandle}
+     * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed
+     * @param bci the BCI of the original {@link MethodHandle} call
+     * @param returnType return type of the original {@link MethodHandle} call
+     * @param arguments arguments to the original {@link MethodHandle} call
+     * @return a more direct invocation derived from the {@link MethodHandle} call or null
+     */
+    public static InvokeNode tryResolveTargetInvoke(Assumptions assumptions, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode... arguments) {
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                return getInvokeBasicTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                return getLinkToTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess();
+        ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]);
+        InvokeNode invoke = tryResolveTargetInvoke(graph().getAssumptions(), methodHandleAccess, intrinsicMethod, targetMethod, bci, returnType, argumentsArray);
+        if (invoke != null) {
+            assert invoke.graph() == null;
+            invoke = graph().addOrUniqueWithInputs(invoke);
+            invoke.setStateAfter(stateAfter());
+            FixedNode currentNext = next();
+            replaceAtUsages(invoke);
+            GraphUtil.removeFixedWithUnusedInputs(this);
+            graph().addBeforeFixed(currentNext, invoke);
+        }
+    }
+
+    /**
+     * Get the receiver of a MethodHandle.invokeBasic call.
+     *
+     * @return the receiver argument node
+     */
+    private static ValueNode getReceiver(ValueNode[] arguments) {
+        return arguments[0];
+    }
+
+    /**
+     * Get the MemberName argument of a MethodHandle.linkTo* call.
+     *
+     * @return the MemberName argument node (which is the last argument)
+     */
+    private static ValueNode getMemberName(ValueNode[] arguments) {
+        return arguments[arguments.length - 1];
+    }
+
+    /**
+     * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC }
+     * method) to get the target {@link InvokeNode} if the method handle receiver is constant.
+     *
+     * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
+     */
+    private static InvokeNode getInvokeBasicTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode[] arguments) {
+        ValueNode methodHandleNode = getReceiver(arguments);
+        if (methodHandleNode.isConstant()) {
+            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original);
+        }
+        return null;
+    }
+
+    /**
+     * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC},
+     * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and
+     * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if
+     * the member name argument is constant.
+     *
+     * @return invoke node for the member name target
+     */
+    private static InvokeNode getLinkToTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode[] arguments) {
+        ValueNode memberNameNode = getMemberName(arguments);
+        if (memberNameNode.isConstant()) {
+            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original);
+        }
+        return null;
+    }
+
+    /**
+     * Helper function to get the {@link InvokeNode} for the targetMethod of a
+     * java.lang.invoke.MemberName.
+     *
+     * @param target the target, already loaded from the member name node
+     * @return invoke node for the member name target
+     */
+    private static InvokeNode getTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, int bci, JavaType returnType, ValueNode[] arguments, ResolvedJavaMethod target,
+                    ResolvedJavaMethod original) {
+        if (target == null) {
+            return null;
+        }
+
+        // In lambda forms we erase signature types to avoid resolving issues
+        // involving class loaders. When we optimize a method handle invoke
+        // to a direct call we must cast the receiver and arguments to its
+        // actual types.
+        Signature signature = target.getSignature();
+        final boolean isStatic = target.isStatic();
+        final int receiverSkip = isStatic ? 0 : 1;
+
+        // Cast receiver to its type.
+        if (!isStatic) {
+            JavaType receiverType = target.getDeclaringClass();
+            maybeCastArgument(arguments, 0, receiverType);
+        }
+
+        // Cast reference arguments to its type.
+        for (int index = 0; index < signature.getParameterCount(false); index++) {
+            JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass());
+            maybeCastArgument(arguments, receiverSkip + index, parameterType);
+        }
+
+        if (target.canBeStaticallyBound()) {
+            return createTargetInvokeNode(intrinsicMethod, target, original, bci, returnType, arguments);
+        }
+
+        // Try to get the most accurate receiver type
+        if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
+            ValueNode receiver = getReceiver(arguments);
+            ResolvedJavaType receiverType = StampTool.typeOrNull(receiver.stamp());
+            if (receiverType != null) {
+                AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.findUniqueConcreteMethod(target);
+                if (concreteMethod != null) {
+                    assumptions.record(concreteMethod);
+                    return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
+                }
+            }
+        } else {
+            AssumptionResult<ResolvedJavaMethod> concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
+            if (concreteMethod != null) {
+                assumptions.record(concreteMethod);
+                return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Inserts a node to cast the argument at index to the given type if the given type is more
+     * concrete than the argument type.
+     *
+     * @param index of the argument to be cast
+     * @param type the type the argument should be cast to
+     */
+    private static void maybeCastArgument(ValueNode[] arguments, int index, JavaType type) {
+        if (type instanceof ResolvedJavaType) {
+            ResolvedJavaType targetType = (ResolvedJavaType) type;
+            if (!targetType.isPrimitive()) {
+                ValueNode argument = arguments[index];
+                ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
+                if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
+                    PiNode piNode = new PiNode(argument, StampFactory.declared(targetType));
+                    arguments[index] = piNode;
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
+     * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}.
+     *
+     * @return invoke node for the member name target
+     */
+    private static InvokeNode createTargetInvokeNode(IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, JavaType returnType, ValueNode[] arguments) {
+        InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        JavaType targetReturnType = target.getSignature().getReturnType(null);
+
+        // MethodHandleLinkTo* nodes have a trailing MemberName argument which
+        // needs to be popped.
+        ValueNode[] targetArguments;
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                targetArguments = arguments;
+                break;
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+
+        MethodCallTargetNode callTarget = ResolvedMethodHandleCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnType, original, arguments, returnType);
+
+        // The call target can have a different return type than the invoker,
+        // e.g. the target returns an Object but the invoker void. In this case
+        // we need to use the stamp of the invoker. Note: always using the
+        // invoker's stamp would be wrong because it's a less concrete type
+        // (usually java.lang.Object).
+        if (returnType.getKind() == Kind.Void) {
+            return new InvokeNode(callTarget, bci, StampFactory.forVoid());
+        } else {
+            return new InvokeNode(callTarget, bci);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ResolvedMethodHandleCallTargetNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.nodes;
+
+import static sun.misc.Version.*;
+
+import java.lang.invoke.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * A call target that replaces itself in the graph when being lowered by restoring the original
+ * {@link MethodHandle} invocation target. Prior to
+ * https://bugs.openjdk.java.net/browse/JDK-8072008, this is required for when a
+ * {@link MethodHandle} call is resolved to a constant target but the target was not inlined. In
+ * that case, the original invocation must be restored with all of its original arguments. Why?
+ * HotSpot linkage for {@link MethodHandle} intrinsics (see
+ * {@code MethodHandles::generate_method_handle_dispatch}) expects certain implicit arguments to be
+ * on the stack such as the MemberName suffix argument for a call to one of the MethodHandle.linkTo*
+ * methods. An {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle}
+ * invocation drops these arguments which means the interpreter won't find them.
+ */
+@NodeInfo
+public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable {
+
+    public static final NodeClass<ResolvedMethodHandleCallTargetNode> TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class);
+
+    /**
+     * Creates a call target for an invocation on a direct target derived by resolving a constant
+     * {@link MethodHandle}.
+     */
+    public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
+                    ValueNode[] originalArguments, JavaType originalReturnType) {
+        if (jdkMajorVersion() >= 1 && jdkMinorVersion() >= 8 && jdkMicroVersion() >= 0 && jdkUpdateVersion() >= 60) {
+            // https://bugs.openjdk.java.net/browse/JDK-8072008 is targeted for 8u60
+            return new MethodCallTargetNode(invokeKind, targetMethod, arguments, returnType);
+        }
+        return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnType, originalTargetMethod, originalArguments, originalReturnType);
+    }
+
+    protected final ResolvedJavaMethod originalTargetMethod;
+    protected final JavaType originalReturnType;
+    @Input NodeInputList<ValueNode> originalArguments;
+
+    protected ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
+                    ValueNode[] originalArguments, JavaType originalReturnType) {
+        super(TYPE, invokeKind, targetMethod, arguments, returnType);
+        this.originalTargetMethod = originalTargetMethod;
+        this.originalReturnType = originalReturnType;
+        this.originalArguments = new NodeInputList<>(this, originalArguments);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        MethodCallTargetNode replacement = graph().add(
+                        new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnType));
+
+        // Replace myself...
+        this.replaceAndDelete(replacement);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        throw GraalInternalError.shouldNotReachHere("should have replaced itself");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/VirtualizableInvokeMacroNode.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * A helper class to allow elimination of byte code instrumentation that could interfere with escape
+ * analysis.
+ */
+@NodeInfo
+public class VirtualizableInvokeMacroNode extends MacroStateSplitNode implements Virtualizable {
+
+    public static final NodeClass<VirtualizableInvokeMacroNode> TYPE = NodeClass.create(VirtualizableInvokeMacroNode.class);
+
+    public VirtualizableInvokeMacroNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, arguments);
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        for (ValueNode arg : arguments) {
+            State state = tool.getObjectState(arg);
+            if (state != null && state.getState() == EscapeState.Virtual) {
+                tool.delete();
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu May 28 17:44:05 2015 +0200
@@ -74,7 +74,6 @@
         return new HotSpotTruffleRuntime();
     }
 
-    private TruffleCompilerImpl truffleCompiler;
     private Map<OptimizedCallTarget, Future<?>> compilations = newIdentityMap();
     private final ThreadPoolExecutor compileQueue;
 
@@ -213,21 +212,12 @@
     @Override
     public void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous) {
         if (truffleCompiler == null) {
-            truffleCompiler = new TruffleCompilerImpl();
+            truffleCompiler = DefaultTruffleCompiler.create();
         }
         Runnable r = new Runnable() {
             @Override
             public void run() {
-                boolean success = true;
-                try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(optimizedCallTarget))) {
-                    truffleCompiler.compileMethod(optimizedCallTarget);
-                } catch (Throwable e) {
-                    optimizedCallTarget.notifyCompilationFailed(e);
-                    success = false;
-                } finally {
-                    optimizedCallTarget.notifyCompilationFinished(success);
-
-                }
+                doCompile(optimizedCallTarget);
             }
         };
         Future<?> future = compileQueue.submit(r);
@@ -306,7 +296,7 @@
     }
 
     @Override
-    public boolean enableInfopoints() {
+    public boolean platformEnableInfopoints() {
         return HotSpotGraalRuntime.runtime().getCompilerToVM().shouldDebugNonSafepoints();
     }
 
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java	Thu May 28 17:44:05 2015 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.framemap.*;
@@ -48,7 +47,8 @@
     @Override
     public Mark recordMark(Object id) {
         Mark mark = super.recordMark(id);
-        if (MarkId.getEnum((int) id) == MarkId.VERIFIED_ENTRY) {
+        HotSpotCodeCacheProvider hsCodeCache = (HotSpotCodeCacheProvider) codeCache;
+        if ((int) id == hsCodeCache.config.MARKID_VERIFIED_ENTRY) {
             HotSpotRegistersProvider registers = HotSpotGraalRuntime.runtime().getHostProviders().getRegisters();
             injectTailCallCode(HotSpotGraalRuntime.runtime().getConfig(), registers);
         }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java	Thu May 28 17:44:05 2015 +0200
@@ -269,7 +269,7 @@
         assertPartialEvalEqualsAndRunsCorrect(new Program("nestedLoopsProgram", bytecodes, 0, 6));
     }
 
-    @Test(timeout = 1000)
+    @Test(timeout = 2000)
     public void manyIfsProgram() {
         byte[] bytecodes = new byte[]{
         /* 0: */Bytecode.CONST,
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ConditionAnchoringTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ConditionAnchoringTest.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.spi.LoweringTool.StandardLoweringStage;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -147,7 +148,7 @@
     private static final class InlineEverythingPlugin implements InlineInvokePlugin {
         public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
             assert method.hasBytecodes();
-            return new InlineInfo(method, false, false);
+            return new InlineInfo(method, false);
         }
     }
 
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Thu May 28 17:44:05 2015 +0200
@@ -205,19 +205,19 @@
     }
 
     @Test
-    public void constantValueInertToolEvalNodeFactory() {
+    public void constantValueInertAdvancedInstrumentRootFactory() {
         FrameDescriptor fd = new FrameDescriptor();
         AbstractTestNode result = new ConstantTestNode(42);
         RootTestNode root = new RootTestNode(fd, "constantValue", result);
         root.adoptChildren();
         Probe testProbe = result.probe();
-        // A factory that could insert a ToolEvalNode into the AST, but which never does.
-        Instrument instrument = Instrument.create(new ToolEvalNodeFactory() {
+        // A factory that could insert a AdvancedInstrumentRoot into the AST, but which never does.
+        Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() {
 
-            public ToolEvalNode createToolEvalNode(Probe probe, Node node) {
+            public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) {
                 return null;
             }
-        }, null);
+        }, null, "test AdvancedInstrument");
         testProbe.attach(instrument);
 
         // It all gets compiled away
@@ -225,29 +225,30 @@
     }
 
     @Test
-    public void constantValueInertToolEvalNode() {
+    public void constantValueInertAdvancedInstrumentRoot() {
         FrameDescriptor fd = new FrameDescriptor();
         AbstractTestNode resultTestNode = new ConstantTestNode(42);
         RootTestNode rootTestNode = new RootTestNode(fd, "constantValue", resultTestNode);
         rootTestNode.adoptChildren();
         Probe testProbe = resultTestNode.probe();
-        // A factory that inserts a ToolEvalNode with empty methods into the instrumentation chain.
-        Instrument instrument = Instrument.create(new ToolEvalNodeFactory() {
+        // Factory inserts a AdvancedInstrumentRoot with empty methods into instrumentation .
+        Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() {
 
-            public ToolEvalNode createToolEvalNode(Probe probe, Node node) {
-                return new ToolEvalNode() {
+            @Override
+            public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) {
+                return new AdvancedInstrumentRoot() {
 
                     public String instrumentationInfo() {
                         return null;
                     }
 
                     @Override
-                    public Object executeToolEvalNode(Node n, VirtualFrame frame) {
+                    public Object executeRoot(Node n, VirtualFrame frame) {
                         return null;
                     }
                 };
             }
-        }, null);
+        }, null, "test AdvancedInstrument");
         testProbe.attach(instrument);
 
         // It all gets compiled away.
@@ -351,6 +352,7 @@
             final boolean[] isCurrentlyCompiled = {false};
             final Instrument optInstrument = Instrument.create(new Instrument.TruffleOptListener() {
 
+                @Override
                 public void notifyIsCompiled(boolean isCompiled) {
                     isCurrentlyCompiled[0] = isCompiled;
                 }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Thu May 28 17:44:05 2015 +0200
@@ -38,12 +38,12 @@
 import com.oracle.truffle.api.nodes.*;
 
 public class PartialEvaluationTest extends GraalCompilerTest {
-    private final TruffleCompilerImpl truffleCompiler;
+    private final TruffleCompiler truffleCompiler;
 
     public PartialEvaluationTest() {
         // Make sure Truffle runtime is initialized.
         Assert.assertTrue(Truffle.getRuntime() != null);
-        this.truffleCompiler = new TruffleCompilerImpl();
+        this.truffleCompiler = DefaultTruffleCompiler.create();
 
         DebugEnvironment.initialize(System.out);
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java	Thu May 28 17:44:05 2015 +0200
@@ -28,8 +28,6 @@
 
 public class CompilationProfile {
 
-    private static final int TIMESTAMP_THRESHOLD = Math.max(TruffleCompilationThreshold.getValue() / 2, 1);
-
     /**
      * Number of times an installed code for this tree was invalidated.
      */
@@ -112,7 +110,7 @@
         interpreterCallAndLoopCount++;
 
         int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount;
-        if (callsMissing == TIMESTAMP_THRESHOLD) {
+        if (callsMissing == getTimestampThreshold()) {
             timestamp = System.nanoTime();
         }
     }
@@ -130,7 +128,7 @@
     }
 
     public void deferCompilation() {
-        ensureProfiling(0, TIMESTAMP_THRESHOLD + 1);
+        ensureProfiling(0, getTimestampThreshold() + 1);
         timestamp = 0;
         deferedCount++;
     }
@@ -139,7 +137,7 @@
         interpreterCallAndLoopCount += count;
 
         int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount;
-        if (callsMissing <= TIMESTAMP_THRESHOLD && callsMissing + count > TIMESTAMP_THRESHOLD) {
+        if (callsMissing <= getTimestampThreshold() && callsMissing + count > getTimestampThreshold()) {
             timestamp = System.nanoTime();
         }
     }
@@ -154,4 +152,7 @@
         return timestamp;
     }
 
+    private static int getTimestampThreshold() {
+        return Math.max(TruffleCompilationThreshold.getValue() / 2, 1);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleCompiler.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import java.util.*;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.java.*;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.runtime.*;
+
+public final class DefaultTruffleCompiler extends TruffleCompiler {
+
+    public static TruffleCompiler create() {
+        Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
+        Suites suites = backend.getSuites().getDefaultSuites();
+        LIRSuites lirSuites = backend.getSuites().getDefaultLIRSuites();
+        GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
+        Plugins plugins = phase.getGraphBuilderConfig().getPlugins();
+        return new DefaultTruffleCompiler(plugins, suites, lirSuites, backend);
+    }
+
+    private DefaultTruffleCompiler(Plugins plugins, Suites suites, LIRSuites lirSuites, Backend backend) {
+        super(plugins, suites, lirSuites, backend);
+    }
+
+    @Override
+    protected PartialEvaluator createPartialEvaluator() {
+        return new PartialEvaluator(providers, config, Graal.getRequiredCapability(SnippetReflectionProvider.class), backend.getTarget().arch);
+    }
+
+    @Override
+    protected PhaseSuite<HighTierContext> createGraphBuilderSuite() {
+        PhaseSuite<HighTierContext> suite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
+        ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
+        iterator.remove();
+        iterator.add(new GraphBuilderPhase(config));
+        return suite;
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Thu May 28 17:44:05 2015 +0200
@@ -31,6 +31,8 @@
 import com.oracle.graal.api.code.stack.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.truffle.debug.*;
 import com.oracle.graal.truffle.unsafe.*;
@@ -55,7 +57,8 @@
     private final List<GraalTruffleCompilationListener> compilationListeners = new ArrayList<>();
     private final GraalTruffleCompilationListener compilationNotify = new DispatchTruffleCompilationListener();
 
-    private LoopNodeFactory loopNodeFactory;
+    protected TruffleCompiler truffleCompiler;
+    protected LoopNodeFactory loopNodeFactory;
 
     public GraalTruffleRuntime() {
         Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
@@ -101,11 +104,14 @@
         if (!(repeatingNode instanceof Node)) {
             throw new IllegalArgumentException("Repeating node must be of type Node.");
         }
+        return getLoopNodeFactory().create(repeatingNode);
+    }
+
+    protected LoopNodeFactory getLoopNodeFactory() {
         if (loopNodeFactory == null) {
             loopNodeFactory = loadPrioritizedServiceProvider(LoopNodeFactory.class);
         }
-
-        return loopNodeFactory.create(repeatingNode);
+        return loopNodeFactory;
     }
 
     @Override
@@ -271,6 +277,18 @@
 
     public abstract void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous);
 
+    protected void doCompile(OptimizedCallTarget optimizedCallTarget) {
+        boolean success = true;
+        try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(optimizedCallTarget))) {
+            truffleCompiler.compileMethod(optimizedCallTarget);
+        } catch (Throwable e) {
+            optimizedCallTarget.notifyCompilationFailed(e);
+            success = false;
+        } finally {
+            optimizedCallTarget.notifyCompilationFinished(success);
+        }
+    }
+
     public abstract boolean cancelInstalledTask(OptimizedCallTarget optimizedCallTarget, Object source, CharSequence reason);
 
     public abstract void waitForCompilation(OptimizedCallTarget optimizedCallTarget, long timeout) throws ExecutionException, TimeoutException;
@@ -281,7 +299,12 @@
 
     public abstract void reinstallStubs();
 
-    public abstract boolean enableInfopoints();
+    public final boolean enableInfopoints() {
+        /* Currently infopoints can change code generation so don't enable them automatically */
+        return platformEnableInfopoints() && TruffleEnableInfopoints.getValue();
+    }
+
+    protected abstract boolean platformEnableInfopoints();
 
     private final class DispatchTruffleCompilationListener implements GraalTruffleCompilationListener {
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java	Thu May 28 17:44:05 2015 +0200
@@ -28,8 +28,6 @@
 
 public final class OptimizedOSRLoopNode extends LoopNode implements ReplaceObserver {
 
-    private static final int OSR_THRESHOLD = TruffleCompilerOptions.TruffleOSRCompilationThreshold.getValue();
-
     private int interpreterLoopCount;
     private OptimizedCallTarget compiledTarget;
 
@@ -75,7 +73,8 @@
     }
 
     private boolean profilingLoop(VirtualFrame frame) {
-        int overflowLoopCount = Integer.MAX_VALUE - OSR_THRESHOLD + interpreterLoopCount;
+        int osrThreshold = TruffleCompilerOptions.TruffleOSRCompilationThreshold.getValue();
+        int overflowLoopCount = Integer.MAX_VALUE - osrThreshold + interpreterLoopCount;
         try {
             while (repeatableNode.executeRepeating(frame)) {
                 try {
@@ -86,7 +85,7 @@
                 }
             }
         } finally {
-            reportLoopCount(overflowLoopCount - Integer.MAX_VALUE + OSR_THRESHOLD - interpreterLoopCount);
+            reportLoopCount(overflowLoopCount - Integer.MAX_VALUE + osrThreshold - interpreterLoopCount);
         }
         return true;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu May 28 17:44:05 2015 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.truffle;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
 import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
 
 import java.lang.invoke.*;
@@ -71,8 +71,8 @@
     @Option(help = "New partial evaluation on Graal graphs", type = OptionType.Expert)//
     public static final StableOptionValue<Boolean> GraphPE = new StableOptionValue<>(true);
 
-    private final Providers providers;
-    private final Architecture architecture;
+    protected final Providers providers;
+    protected final Architecture architecture;
     private final CanonicalizerPhase canonicalizer;
     private final SnippetReflectionProvider snippetReflection;
     private final ResolvedJavaMethod callDirectMethod;
@@ -140,11 +140,6 @@
         }
 
         public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) {
-            if (TruffleCompilerOptions.TruffleExcludeAssertions.getValue() && staticField.getName().equals("$assertionsDisabled")) {
-                ConstantNode trueNode = builder.add(ConstantNode.forBoolean(true));
-                builder.addPush(trueNode);
-                return true;
-            }
             return tryConstantFold(builder, providers.getMetaAccess(), providers.getConstantReflection(), staticField, null);
         }
     }
@@ -190,7 +185,7 @@
             if (replacements.hasSubstitution(original, builder.bci())) {
                 return null;
             }
-            assert !builder.parsingReplacement();
+            assert !builder.parsingIntrinsic();
 
             if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) {
                 if (original.equals(callSiteProxyMethod)) {
@@ -210,12 +205,12 @@
                     if (decision != null && decision.isInline()) {
                         inlining.push(decision);
                         builder.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption()));
-                        return new InlineInfo(callInlinedMethod, false, false);
+                        return new InlineInfo(callInlinedMethod, false);
                     }
                 }
             }
 
-            return new InlineInfo(original, false, false);
+            return new InlineInfo(original, false);
         }
 
         @Override
@@ -277,10 +272,10 @@
                  * We want to inline invokes that have a constant MethodHandle parameter to remove
                  * invokedynamic related calls as early as possible.
                  */
-                return new InlineInfo(original, false, false);
+                return new InlineInfo(original, false);
             }
             if (inlineDuringParsing && original.hasBytecodes() && original.getCode().length < TrivialInliningSize.getValue() && builder.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
-                return new InlineInfo(original, false, false);
+                return new InlineInfo(original, false);
             }
             return null;
         }
@@ -319,19 +314,17 @@
         }
         plugins.setInlineInvokePlugin(inlinePlugin);
         plugins.setLoopExplosionPlugin(new PELoopExplosionPlugin());
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), newConfig, TruffleCompilerImpl.Optimizations, null).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), newConfig, TruffleCompiler.Optimizations, null).apply(graph);
         if (PrintTruffleExpansionHistogram.getValue()) {
             ((HistogramInlineInvokePlugin) inlinePlugin).print(callTarget, System.out);
         }
     }
 
-    protected void doGraphPE(OptimizedCallTarget callTarget, StructuredGraph graph) {
+    protected PEGraphDecoder createGraphDecoder(StructuredGraph graph) {
         GraphBuilderConfiguration newConfig = configForRoot.copy();
         InvocationPlugins parsingInvocationPlugins = newConfig.getPlugins().getInvocationPlugins();
         TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), parsingInvocationPlugins, true, snippetReflection);
 
-        callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
-
         LoopExplosionPlugin loopExplosionPlugin = new PELoopExplosionPlugin();
 
         newConfig.setUseProfiling(false);
@@ -340,12 +333,18 @@
         plugins.setInlineInvokePlugin(new ParsingInlineInvokePlugin((ReplacementsImpl) providers.getReplacements(), parsingInvocationPlugins, loopExplosionPlugin,
                         !PrintTruffleExpansionHistogram.getValue()));
 
-        CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(providers, newConfig, TruffleCompilerImpl.Optimizations, AllowAssumptions.from(graph.getAssumptions() != null), architecture);
+        return new CachingPEGraphDecoder(providers, newConfig, TruffleCompiler.Optimizations, AllowAssumptions.from(graph.getAssumptions() != null), architecture);
+    }
 
+    protected void doGraphPE(OptimizedCallTarget callTarget, StructuredGraph graph) {
+        callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
+
+        PEGraphDecoder decoder = createGraphDecoder(graph);
+
+        LoopExplosionPlugin loopExplosionPlugin = new PELoopExplosionPlugin();
         ParameterPlugin parameterPlugin = new InterceptReceiverPlugin(callTarget);
 
-        InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(providers.getMetaAccess());
-        TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), decodingInvocationPlugins, false, snippetReflection);
+        InvocationPlugins decodingInvocationPlugins = createDecodingInvocationPlugins();
         InlineInvokePlugin decodingInlinePlugin = new PEInlineInvokePlugin(callTarget.getInlining(), (ReplacementsImpl) providers.getReplacements());
         if (PrintTruffleExpansionHistogram.getValue()) {
             decodingInlinePlugin = new HistogramInlineInvokePlugin(graph, decodingInlinePlugin);
@@ -358,6 +357,12 @@
         }
     }
 
+    protected InvocationPlugins createDecodingInvocationPlugins() {
+        InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(providers.getMetaAccess());
+        TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), decodingInvocationPlugins, false, snippetReflection);
+        return decodingInvocationPlugins;
+    }
+
     @SuppressWarnings("unused")
     private void fastPartialEvaluation(OptimizedCallTarget callTarget, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) {
         if (GraphPE.getValue()) {
@@ -434,13 +439,13 @@
     }
 
     public StructuredGraph createRootGraph(StructuredGraph graph) {
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, null).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompiler.Optimizations, null).apply(graph);
         return graph;
     }
 
     public StructuredGraph createInlineGraph(String name, StructuredGraph caller) {
         StructuredGraph graph = new StructuredGraph(name, callInlinedMethod, AllowAssumptions.from(caller.getAssumptions() != null));
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, null).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompiler.Optimizations, null).apply(graph);
         return graph;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import static com.oracle.graal.api.code.CodeUtil.*;
+import static com.oracle.graal.compiler.GraalCompiler.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.meta.Assumptions.Assumption;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
+import com.oracle.graal.printer.*;
+import com.oracle.graal.truffle.nodes.*;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Implementation of the Truffle compiler using Graal.
+ */
+public abstract class TruffleCompiler {
+
+    protected final Providers providers;
+    protected final Suites suites;
+    protected final GraphBuilderConfiguration config;
+    protected final LIRSuites lirSuites;
+    protected final PartialEvaluator partialEvaluator;
+    protected final Backend backend;
+    protected final GraalTruffleCompilationListener compilationNotify;
+
+    // @formatter:off
+    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{
+        UnexpectedResultException.class,
+        SlowPathException.class,
+        ArithmeticException.class,
+        IllegalArgumentException.class,
+        VirtualMachineError.class,
+        StringIndexOutOfBoundsException.class,
+        ClassCastException.class
+    };
+    // @formatter:on
+
+    public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
+                    OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
+
+    public TruffleCompiler(Plugins plugins, Suites suites, LIRSuites lirSuites, Backend backend) {
+        GraalTruffleRuntime graalTruffleRuntime = ((GraalTruffleRuntime) Truffle.getRuntime());
+        this.compilationNotify = graalTruffleRuntime.getCompilationNotify();
+        this.backend = backend;
+        Providers backendProviders = backend.getProviders();
+        ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backendProviders.getConstantReflection(), backendProviders.getMetaAccess());
+        this.providers = backendProviders.copyWith(constantReflection);
+        this.suites = suites;
+        this.lirSuites = lirSuites;
+
+        ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
+
+        GraphBuilderConfiguration baseConfig = graalTruffleRuntime.enableInfopoints() ? GraphBuilderConfiguration.getInfopointDefault(new Plugins(plugins))
+                        : GraphBuilderConfiguration.getDefault(new Plugins(plugins));
+        this.config = baseConfig.withSkippedExceptionTypes(skippedExceptionTypes).withOmitAssertions(TruffleCompilerOptions.TruffleExcludeAssertions.getValue());
+
+        this.partialEvaluator = createPartialEvaluator();
+
+        if (Debug.isEnabled()) {
+            DebugEnvironment.initialize(System.out);
+        }
+    }
+
+    protected abstract PartialEvaluator createPartialEvaluator();
+
+    public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) {
+        ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length];
+        for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) {
+            skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]);
+        }
+        return skippedExceptionTypes;
+    }
+
+    public static final DebugTimer PartialEvaluationTime = Debug.timer("PartialEvaluationTime");
+    public static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
+    public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
+
+    public static final DebugMemUseTracker PartialEvaluationMemUse = Debug.memUseTracker("TrufflePartialEvaluationMemUse");
+    public static final DebugMemUseTracker CompilationMemUse = Debug.memUseTracker("TruffleCompilationMemUse");
+    public static final DebugMemUseTracker CodeInstallationMemUse = Debug.memUseTracker("TruffleCodeInstallationMemUse");
+
+    public void compileMethod(final OptimizedCallTarget compilable) {
+        StructuredGraph graph = null;
+
+        compilationNotify.notifyCompilationStarted(compilable);
+
+        try {
+            PhaseSuite<HighTierContext> graphBuilderSuite = createGraphBuilderSuite();
+
+            try (DebugCloseable a = PartialEvaluationTime.start(); DebugCloseable c = PartialEvaluationMemUse.start()) {
+                graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES);
+            }
+
+            if (Thread.currentThread().isInterrupted()) {
+                return;
+            }
+
+            compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph);
+            CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), graphBuilderSuite, compilable.getSpeculationLog(), compilable);
+            compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult);
+        } catch (Throwable t) {
+            System.out.println("compilation failed!?");
+            compilationNotify.notifyCompilationFailed(compilable, graph, t);
+            throw t;
+        }
+    }
+
+    public CompilationResult compileMethodHelper(StructuredGraph graph, String name, PhaseSuite<HighTierContext> graphBuilderSuite, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) {
+        try (Scope s = Debug.scope("TruffleFinal")) {
+            Debug.dump(1, graph, "After TruffleTier");
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+        CompilationResult result = null;
+        try (DebugCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); DebugCloseable c = CompilationMemUse.start()) {
+            CodeCacheProvider codeCache = providers.getCodeCache();
+            CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
+            CompilationResult compilationResult = new CompilationResult(name);
+            result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), graphBuilderSuite, Optimizations, getProfilingInfo(graph), speculationLog, suites, lirSuites,
+                            compilationResult, CompilationResultBuilderFactory.Default);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+        compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph);
+
+        if (graph.isInlinedMethodRecordingEnabled()) {
+            result.setMethods(graph.method(), graph.getInlinedMethods());
+        } else {
+            assert result.getMethods() == null;
+        }
+
+        List<AssumptionValidAssumption> validAssumptions = new ArrayList<>();
+        Set<Assumption> newAssumptions = new HashSet<>();
+        for (Assumption assumption : graph.getAssumptions()) {
+            processAssumption(newAssumptions, assumption, validAssumptions);
+        }
+
+        if (result.getAssumptions() != null) {
+            for (Assumption assumption : result.getAssumptions()) {
+                processAssumption(newAssumptions, assumption, validAssumptions);
+            }
+        }
+
+        result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()]));
+
+        InstalledCode installedCode;
+        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); DebugCloseable a = CodeInstallationTime.start(); DebugCloseable c = CodeInstallationMemUse.start()) {
+            installedCode = providers.getCodeCache().addMethod(graph.method(), result, speculationLog, predefinedInstalledCode);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+        for (AssumptionValidAssumption a : validAssumptions) {
+            a.getAssumption().registerInstalledCode(installedCode);
+        }
+
+        if (Debug.isLogEnabled()) {
+            Debug.log(providers.getCodeCache().disassemble(result, installedCode));
+        }
+        return result;
+    }
+
+    protected abstract PhaseSuite<HighTierContext> createGraphBuilderSuite();
+
+    public void processAssumption(Set<Assumption> newAssumptions, Assumption assumption, List<AssumptionValidAssumption> manual) {
+        if (assumption != null) {
+            if (assumption instanceof AssumptionValidAssumption) {
+                AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption;
+                manual.add(assumptionValidAssumption);
+            } else {
+                newAssumptions.add(assumption);
+            }
+        }
+    }
+
+    public PartialEvaluator getPartialEvaluator() {
+        return partialEvaluator;
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle;
-
-import static com.oracle.graal.api.code.CodeUtil.*;
-import static com.oracle.graal.compiler.GraalCompiler.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.CallingConvention.Type;
-import com.oracle.graal.api.meta.Assumptions.Assumption;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-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.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.java.*;
-import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.lir.phases.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.phases.util.*;
-import com.oracle.graal.printer.*;
-import com.oracle.graal.runtime.*;
-import com.oracle.graal.truffle.nodes.*;
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Implementation of the Truffle compiler using Graal.
- */
-public class TruffleCompilerImpl {
-
-    private final Providers providers;
-    private final Suites suites;
-    private final LIRSuites lirSuites;
-    private final PartialEvaluator partialEvaluator;
-    private final Backend backend;
-    private final GraphBuilderConfiguration config;
-    private final RuntimeProvider runtime;
-    private final GraalTruffleCompilationListener compilationNotify;
-
-    // @formatter:off
-    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{
-        UnexpectedResultException.class,
-        SlowPathException.class,
-        ArithmeticException.class,
-        IllegalArgumentException.class,
-        VirtualMachineError.class,
-        StringIndexOutOfBoundsException.class,
-        ClassCastException.class
-    };
-    // @formatter:on
-
-    public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
-                    OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
-
-    public TruffleCompilerImpl() {
-        GraalTruffleRuntime graalTruffleRuntime = ((GraalTruffleRuntime) Truffle.getRuntime());
-        this.runtime = Graal.getRequiredCapability(RuntimeProvider.class);
-        this.compilationNotify = graalTruffleRuntime.getCompilationNotify();
-        this.backend = runtime.getHostBackend();
-        Providers backendProviders = backend.getProviders();
-        ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backendProviders.getConstantReflection(), backendProviders.getMetaAccess());
-        this.providers = backendProviders.copyWith(constantReflection);
-        this.suites = backend.getSuites().getDefaultSuites();
-        this.lirSuites = backend.getSuites().getDefaultLIRSuites();
-
-        ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
-
-        GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
-        // copy all plugins from the host
-        Plugins plugins = new Plugins(phase.getGraphBuilderConfig().getPlugins());
-        GraphBuilderConfiguration baseConfig = graalTruffleRuntime.enableInfopoints() ? GraphBuilderConfiguration.getInfopointDefault(plugins) : GraphBuilderConfiguration.getDefault(plugins);
-        this.config = baseConfig.withSkippedExceptionTypes(skippedExceptionTypes);
-
-        this.partialEvaluator = new PartialEvaluator(providers, config, Graal.getRequiredCapability(SnippetReflectionProvider.class), backend.getTarget().arch);
-
-        if (Debug.isEnabled()) {
-            DebugEnvironment.initialize(System.out);
-        }
-    }
-
-    public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) {
-        ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length];
-        for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) {
-            skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]);
-        }
-        return skippedExceptionTypes;
-    }
-
-    public static final DebugTimer PartialEvaluationTime = Debug.timer("PartialEvaluationTime");
-    public static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
-    public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
-
-    public static final DebugMemUseTracker PartialEvaluationMemUse = Debug.memUseTracker("TrufflePartialEvaluationMemUse");
-    public static final DebugMemUseTracker CompilationMemUse = Debug.memUseTracker("TruffleCompilationMemUse");
-    public static final DebugMemUseTracker CodeInstallationMemUse = Debug.memUseTracker("TruffleCodeInstallationMemUse");
-
-    public void compileMethod(final OptimizedCallTarget compilable) {
-        StructuredGraph graph = null;
-
-        compilationNotify.notifyCompilationStarted(compilable);
-
-        try {
-            PhaseSuite<HighTierContext> graphBuilderSuite = createGraphBuilderSuite();
-
-            try (DebugCloseable a = PartialEvaluationTime.start(); DebugCloseable c = PartialEvaluationMemUse.start()) {
-                graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES);
-            }
-
-            if (Thread.currentThread().isInterrupted()) {
-                return;
-            }
-
-            compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph);
-            CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), graphBuilderSuite, compilable.getSpeculationLog(), compilable);
-            compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult);
-        } catch (Throwable t) {
-            System.out.println("compilation failed!?");
-            compilationNotify.notifyCompilationFailed(compilable, graph, t);
-            throw t;
-        }
-    }
-
-    public CompilationResult compileMethodHelper(StructuredGraph graph, String name, PhaseSuite<HighTierContext> graphBuilderSuite, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) {
-        try (Scope s = Debug.scope("TruffleFinal")) {
-            Debug.dump(1, graph, "After TruffleTier");
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-
-        CompilationResult result = null;
-        try (DebugCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); DebugCloseable c = CompilationMemUse.start()) {
-            CodeCacheProvider codeCache = providers.getCodeCache();
-            CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
-            CompilationResult compilationResult = new CompilationResult(name);
-            result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), graphBuilderSuite, Optimizations, getProfilingInfo(graph), speculationLog, suites, lirSuites,
-                            compilationResult, CompilationResultBuilderFactory.Default);
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-
-        compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph);
-
-        if (graph.isInlinedMethodRecordingEnabled()) {
-            result.setMethods(graph.method(), graph.getInlinedMethods());
-        } else {
-            assert result.getMethods() == null;
-        }
-
-        List<AssumptionValidAssumption> validAssumptions = new ArrayList<>();
-        Set<Assumption> newAssumptions = new HashSet<>();
-        for (Assumption assumption : graph.getAssumptions()) {
-            processAssumption(newAssumptions, assumption, validAssumptions);
-        }
-
-        if (result.getAssumptions() != null) {
-            for (Assumption assumption : result.getAssumptions()) {
-                processAssumption(newAssumptions, assumption, validAssumptions);
-            }
-        }
-
-        result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()]));
-
-        InstalledCode installedCode;
-        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); DebugCloseable a = CodeInstallationTime.start(); DebugCloseable c = CodeInstallationMemUse.start()) {
-            installedCode = providers.getCodeCache().addMethod(graph.method(), result, speculationLog, predefinedInstalledCode);
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-
-        for (AssumptionValidAssumption a : validAssumptions) {
-            a.getAssumption().registerInstalledCode(installedCode);
-        }
-
-        if (Debug.isLogEnabled()) {
-            Debug.log(providers.getCodeCache().disassemble(result, installedCode));
-        }
-        return result;
-    }
-
-    private PhaseSuite<HighTierContext> createGraphBuilderSuite() {
-        PhaseSuite<HighTierContext> suite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
-        ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
-        iterator.remove();
-        iterator.add(new GraphBuilderPhase(config));
-        return suite;
-    }
-
-    public void processAssumption(Set<Assumption> newAssumptions, Assumption assumption, List<AssumptionValidAssumption> manual) {
-        if (assumption != null) {
-            if (assumption instanceof AssumptionValidAssumption) {
-                AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption;
-                manual.add(assumptionValidAssumption);
-            } else {
-                newAssumptions.add(assumption);
-            }
-        }
-    }
-
-    public PartialEvaluator getPartialEvaluator() {
-        return partialEvaluator;
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Thu May 28 17:44:05 2015 +0200
@@ -170,5 +170,8 @@
 
     @Option(help = "Print additional more verbose Truffle compilation statistics at the end of a run.", type = OptionType.Debug)
     public static final OptionValue<Boolean> TruffleCompilationStatisticDetails = new OptionValue<>(false);
+
+    @Option(help = "Enable support for simple infopoints in truffle partial evaluations.", type = OptionType.Expert)
+    public static final OptionValue<Boolean> TruffleEnableInfopoints = new OptionValue<>(false);
     // @formatter:on
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleConstantReflectionProvider.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleConstantReflectionProvider.java	Thu May 28 17:44:05 2015 +0200
@@ -52,6 +52,10 @@
         return graalConstantReflection.readConstantArrayElement(array, index);
     }
 
+    public JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset) {
+        return graalConstantReflection.readConstantArrayElementForOffset(array, offset);
+    }
+
     public JavaConstant readConstantFieldValue(JavaField field0, JavaConstant receiver) {
         ResolvedJavaField field = (ResolvedJavaField) field0;
         if (!field.isStatic() && receiver.isNonNull()) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java	Thu May 28 17:44:05 2015 +0200
@@ -27,8 +27,6 @@
 
 public final class AssumptionValidAssumption extends Assumptions.Assumption {
 
-    private static final long serialVersionUID = 2010244979610891262L;
-
     private final OptimizedAssumption assumption;
 
     public AssumptionValidAssumption(OptimizedAssumption assumption) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java	Thu May 28 17:44:05 2015 +0200
@@ -53,11 +53,15 @@
     }
 
     private ObjectLocationIdentity(JavaConstant object) {
-        super(false);
         this.object = object;
     }
 
     @Override
+    public boolean isImmutable() {
+        return false;
+    }
+
+    @Override
     public String toString() {
         return "Identity(" + object + ")";
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Thu May 28 17:44:05 2015 +0200
@@ -34,8 +34,8 @@
     public static final NodeClass<NeverPartOfCompilationNode> TYPE = NodeClass.create(NeverPartOfCompilationNode.class);
     protected final String message;
 
-    public NeverPartOfCompilationNode(String message, FrameState stateAfter) {
-        super(TYPE, StampFactory.forVoid(), stateAfter);
+    public NeverPartOfCompilationNode(String message) {
+        super(TYPE, StampFactory.forVoid());
         this.message = message;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Thu May 28 17:44:05 2015 +0200
@@ -239,7 +239,7 @@
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) {
                 if (message.isConstant()) {
                     String messageString = message.asConstant().toValueString();
-                    b.add(new NeverPartOfCompilationNode(messageString, b.createStateAfter()));
+                    b.add(new NeverPartOfCompilationNode(messageString));
                     return true;
                 } else if (canDelayIntrinsification) {
                     return false;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Thu May 28 17:44:05 2015 +0200
@@ -182,7 +182,7 @@
 
     /**
      * Collects the effects of virtualizing the given node.
-     * 
+     *
      * @return {@code true} if the effects include removing the node, {@code false} otherwise.
      */
     protected abstract boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode);
@@ -210,6 +210,7 @@
 
         BlockT loopEntryState = initialState;
         BlockT lastMergedState = cloneState(initialState);
+        processInitialLoopState(loop, lastMergedState);
         MergeProcessor mergeProcessor = createMergeProcessor(loop.getHeader());
         for (int iteration = 0; iteration < 10; iteration++) {
             LoopInfo<BlockT> info = ReentrantBlockIterator.processLoop(this, loop, cloneState(lastMergedState));
@@ -245,6 +246,11 @@
         throw new GraalInternalError("too many iterations at %s", loop);
     }
 
+    @SuppressWarnings("unused")
+    protected void processInitialLoopState(Loop<Block> loop, BlockT initialState) {
+        // nothing to do
+    }
+
     private void doMergeWithoutDead(MergeProcessor mergeProcessor, List<BlockT> states) {
         int alive = 0;
         for (BlockT state : states) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Thu May 28 17:44:05 2015 +0200
@@ -115,7 +115,7 @@
         ValueNode cacheObject;
         ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
-            assert !obj.isVirtual();
+            assert !obj.isVirtual() : object;
             cacheObject = obj.getMaterializedValue();
         } else {
             cacheObject = object;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * 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,11 +27,13 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
@@ -212,6 +214,23 @@
     }
 
     @Override
+    protected void processInitialLoopState(Loop<Block> loop, PEReadEliminationBlockState initialState) {
+        super.processInitialLoopState(loop, initialState);
+
+        for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) {
+            ValueNode firstValue = phi.valueAt(0);
+            if (firstValue != null) {
+                firstValue = GraphUtil.unproxify(firstValue);
+                for (Map.Entry<ReadCacheEntry, ValueNode> entry : new ArrayList<>(initialState.getReadCache().entrySet())) {
+                    if (entry.getKey().object == firstValue) {
+                        initialState.addReadCache(phi, entry.getKey().identity, entry.getKey().index, entry.getValue(), this);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
     protected void processLoopExit(LoopExitNode exitNode, PEReadEliminationBlockState initialState, PEReadEliminationBlockState exitState, GraphEffectList effects) {
         super.processLoopExit(exitNode, initialState, exitState, effects);
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Thu May 28 17:44:05 2015 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.util.*;
 import com.oracle.graal.debug.*;
@@ -135,15 +136,21 @@
         FixedNode nextFixedNode = lastFixedNode == null ? null : lastFixedNode.next();
         VirtualUtil.trace("%s", node);
 
-        if (node instanceof VirtualizableAllocation) {
-            if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects)) {
+        if (requiresProcessing(node)) {
+            if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects) == false) {
+                return false;
+            }
+            if (tool.isDeleted()) {
                 VirtualUtil.trace("deleted virtualizable allocation %s", node);
                 return true;
             }
         }
         if (hasVirtualInputs.isMarked(node) && node instanceof ValueNode) {
             if (node instanceof Virtualizable) {
-                if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects)) {
+                if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects) == false) {
+                    return false;
+                }
+                if (tool.isDeleted()) {
                     VirtualUtil.trace("deleted virtualizable node %s", node);
                     return true;
                 }
@@ -159,6 +166,10 @@
         return false;
     }
 
+    protected boolean requiresProcessing(Node node) {
+        return node instanceof VirtualizableAllocation;
+    }
+
     private boolean processNodeWithScalarReplacedInputs(ValueNode node, FixedNode insertBefore, BlockT state, GraphEffectList effects) {
         ValueNode canonicalizedValue = node;
         if (node instanceof Canonicalizable.Unary<?>) {
@@ -264,8 +275,12 @@
 
     private boolean processVirtualizable(ValueNode node, FixedNode insertBefore, BlockT state, GraphEffectList effects) {
         tool.reset(state, node, insertBefore, effects);
-        ((Virtualizable) node).virtualize(tool);
-        return tool.isDeleted();
+        return virtualize(node, tool);
+    }
+
+    protected boolean virtualize(ValueNode node, VirtualizerTool vt) {
+        ((Virtualizable) node).virtualize(vt);
+        return true; // request further processing
     }
 
     private void processNodeWithState(NodeWithState nodeWithState, BlockT state, GraphEffectList effects) {
@@ -359,6 +374,20 @@
     }
 
     @Override
+    protected void processInitialLoopState(Loop<Block> loop, BlockT initialState) {
+        super.processInitialLoopState(loop, initialState);
+
+        for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) {
+            if (phi.valueAt(0) != null) {
+                ObjectState state = getObjectState(initialState, phi.valueAt(0));
+                if (state != null && state.isVirtual()) {
+                    addAndMarkAlias(state.virtual, phi);
+                }
+            }
+        }
+    }
+
+    @Override
     protected void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects) {
         if (exitNode.graph().hasValueProxies()) {
             Map<VirtualObjectNode, ProxyNode> proxies = Node.newMap();
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,7 @@
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.memory.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.CacheEntry;
 import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Thu May 28 17:44:05 2015 +0200
@@ -109,6 +109,12 @@
         return success;
     }
 
+    public static void trace(String format) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format);
+        }
+    }
+
     public static void trace(String format, Object obj) {
         if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
             Debug.logv(format, obj);
@@ -127,6 +133,12 @@
         }
     }
 
+    public static void trace(String format, Object obj, Object obj2, Object obj3, Object obj4) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format, obj, obj2, obj3, obj4);
+        }
+    }
+
     public static boolean matches(StructuredGraph graph, String filter) {
         if (filter != null) {
             return matchesHelper(graph, filter);
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,8 +23,8 @@
 package com.oracle.graal.word;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.HeapAccess.*;
 
 /**
  * Lowest-level memory access of native C memory. These methods access the raw memory without any
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,9 +30,9 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.memory.HeapAccess.*;
 
 public abstract class Word implements Signed, Unsigned, Pointer {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExpectError.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.dsl.test;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is internally known by the dsl processor and used to expect errors for testing
+ * purposes. This is not part of public API.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExpectError {
+
+    String[] value();
+
+}
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java	Thu May 28 17:44:05 2015 +0200
@@ -105,7 +105,6 @@
         }
 
         @Specialization(contains = "doPowCached", guards = {"exponent == cachedExponent", "cachedExponent <= 10"})
-        @ExplodeLoop
         double doPowCachedExponent(double base, int exponent, @Cached("exponent") int cachedExponent) {
             doPowCachedExponent++;
             double result = 1.0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/Compile.java	Thu May 28 17:44:05 2015 +0200
@@ -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.truffle.api.dsl.test.processor;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+import static org.junit.Assert.*;
+
+final class Compile implements DiagnosticListener<JavaFileObject> {
+    private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<>();
+    private final Map<String, byte[]> classes;
+    private final String sourceLevel;
+
+    private Compile(Class<?> processor, String code, String sl) {
+        this.sourceLevel = sl;
+        classes = compile(processor, code);
+    }
+
+    /**
+     * Performs compilation of given HTML page and associated Java code.
+     */
+    public static Compile create(Class<?> processor, String code) {
+        return new Compile(processor, code, "1.7");
+    }
+
+    /** Checks for given class among compiled resources. */
+    public byte[] get(String res) {
+        return classes.get(res);
+    }
+
+    /**
+     * Obtains errors created during compilation.
+     */
+    public List<Diagnostic<? extends JavaFileObject>> getErrors() {
+        List<Diagnostic<? extends JavaFileObject>> err;
+        err = new ArrayList<>();
+        for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
+            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+                err.add(diagnostic);
+            }
+        }
+        return err;
+    }
+
+    private Map<String, byte[]> compile(Class<?> processor, final String code) {
+        StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
+
+        final Map<String, ByteArrayOutputStream> class2BAOS;
+        class2BAOS = new HashMap<>();
+
+        JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
+            @Override
+            public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+                return code;
+            }
+        };
+
+        JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
+            @Override
+            public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
+                if (kind == Kind.CLASS) {
+                    final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+                    class2BAOS.put(className.replace('.', '/') + ".class", buffer);
+                    return new SimpleJavaFileObject(sibling.toUri(), kind) {
+                        @Override
+                        public OutputStream openOutputStream() {
+                            return buffer;
+                        }
+                    };
+                }
+
+                if (kind == Kind.SOURCE) {
+                    final String n = className.replace('.', '/') + ".java";
+                    final URI un;
+                    try {
+                        un = new URI("mem://" + n);
+                    } catch (URISyntaxException ex) {
+                        throw new IOException(ex);
+                    }
+                    return new VirtFO(un/* sibling.toUri() */, kind, n);
+                }
+
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public boolean isSameFile(FileObject a, FileObject b) {
+                if (a instanceof VirtFO && b instanceof VirtFO) {
+                    return ((VirtFO) a).getName().equals(((VirtFO) b).getName());
+                }
+
+                return super.isSameFile(a, b);
+            }
+
+            class VirtFO extends SimpleJavaFileObject {
+
+                private final String n;
+
+                public VirtFO(URI uri, Kind kind, String n) {
+                    super(uri, kind);
+                    this.n = n;
+                }
+
+                private final ByteArrayOutputStream data = new ByteArrayOutputStream();
+
+                @Override
+                public OutputStream openOutputStream() {
+                    return data;
+                }
+
+                @Override
+                public String getName() {
+                    return n;
+                }
+
+                @Override
+                public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+                    data.close();
+                    return new String(data.toByteArray());
+                }
+            }
+        };
+        List<String> args = Arrays.asList("-source", sourceLevel, "-target", "1.7", //
+                        "-processor", processor.getName());
+
+        ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, args, null, Arrays.asList(file)).call();
+
+        Map<String, byte[]> result = new HashMap<>();
+
+        for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
+            result.put(e.getKey(), e.getValue().toByteArray());
+        }
+
+        return result;
+    }
+
+    @Override
+    public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+        errors.add(diagnostic);
+    }
+
+    void assertErrors() {
+        assertFalse("There are supposed to be some errors", getErrors().isEmpty());
+    }
+
+    void assertNoErrors() {
+        assertTrue("There are supposed to be no errors: " + getErrors(), getErrors().isEmpty());
+    }
+
+    void assertError(String expMsg) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Can't find ").append(expMsg).append(" among:");
+        for (Diagnostic<? extends JavaFileObject> e : errors) {
+            String msg = e.getMessage(Locale.US);
+            if (msg.contains(expMsg)) {
+                return;
+            }
+            sb.append("\n");
+            sb.append(msg);
+        }
+        fail(sb.toString());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.dsl.test.processor;
+
+import java.io.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.test.*;
+import com.oracle.truffle.api.source.*;
+
+public class LanguageRegistrationTest {
+
+    @ExpectError("Registered language class must be public")
+    @TruffleLanguage.Registration(name = "myLang", mimeType = "text/x-my")
+    private static final class MyLang {
+    }
+
+    @ExpectError("Registered language inner-class must be static")
+    @TruffleLanguage.Registration(name = "myLangNonStatic", mimeType = "text/x-my")
+    public final class MyLangNonStatic {
+    }
+
+    @ExpectError("Registered language class must subclass TruffleLanguage")
+    @TruffleLanguage.Registration(name = "myLang", mimeType = "text/x-my")
+    public static final class MyLangNoSubclass {
+    }
+
+    @ExpectError("Language must have a public constructor accepting TruffleLanguage.Env as parameter")
+    @TruffleLanguage.Registration(name = "myLangNoCnstr", mimeType = "text/x-my")
+    public static final class MyLangWrongConstr extends TruffleLanguage {
+        private MyLangWrongConstr() {
+            super(null);
+        }
+
+        @Override
+        protected Object eval(Source code) throws IOException {
+            return null;
+        }
+
+        @Override
+        protected Object findExportedSymbol(String globalName) {
+            return null;
+        }
+
+        @Override
+        protected Object getLanguageGlobal() {
+            return null;
+        }
+
+        @Override
+        protected boolean isObjectOfLanguage(Object object) {
+            return false;
+        }
+    }
+
+    @ExpectError("Language must have a public constructor accepting TruffleLanguage.Env as parameter")
+    @TruffleLanguage.Registration(name = "myLangNoCnstr", mimeType = "text/x-my")
+    public static final class MyLangNoConstr extends TruffleLanguage {
+        public MyLangNoConstr() {
+            super(null);
+        }
+
+        @Override
+        protected Object eval(Source code) throws IOException {
+            return null;
+        }
+
+        @Override
+        protected Object findExportedSymbol(String globalName) {
+            return null;
+        }
+
+        @Override
+        protected Object getLanguageGlobal() {
+            return null;
+        }
+
+        @Override
+        protected boolean isObjectOfLanguage(Object object) {
+            return false;
+        }
+    }
+
+    @TruffleLanguage.Registration(name = "myLangGood", mimeType = "text/x-my")
+    public static final class MyLangGood extends TruffleLanguage {
+        public MyLangGood(TruffleLanguage.Env env) {
+            super(env);
+        }
+
+        @Override
+        protected Object eval(Source code) throws IOException {
+            return null;
+        }
+
+        @Override
+        protected Object findExportedSymbol(String globalName) {
+            return null;
+        }
+
+        @Override
+        protected Object getLanguageGlobal() {
+            return null;
+        }
+
+        @Override
+        protected boolean isObjectOfLanguage(Object object) {
+            return false;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/TruffleProcessorTest.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.dsl.test.processor;
+
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import javax.annotation.processing.*;
+import javax.tools.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.dsl.test.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.dsl.processor.verify.*;
+
+/**
+ * Verify errors emitted by the processor.
+ */
+public class TruffleProcessorTest {
+    //
+    // AnnotationProcessor test using the NetBeans style
+    //
+
+    @Test
+    public void childCannotBeFinal() throws Exception {
+        // @formatter:off
+        String code = "package x.y.z;\n" +
+            "import com.oracle.truffle.api.nodes.Node;\n" +
+            "abstract class MyNode extends Node {\n" +
+            "  @Child final MyNode first;\n" +
+            "  MyNode(MyNode n) {\n" +
+            "    this.first = n;\n" +
+            "  };\n" +
+            "}\n";
+        // @formatter:on
+
+        Compile c = Compile.create(VerifyTruffleProcessor.class, code);
+        c.assertErrors();
+        boolean ok = false;
+        StringBuilder msgs = new StringBuilder();
+        for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
+            String msg = e.getMessage(Locale.ENGLISH);
+            if (msg.contains("cannot be final")) {
+                ok = true;
+            }
+            msgs.append("\n").append(msg);
+        }
+        if (!ok) {
+            fail("Should contain warning about final:" + msgs);
+        }
+    }
+
+    @Test
+    public void workAroundCannonicalDependency() throws Exception {
+        Class<?> myProc = VerifyTruffleProcessor.class;
+        assertNotNull(myProc);
+        StringBuilder sb = new StringBuilder();
+        sb.append("Cannot find ").append(myProc);
+        for (Processor load : ServiceLoader.load(Processor.class)) {
+            sb.append("Found ").append(load);
+            if (myProc.isInstance(load)) {
+                return;
+            }
+        }
+        fail(sb.toString());
+    }
+
+    //
+    // and now the Truffle traditional way
+    //
+
+    abstract class MyNode extends Node {
+        @ExpectError("@Child field cannot be final") @Child final MyNode first;
+
+        MyNode(MyNode n) {
+            this.first = n;
+        }
+    }
+}
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ExpectError.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.dsl;
-
-import java.lang.annotation.*;
-
-/**
- * This annotation is internally known by the dsl processor and used to expect errors for testing
- * purposes. This is not part of public API.
- */
-@Retention(RetentionPolicy.RUNTIME)
-public @interface ExpectError {
-
-    String[] value();
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.test.instrument;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdvancedInstrumentCounterRoot;
+
+/**
+ * Tests the kind of instrumentation where a client can provide an AST fragment to be
+ * <em>spliced</em> directly into the AST.
+ */
+public class AdvancedInstrumentTest {
+
+    @Test
+    public void testAdvancedInstrumentListener() {
+        // Create a simple addition AST
+        final TruffleRuntime runtime = Truffle.getRuntime();
+        final TestValueNode leftValueNode = new TestValueNode(6);
+        final TestValueNode rightValueNode = new TestValueNode(7);
+        final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode);
+        final TestRootNode rootNode = new TestRootNode(addNode);
+        final CallTarget callTarget1 = runtime.createCallTarget(rootNode);
+
+        // Ensure it executes correctly
+        assertEquals(13, callTarget1.call());
+
+        // Probe the addition node
+        final Probe probe = addNode.probe();
+
+        assertEquals(13, callTarget1.call());
+
+        // Attach a null factory; it never actually attaches a node.
+        final Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() {
+
+            public AdvancedInstrumentRoot createInstrumentRoot(Probe p, Node n) {
+                return null;
+            }
+        }, null, "test AdvancedInstrument");
+        probe.attach(instrument);
+
+        assertEquals(13, callTarget1.call());
+
+        final TestAdvancedInstrumentCounterRoot counter = new TestAdvancedInstrumentCounterRoot();
+
+        // Attach a factory that splices an execution counter into the AST.
+        probe.attach(Instrument.create(null, new AdvancedInstrumentRootFactory() {
+
+            public AdvancedInstrumentRoot createInstrumentRoot(Probe p, Node n) {
+                return counter;
+            }
+        }, null, "test AdvancedInstrument"));
+        assertEquals(0, counter.getCount());
+
+        assertEquals(13, callTarget1.call());
+
+        assertEquals(1, counter.getCount());
+    }
+}
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java	Thu May 28 17:44:05 2015 +0200
@@ -167,12 +167,12 @@
         }
     }
 
-    static class TestToolEvalCounterNode extends ToolEvalNode {
+    static class TestAdvancedInstrumentCounterRoot extends AdvancedInstrumentRoot {
 
         private long count;
 
         @Override
-        public Object executeToolEvalNode(Node node, VirtualFrame vFrame) {
+        public Object executeRoot(Node node, VirtualFrame vFrame) {
             count++;
             return null;
         }
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/ToolEvalInstrumentTest.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.test.instrument;
-
-import static org.junit.Assert.*;
-
-import org.junit.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode;
-import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode;
-import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode;
-import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestToolEvalCounterNode;
-
-/**
- * Tests the kind of instrumentation where a client can provide an AST fragment to be
- * <em>spliced</em> directly into the AST.
- */
-public class ToolEvalInstrumentTest {
-
-    @Test
-    public void testSpliceInstrumentListener() {
-        // Create a simple addition AST
-        final TruffleRuntime runtime = Truffle.getRuntime();
-        final TestValueNode leftValueNode = new TestValueNode(6);
-        final TestValueNode rightValueNode = new TestValueNode(7);
-        final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode);
-        final TestRootNode rootNode = new TestRootNode(addNode);
-        final CallTarget callTarget1 = runtime.createCallTarget(rootNode);
-
-        // Ensure it executes correctly
-        assertEquals(13, callTarget1.call());
-
-        // Probe the addition node
-        final Probe probe = addNode.probe();
-
-        assertEquals(13, callTarget1.call());
-
-        // Attach a null listener; it never actually attaches a node.
-        final Instrument instrument = Instrument.create(new ToolEvalNodeFactory() {
-
-            public ToolEvalNode createToolEvalNode(Probe p, Node n) {
-                return null;
-            }
-        }, null);
-        probe.attach(instrument);
-
-        assertEquals(13, callTarget1.call());
-
-        final TestToolEvalCounterNode counter = new TestToolEvalCounterNode();
-
-        // Attach a listener that splices an execution counter into the AST.
-        probe.attach(Instrument.create(new ToolEvalNodeFactory() {
-
-            public ToolEvalNode createToolEvalNode(Probe p, Node n) {
-                return counter;
-            }
-        }, null));
-        assertEquals(0, counter.getCount());
-
-        assertEquals(13, callTarget1.call());
-
-        assertEquals(1, counter.getCount());
-
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.test.vm;
+
+import com.oracle.truffle.api.vm.TruffleVM;
+import java.util.Random;
+import org.junit.Test;
+
+/**
+ * A collection of tests that can certify language implementaiton to be complient with most recent
+ * requirements of the Truffle infrastructure and tooling. Subclass, implement abstract methods and
+ * include in your test suite.
+ */
+public class TruffleTCK { // abstract
+    private TruffleVM tckVM;
+
+    public TruffleTCK() { // protected
+    }
+
+    /**
+     * This methods is called before first test is executed. It's purpose is to set a TruffleVM with
+     * your language up, so it is ready for testing.
+     * {@link TruffleVM#eval(java.lang.String, java.lang.String) Execute} any scripts you need, and
+     * prepare global symbols with proper names. The symbols will then be looked up by the
+     * infastructure (using the names provided by you from methods like {@link #plusInt()}) and used
+     * for internal testing.
+     *
+     * @return initialized Truffle virtual machine
+     * @throws java.lang.Exception thrown when the VM preparation fails
+     */
+    protected TruffleVM prepareVM() throws Exception { // abstract
+        return null;
+    }
+
+    /**
+     * Name of function which will return value 42 as a number. The return value of the method
+     * should be instance of {@link Number} and its {@link Number#intValue()} should return
+     * <code>42</code>.
+     *
+     * @return name of globally exported symbol
+     */
+    protected String fourtyTwo() { // abstract
+        return null;
+    }
+
+    /**
+     * Name of function to add two integer values together. The symbol will be invoked with two
+     * parameters of type {@link Integer} and expects result of type {@link Number} which's
+     * {@link Number#intValue()} is equivalent of <code>param1 + param2</code>.
+     *
+     * @return name of globally exported symbol
+     */
+    protected String plusInt() {  // abstract
+        return null;
+    }
+
+    private TruffleVM vm() throws Exception {
+        if (tckVM == null) {
+            tckVM = prepareVM();
+        }
+        return tckVM;
+    }
+
+    //
+    // The tests
+    //
+
+    @Test
+    public void testFortyTwo() throws Exception {
+        if (getClass() == TruffleTCK.class) {
+            return;
+        }
+        TruffleVM.Symbol fourtyTwo = findGlobalSymbol(fourtyTwo());
+
+        Object res = fourtyTwo.invoke(null);
+
+        assert res instanceof Number : "should yield a number, but was: " + res;
+
+        Number n = (Number) res;
+
+        assert 42 == n.intValue() : "The value is 42 =  " + n.intValue();
+    }
+
+    @Test
+    public void testPlusWithInts() throws Exception {
+        if (getClass() == TruffleTCK.class) {
+            return;
+        }
+        Random r = new Random();
+        int a = r.nextInt(100);
+        int b = r.nextInt(100);
+
+        TruffleVM.Symbol plus = findGlobalSymbol(plusInt());
+
+        Object res = plus.invoke(null, a, b);
+
+        assert res instanceof Number : "+ on two ints should yield a number, but was: " + res;
+
+        Number n = (Number) res;
+
+        assert a + b == n.intValue() : "The value is correct: (" + a + " + " + b + ") =  " + n.intValue();
+    }
+
+    private TruffleVM.Symbol findGlobalSymbol(String name) throws Exception {
+        TruffleVM.Symbol s = vm().findGlobalSymbol(name);
+        assert s != null : "Symbol " + name + " is not found!";
+        return s;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.test.vm;
+
+import com.oracle.truffle.api.vm.TruffleVM;
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TruffleVMSingleThreadedTest {
+    TruffleVM tvm;
+
+    @Before
+    public void initInDifferentThread() throws InterruptedException {
+        final TruffleVM.Builder b = TruffleVM.newVM();
+        Thread t = new Thread("Initializer") {
+            @Override
+            public void run() {
+                tvm = b.build();
+            }
+        };
+        t.start();
+        t.join();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void evalURI() throws IOException, URISyntaxException {
+        tvm.eval(new URI("http://unknown.js"));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void evalString() throws IOException {
+        tvm.eval("text/javascript", "1 + 1");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void evalReader() throws IOException {
+        try (StringReader sr = new StringReader("1 + 1")) {
+            tvm.eval("text/javascript", sr);
+        }
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void findGlobalSymbol() {
+        tvm.findGlobalSymbol("doesNotExists");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api;
+
+import com.oracle.truffle.api.impl.Accessor;
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.vm.TruffleVM;
+import com.oracle.truffle.api.vm.TruffleVM.Language;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Constructor;
+
+/**
+ * An entry point for everyone who wants to implement a Truffle based language. By providing
+ * implementation of this type and registering it using {@link Registration} annotation, your
+ * language becomes accessible to users of the {@link TruffleVM Truffle virtual machine} - all they
+ * will need to do is to include your JAR into their application and all the Truffle goodies (multi
+ * language support, multi tennat hosting, debugging, etc.) will be made available to them.
+ */
+public abstract class TruffleLanguage {
+    private final Env env;
+
+    /**
+     * Constructor to be called by subclasses.
+     *
+     * @param env language environment that will be available via {@link #env()} method to
+     *            subclasses.
+     */
+    protected TruffleLanguage(Env env) {
+        this.env = env;
+    }
+
+    /**
+     * The annotation to use to register your language to the {@link TruffleVM Truffle} system. By
+     * annotating your implementation of {@link TruffleLanguage} by this annotation you are just a
+     * <em>one JAR drop to the classpath</em> away from your users. Once they include your JAR in
+     * their application, your language will be available to the {@link TruffleVM Truffle virtual
+     * machine}.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @Target(ElementType.TYPE)
+    public @interface Registration {
+        /**
+         * Unique name of your language. This name will be exposed to users via the
+         * {@link Language#getName()} getter.
+         *
+         * @return identifier of your language
+         */
+        String name();
+
+        /**
+         * List of mimetypes associated with your language. Users will use them (directly or
+         * inderectly) when {@link TruffleVM#eval(java.lang.String, java.lang.String) executing}
+         * their code snippets or their {@link TruffleVM#eval(java.net.URI) files}.
+         *
+         * @return array of mime types assigned to your language files
+         */
+        String[] mimeType();
+    }
+
+    protected final Env env() {
+        if (this.env == null) {
+            throw new NullPointerException("Accessing env before initialization is finished");
+        }
+        return this.env;
+    }
+
+    protected abstract Object eval(Source code) throws IOException;
+
+    /**
+     * Called when some other language is seeking for a global symbol. This method is supposed to do
+     * lazy binding, e.g. there is no need to export symbols in advance, it is fine to wait until
+     * somebody asks for it (by calling this method).
+     * <p>
+     * The exported object can either be <code>TruffleObject</code> (e.g. a native object from the
+     * other language) to support interoperability between languages or one of Java primitive
+     * wrappers ( {@link Integer}, {@link Double}, {@link Short}, etc.).
+     *
+     * @param globalName the name of the global symbol to find
+     * @return an exported object or <code>null</code>, if the symbol does not represent anything
+     *         meaningful in this language
+     */
+    protected abstract Object findExportedSymbol(String globalName);
+
+    /**
+     * Returns global object for the language.
+     * <p>
+     * The object is expected to be <code>TruffleObject</code> (e.g. a native object from the other
+     * language) but technically it can be one of Java primitive wrappers ({@link Integer},
+     * {@link Double}, {@link Short}, etc.).
+     *
+     * @return the global object or <code>null</code> if the language does not support such concept
+     */
+    protected abstract Object getLanguageGlobal();
+
+    /**
+     * Checks whether the object is provided by this language.
+     *
+     * @param object the object to check
+     * @return <code>true</code> if this language can deal with such object in native way
+     */
+    protected abstract boolean isObjectOfLanguage(Object object);
+
+    /**
+     * Represents execution environment of the {@link TruffleLanguage}. Each active
+     * {@link TruffleLanguage} receives instance of the environment before any code is executed upon
+     * it. The environment has knowledge of all active languages and can exchange symbols between
+     * them.
+     */
+    public static final class Env {
+        private final TruffleVM vm;
+        private final TruffleLanguage lang;
+        private final Reader in;
+        private final Writer err;
+        private final Writer out;
+
+        Env(TruffleVM vm, Constructor<?> langConstructor, Writer out, Writer err, Reader in) {
+            this.vm = vm;
+            this.in = in;
+            this.err = err;
+            this.out = out;
+            try {
+                this.lang = (TruffleLanguage) langConstructor.newInstance(this);
+            } catch (Exception ex) {
+                throw new IllegalStateException("Cannot construct language " + langConstructor.getDeclaringClass().getName(), ex);
+            }
+        }
+
+        /**
+         * Asks the environment to go through other registered languages and find whether they
+         * export global symbol of specified name. The expected return type is either
+         * <code>TruffleObject</code>, or one of wrappers of Java primitive types ({@link Integer},
+         * {@link Double}).
+         *
+         * @param globalName the name of the symbol to search for
+         * @return object representing the symbol or <code>null</code>
+         */
+        public Object importSymbol(String globalName) {
+            return API.importSymbol(vm, lang, globalName);
+        }
+
+        /**
+         * Input associated with this {@link TruffleVM}.
+         *
+         * @return reader, never <code>null</code>
+         */
+        public Reader stdIn() {
+            return in;
+        }
+
+        /**
+         * Standard output writer for this {@link TruffleVM}.
+         *
+         * @return writer, never <code>null</code>
+         */
+        public Writer stdOut() {
+            return out;
+        }
+
+        /**
+         * Standard error writer for this {@link TruffleVM}.
+         *
+         * @return writer, never <code>null</code>
+         */
+        public Writer stdErr() {
+            return err;
+        }
+    }
+
+    private static final AccessAPI API = new AccessAPI();
+
+    private static final class AccessAPI extends Accessor {
+        @Override
+        protected TruffleLanguage attachEnv(TruffleVM vm, Constructor<?> langClazz, Writer stdOut, Writer stdErr, Reader stdIn) {
+            Env env = new Env(vm, langClazz, stdOut, stdErr, stdIn);
+            return env.lang;
+        }
+
+        @Override
+        public Object importSymbol(TruffleVM vm, TruffleLanguage queryingLang, String globalName) {
+            return super.importSymbol(vm, queryingLang, globalName);
+        }
+
+        @Override
+        protected Object eval(TruffleLanguage l, Source s) throws IOException {
+            return l.eval(s);
+        }
+
+        @Override
+        protected Object findExportedSymbol(TruffleLanguage l, String globalName) {
+            return l.findExportedSymbol(globalName);
+        }
+
+        @Override
+        protected Object languageGlobal(TruffleLanguage l) {
+            return l.getLanguageGlobal();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.impl;
+
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.vm.TruffleVM;
+import com.oracle.truffle.api.source.Source;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ServiceLoader;
+
+/**
+ * Communication between TruffleVM and TruffleLanguage API/SPI.
+ */
+public abstract class Accessor {
+    private static Accessor API;
+    private static Accessor SPI;
+    static {
+        TruffleLanguage lng = new TruffleLanguage(null) {
+            @Override
+            protected Object eval(Source code) throws IOException {
+                return null;
+            }
+
+            @Override
+            protected Object findExportedSymbol(String globalName) {
+                return null;
+            }
+
+            @Override
+            protected Object getLanguageGlobal() {
+                return null;
+            }
+
+            @Override
+            protected boolean isObjectOfLanguage(Object object) {
+                return false;
+            }
+        };
+        lng.hashCode();
+    }
+
+    protected Accessor() {
+        if (this.getClass().getSimpleName().endsWith("API")) {
+            if (API != null) {
+                throw new IllegalStateException();
+            }
+            API = this;
+        } else {
+            if (SPI != null) {
+                throw new IllegalStateException();
+            }
+            SPI = this;
+        }
+    }
+
+    protected TruffleLanguage attachEnv(TruffleVM vm, Constructor<?> langClazz, Writer stdOut, Writer stdErr, Reader stdIn) {
+        return API.attachEnv(vm, langClazz, stdOut, stdErr, stdIn);
+    }
+
+    protected Object eval(TruffleLanguage l, Source s) throws IOException {
+        return API.eval(l, s);
+    }
+
+    protected Object importSymbol(TruffleVM vm, TruffleLanguage queryingLang, String globalName) {
+        return SPI.importSymbol(vm, queryingLang, globalName);
+    }
+
+    protected Object findExportedSymbol(TruffleLanguage l, String globalName) {
+        return API.findExportedSymbol(l, globalName);
+    }
+
+    protected Object languageGlobal(TruffleLanguage l) {
+        return API.languageGlobal(l);
+    }
+
+    protected Object invoke(Object obj, Object[] args) throws IOException {
+        for (SymbolInvoker si : ServiceLoader.load(SymbolInvoker.class)) {
+            return si.invoke(obj, args);
+        }
+        throw new IOException("No symbol invoker found!");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/SymbolInvoker.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.impl;
+
+import java.io.IOException;
+
+/**
+ * XXX: Temporary class to make unit tests pass without messing with Message implementations and
+ * associated nodes too much.
+ */
+public abstract class SymbolInvoker {
+    protected abstract Object invoke(Object symbol, Object... args) throws IOException;
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -63,4 +63,9 @@
      */
     String printTreeToString(Node node, int maxDepth);
 
+    /**
+     * Creates a textual display describing a single (non-wrapper) node, including instrumentation
+     * status: if Probed, and any tags.
+     */
+    String printNodeWithInstrumentation(Node node);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentResultListener.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Listener for receiving the result a client-provided {@linkplain AdvancedInstrumentRoot AST
+ * fragment}, when executed by a
+ * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
+ * Advanced Instrument}.
+ *
+ * @see Instrument
+ * @see AdvancedInstrumentRoot
+ * @see AdvancedInstrumentRootFactory
+ */
+public interface AdvancedInstrumentResultListener {
+
+    /**
+     * Notifies listener that a client-provided {@linkplain AdvancedInstrumentRoot AST fragment} has
+     * been executed by an
+     * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
+     * Advanced Instrument} with the specified result, possibly {@code null}.
+     * <p>
+     * <strong>Note: </strong> Truffle will attempt to optimize implementations through partial
+     * evaluation; annotate with {@link TruffleBoundary} if this should not be permitted.
+     *
+     * @param node the guest-language AST node to which the host Instrument's {@link Probe} is
+     *            attached
+     * @param vFrame execution frame at the guest-language AST node
+     * @param result the result of this AST fragment's execution
+     */
+    void notifyResult(Node node, VirtualFrame vFrame, Object result);
+
+    /**
+     * Notifies listener that execution of client-provided {@linkplain AdvancedInstrumentRoot AST
+     * fragment} filed during execution by a @linkplain
+     * Instrument#create(AdvancedInstrumentRootFactory, String) Advanced Instrument}.
+     * <p>
+     * <strong>Note: </strong> Truffle will attempt to optimize implementations through partial
+     * evaluation; annotate with {@link TruffleBoundary} if this should not be permitted.
+     *
+     * @param node the guest-language AST node to which the host Instrument's {@link Probe} is
+     *            attached
+     * @param vFrame execution frame at the guest-language AST node
+     * @param ex the exception
+     */
+    void notifyFailure(Node node, VirtualFrame vFrame, RuntimeException ex);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRoot.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Root of a client-provided AST fragment that can be executed efficiently, subject to full Truffle
+ * optimization, by an
+ * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
+ * Advanced Instrument}.
+ *
+ * @see Instrument
+ * @see AdvancedInstrumentRootFactory
+ * @see AdvancedInstrumentResultListener
+ */
+public abstract class AdvancedInstrumentRoot extends Node implements InstrumentationNode {
+
+    /**
+     * Executes this AST fragment on behalf of a client {@link Instrument}, just before the
+     * guest-language AST node to which the {@link Probe} holding the Instrument is executed.
+     *
+     * @param node the guest-language AST node to which the host Instrument's Probe is attached
+     * @param vFrame execution frame at the guest-language AST node
+     * @return the result of this AST fragment's execution
+     */
+    public abstract Object executeRoot(Node node, VirtualFrame vFrame);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRootFactory.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Creator of {@linkplain AdvancedInstrumentRoot AST fragments} suitable for efficient execution,
+ * subject to full Truffle optimization, by an
+ * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
+ * Advanced Instrument}.
+ *
+ * @see Instrument
+ * @see AdvancedInstrumentRoot
+ */
+public interface AdvancedInstrumentRootFactory {
+
+    /**
+     * Provider of {@linkplain AdvancedInstrumentRoot AST fragment} instances to be executed by the
+     * Instrumentation Framework at a {@linkplain Probe Probed} site in a guest-language AST.
+     * <p>
+     * <strong>Notes:</strong>
+     * <ul>
+     * <li>Once the factory has produced an AST fragment at a particular {@linkplain Node AST Node},
+     * it will not be called again at that Node.</li>
+     * <li>In some use cases, for example to implement a breakpoint at a specific program location,
+     * the Probe argument will be the same for every call. Each Node argument will represent the
+     * same program location associated with the Probe, but in different clones of the AST.</li>
+     * <li>In other use cases, for example to implement a breakpoint at any Node with a particular
+     * {@linkplain SyntaxTag tag}, both the Probe and Node argument may differ. Implementations that
+     * are sensitive to the lexical context in which the AST fragment will be evaluated must take
+     * care to build a new, possibly different AST fragment for each request.</li>
+     * </ul>
+     *
+     * @param probe the Probe to which the Instrument requesting the AST fragment is attached
+     * @param node the guest-language AST location that is the context in which the requesting
+     *            Instrument must execute the AST fragment.
+     * @return a newly created AST fragment suitable for execution, via instrumentation, in the
+     *         execution context of the specified guest-language AST site.
+     */
+    AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node);
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Thu May 28 17:44:05 2015 +0200
@@ -31,7 +31,7 @@
 import com.oracle.truffle.api.source.*;
 
 // TODO (mlvdv) these statics should not be global.  Move them to some kind of context.
-// TODO (mlvdv) migrate factory into .impl (together with Probe)? break out nested classes?
+// TODO (mlvdv) migrate factory (together with Probe)? break out nested classes?
 
 /**
  * A <em>binding</em> between:
@@ -127,16 +127,22 @@
     }
 
     /**
-     * Creates a <em>Tool Eval Instrument</em>: this Instrument executes efficiently, subject to
+     * Creates an <em>Advanced Instrument</em>: this Instrument executes efficiently, subject to
      * full Truffle optimization, a client-provided AST fragment every time the Probed node is
      * entered.
+     * <p>
+     * Any {@link RuntimeException} thrown by execution of the fragment is caught by the framework
+     * and reported to the listener; there is no other notification.
      *
-     * @param toolEvalNodeFactory provider of AST fragments on behalf of the client
+     * @param resultListener optional client callback for results/failure notification
+     * @param rootFactory provider of AST fragments on behalf of the client
+     * @param requiredResultType optional requirement, any non-assignable result is reported to the
+     *            the listener, if any, as a failure
      * @param instrumentInfo optional description of the instrument's role, intended for debugging.
      * @return a new instrument, ready for attachment at a probe
      */
-    public static Instrument create(ToolEvalNodeFactory toolEvalNodeFactory, String instrumentInfo) {
-        return new ToolEvalInstrument(toolEvalNodeFactory, instrumentInfo);
+    public static Instrument create(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) {
+        return new AdvancedInstrument(resultListener, rootFactory, requiredResultType, instrumentInfo);
     }
 
     // TODO (mlvdv) experimental
@@ -379,22 +385,22 @@
      * within a Probe's <em>instrumentation chain</em>, and thus directly in the executing Truffle
      * AST with potential for full optimization.
      */
-    private static final class ToolEvalInstrument extends Instrument {
+    private static final class AdvancedInstrument extends Instrument {
+
+        private final AdvancedInstrumentResultListener resultListener;
+        private final AdvancedInstrumentRootFactory rootFactory;
+        private final Class<?> requiredResultType;
 
-        /**
-         * Client-provided supplier of new node instances to attach.
-         */
-        private final ToolEvalNodeFactory toolEvalNodeFactory;
-
-        private ToolEvalInstrument(ToolEvalNodeFactory toolEvalNodeFactory, String instrumentInfo) {
+        private AdvancedInstrument(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) {
             super(instrumentInfo);
-            this.toolEvalNodeFactory = toolEvalNodeFactory;
-
+            this.resultListener = resultListener;
+            this.rootFactory = rootFactory;
+            this.requiredResultType = requiredResultType;
         }
 
         @Override
         AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
-            return new ToolEvalNodeInstrumentNode(nextNode);
+            return new AdvancedInstrumentNode(nextNode);
         }
 
         @Override
@@ -406,7 +412,7 @@
                     return instrumentNode.nextInstrumentNode;
                 }
                 // Match not at the head of the chain; remove it.
-                found = instrumentNode.removeFromChain(ToolEvalInstrument.this);
+                found = instrumentNode.removeFromChain(AdvancedInstrument.this);
             }
             if (!found) {
                 throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
@@ -415,35 +421,62 @@
         }
 
         /**
-         * Node that implements a {@link ToolEvalInstrument} in a particular AST.
+         * Node that implements a {@link AdvancedInstrument} in a particular AST.
          */
         @NodeInfo(cost = NodeCost.NONE)
-        private final class ToolEvalNodeInstrumentNode extends AbstractInstrumentNode {
+        private final class AdvancedInstrumentNode extends AbstractInstrumentNode {
 
-            @Child ToolEvalNode toolEvalNode;
+            @Child private AdvancedInstrumentRoot instrumentRoot;
 
-            private ToolEvalNodeInstrumentNode(AbstractInstrumentNode nextNode) {
+            private AdvancedInstrumentNode(AbstractInstrumentNode nextNode) {
                 super(nextNode);
             }
 
             public void enter(Node node, VirtualFrame vFrame) {
-                if (toolEvalNode == null) {
-                    final ToolEvalNode newToolEvalNodeNode = ToolEvalInstrument.this.toolEvalNodeFactory.createToolEvalNode(ToolEvalInstrument.this.probe, node);
-                    if (newToolEvalNodeNode != null) {
-                        toolEvalNode = newToolEvalNodeNode;
-                        adoptChildren();
-                        ToolEvalInstrument.this.probe.invalidateProbeUnchanged();
+                if (instrumentRoot == null) {
+                    try {
+                        final AdvancedInstrumentRoot newInstrumentRoot = AdvancedInstrument.this.rootFactory.createInstrumentRoot(AdvancedInstrument.this.probe, node);
+                        if (newInstrumentRoot != null) {
+                            instrumentRoot = newInstrumentRoot;
+                            adoptChildren();
+                            AdvancedInstrument.this.probe.invalidateProbeUnchanged();
+                        }
+                    } catch (RuntimeException ex) {
+                        if (resultListener != null) {
+                            resultListener.notifyFailure(node, vFrame, ex);
+                        }
                     }
                 }
-                if (toolEvalNode != null) {
-                    // TODO (mlvdv) should report exception ; non-trivial architectural change
-                    toolEvalNode.executeToolEvalNode(node, vFrame);
+                if (instrumentRoot != null) {
+                    try {
+                        final Object result = instrumentRoot.executeRoot(node, vFrame);
+                        if (resultListener != null) {
+                            checkResultType(result);
+                            resultListener.notifyResult(node, vFrame, result);
+                        }
+                    } catch (RuntimeException ex) {
+                        if (resultListener != null) {
+                            resultListener.notifyFailure(node, vFrame, ex);
+                        }
+                    }
                 }
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.enter(node, vFrame);
                 }
             }
 
+            private void checkResultType(Object result) {
+                if (requiredResultType == null) {
+                    return;
+                }
+                if (result == null) {
+                    throw new RuntimeException("Instrument result null: " + requiredResultType.getSimpleName() + " is required");
+                }
+                if (!(requiredResultType.isAssignableFrom(result.getClass()))) {
+                    throw new RuntimeException("Instrument result " + result.toString() + " not assignable to " + requiredResultType.getSimpleName());
+                }
+            }
+
             public void returnVoid(Node node, VirtualFrame vFrame) {
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.returnVoid(node, vFrame);
@@ -464,7 +497,7 @@
 
             public String instrumentationInfo() {
                 final String info = getInstrumentInfo();
-                return info != null ? info : toolEvalNodeFactory.getClass().getSimpleName();
+                return info != null ? info : rootFactory.getClass().getSimpleName();
             }
         }
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNode.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.instrument;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Root of a client-provided AST fragment that can be executed efficiently, subject to full Truffle
- * optimization, by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval
- * Instrument}.
- *
- * @see Instrument
- * @see ToolEvalNodeFactory
- * @see ToolEvalResultListener
- */
-public abstract class ToolEvalNode extends Node implements InstrumentationNode {
-
-    /**
-     * Executes this AST fragment on behalf of a client {@link Instrument}, just before the
-     * guest-language AST node to which the {@link Probe} holding the Instrument is executed.
-     *
-     * @param node the guest-language AST node to which the host Instrument's Probe is attached
-     * @param vFrame execution frame at the guest-language AST node
-     * @return the result of this AST fragment's execution
-     */
-    public abstract Object executeToolEvalNode(Node node, VirtualFrame vFrame);
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNodeFactory.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.instrument;
-
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Creator of {@linkplain ToolEvalNode AST fragments} suitable for efficient execution, subject to
- * full Truffle optimization, by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool
- * Eval Instrument}.
- *
- * @see Instrument
- * @see ToolEvalNode
- */
-public interface ToolEvalNodeFactory {
-
-    /**
-     * Provider of {@linkplain ToolEvalNode AST fragment} instances for efficient execution via
-     * instrumentation, subject to full Truffle optimization, at a {@linkplain Probe Probed} site in
-     * a guest-language AST.
-     *
-     * @param probe the Probe to which the Instrument requesting the AST fragment is attached
-     * @param node the guest-language AST location that is the context in which the requesting
-     *            Instrument must execute the AST fragment.
-     * @return a newly created AST fragment suitable for execution, via instrumentation, in the
-     *         execution context of the specified guest-language AST site.
-     */
-    ToolEvalNode createToolEvalNode(Probe probe, Node node);
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalResultListener.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.instrument;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Listener for receiving the result a client-provided {@linkplain ToolEvalNode AST fragment}, when
- * executed by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval Instrument}.
- *
- * @see Instrument
- * @see ToolEvalNode
- * @see ToolEvalNodeFactory
- */
-public interface ToolEvalResultListener {
-
-    /**
-     * Notifies listener that a client-provided {@linkplain ToolEvalNode AST fragment} has been
-     * executed by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval
-     * Instrument} with the specified result, possibly {@code null}.
-     *
-     * @param node the guest-language AST node to which the host Instrument's {@link Probe} is
-     *            attached
-     * @param vFrame execution frame at the guest-language AST node
-     * @param result the result of this AST fragment's execution
-     */
-    void notifyToolEvalResult(Node node, VirtualFrame vFrame, Object result);
-
-    /**
-     * Notifies listener that execution of client-provided {@linkplain ToolEvalNode AST fragment}
-     * filed during execution by a @linkplain Instrument#create(ToolEvalNodeFactory, String) Tool
-     * Eval Instrument}.
-     *
-     * @param node the guest-language AST node to which the host Instrument's {@link Probe} is
-     *            attached
-     * @param vFrame execution frame at the guest-language AST node
-     * @param ex the exception
-     */
-    void notifyToolEvalFailure(Node node, VirtualFrame vFrame, RuntimeException ex);
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 import java.util.*;
 
 import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.nodes.NodeFieldAccessor.NodeFieldKind;
 import com.oracle.truffle.api.source.*;
@@ -56,6 +57,28 @@
         return printTreeToString(node, maxDepth, null);
     }
 
+    public String printNodeWithInstrumentation(Node node) {
+        if (node == null) {
+            return "null";
+        }
+        final StringBuilder sb = new StringBuilder();
+        sb.append(nodeName(node));
+        sb.append("(");
+        if (node instanceof InstrumentationNode) {
+            sb.append(instrumentInfo((InstrumentationNode) node));
+        }
+        sb.append(sourceInfo(node));
+        sb.append(NodeUtil.printSyntaxTags(node));
+        sb.append(")");
+        final Node parent = node.getParent();
+        if (parent instanceof WrapperNode) {
+            final WrapperNode wrapper = (WrapperNode) parent;
+            sb.append(" Probed");
+            sb.append(NodeUtil.printSyntaxTags(wrapper));
+        }
+        return sb.toString();
+    }
+
     protected void printTree(PrintWriter p, Node node, int maxDepth, Node markNode, int level) {
         if (node == null) {
             p.print("null");
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Thu May 28 17:44:05 2015 +0200
@@ -561,6 +561,10 @@
         printSourceAttributionTree(new PrintWriter(out), null, node, 1);
     }
 
+    public static void printSourceAttributionTree(PrintWriter out, Node node) {
+        printSourceAttributionTree(out, null, node, 1);
+    }
+
     private static void printSourceAttributionTree(PrintWriter p, Node parent, Node node, int level) {
         if (node == null) {
             return;
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Thu May 28 17:44:05 2015 +0200
@@ -35,32 +35,46 @@
  * Representation of a guest language source code unit and its contents. Sources originate in
  * several ways:
  * <ul>
- * <li><strong>Literal:</strong> A named text string. These are not indexed and should be considered
- * value objects; equality is defined based on contents. <br>
+ * <li><strong>Literal:</strong> An anonymous text string: not named and not indexed. These should
+ * be considered value objects; equality is defined based on contents.<br>
  * See {@link Source#fromText(CharSequence, String)}</li>
  * <p>
+ * <li><strong>Named Literal:</strong> A text string that can be retrieved by name as if it were a
+ * file, but without any assumption that the name is related to a file path. Creating a new literal
+ * with an already existing name will replace its predecessor in the index.<br>
+ * See {@link Source#fromNamedText(CharSequence, String)}<br>
+ * See {@link Source#find(String)}</li>
+ * <p>
  * <li><strong>File:</strong> Each file is represented as a canonical object, indexed by the
  * absolute, canonical path name of the file. File contents are <em>read lazily</em> and contents
  * optionally <em>cached</em>. <br>
  * See {@link Source#fromFileName(String)}<br>
- * See {@link Source#fromFileName(String, boolean)}</li>
+ * See {@link Source#fromFileName(String, boolean)}<br>
+ * See {@link Source#find(String)}</li>
  * <p>
  * <li><strong>URL:</strong> Each URL source is represented as a canonical object, indexed by the
  * URL. Contents are <em>read eagerly</em> and <em>cached</em>. <br>
- * See {@link Source#fromURL(URL, String)}</li>
+ * See {@link Source#fromURL(URL, String)}<br>
+ * See {@link Source#find(String)}</li>
  * <p>
- * <li><strong>Reader:</strong> Contents are <em>read eagerly</em> and treated as a <em>Literal</em>
- * . <br>
+ * <li><strong>Reader:</strong> Contents are <em>read eagerly</em> and treated as an anonymous
+ * (non-indexed) <em>Literal</em> . <br>
  * See {@link Source#fromReader(Reader, String)}</li>
  * <p>
- * <li><strong>Pseudo File:</strong> A literal text string that can be retrieved by name as if it
- * were a file, unlike literal sources; useful for testing. <br>
- * See {@link Source#asPseudoFile(CharSequence, String)}</li>
+ * <li><strong>Sub-Source:</strong> A representation of the contents of a sub-range of another
+ * {@link Source}.<br>
+ * See @link {@link Source#subSource(Source, int, int)}<br>
+ * See @link {@link Source#subSource(Source, int)}</li>
+ * <p>
+ * <li><strong>AppendableSource:</strong> Literal contents are provided by the client,
+ * incrementally, after the instance is created.<br>
+ * See {@link Source#fromAppendableText(String)}<br>
+ * See {@link Source#fromNamedAppendableText(String)}</li>
  * </ul>
  * <p>
  * <strong>File cache:</strong>
  * <ol>
- * <li>File content caching is optional, <em>off</em> by default.</li>
+ * <li>File content caching is optional, <em>on</em> by default.</li>
  * <li>The first access to source file contents will result in the contents being read, and (if
  * enabled) cached.</li>
  * <li>If file contents have been cached, access to contents via {@link Source#getInputStream()} or
@@ -128,14 +142,24 @@
      */
     private static final List<WeakReference<Source>> allSources = Collections.synchronizedList(new ArrayList<WeakReference<Source>>());
 
-    // Files and pseudo files are indexed.
-    private static final Map<String, WeakReference<Source>> filePathToSource = new HashMap<>();
+    /**
+     * Index of all named sources.
+     */
+    private static final Map<String, WeakReference<Source>> nameToSource = new HashMap<>();
 
     private static boolean fileCacheEnabled = true;
 
     private static final List<SourceListener> sourceListeners = new ArrayList<>();
 
     /**
+     * Locates an existing instance by the name under which it was indexed.
+     */
+    public static Source find(String name) {
+        final WeakReference<Source> nameRef = nameToSource.get(name);
+        return nameRef == null ? null : nameRef.get();
+    }
+
+    /**
      * Gets the canonical representation of a source file, whose contents will be read lazily and
      * then cached.
      *
@@ -146,7 +170,7 @@
      */
     public static Source fromFileName(String fileName, boolean reset) throws IOException {
 
-        final WeakReference<Source> nameRef = filePathToSource.get(fileName);
+        final WeakReference<Source> nameRef = nameToSource.get(fileName);
         Source source = nameRef == null ? null : nameRef.get();
         if (source == null) {
             final File file = new File(fileName);
@@ -154,11 +178,11 @@
                 throw new IOException("Can't read file " + fileName);
             }
             final String path = file.getCanonicalPath();
-            final WeakReference<Source> pathRef = filePathToSource.get(path);
+            final WeakReference<Source> pathRef = nameToSource.get(path);
             source = pathRef == null ? null : pathRef.get();
             if (source == null) {
                 source = new FileSource(file, fileName, path);
-                filePathToSource.put(path, new WeakReference<>(source));
+                nameToSource.put(path, new WeakReference<>(source));
             }
         }
         if (reset) {
@@ -193,17 +217,17 @@
      */
     public static Source fromFileName(CharSequence chars, String fileName) throws IOException {
 
-        final WeakReference<Source> nameRef = filePathToSource.get(fileName);
+        final WeakReference<Source> nameRef = nameToSource.get(fileName);
         Source source = nameRef == null ? null : nameRef.get();
         if (source == null) {
             final File file = new File(fileName);
             // We are going to trust that the fileName is readable.
             final String path = file.getCanonicalPath();
-            final WeakReference<Source> pathRef = filePathToSource.get(path);
+            final WeakReference<Source> pathRef = nameToSource.get(path);
             source = pathRef == null ? null : pathRef.get();
             if (source == null) {
                 source = new FileSource(file, fileName, path, chars);
-                filePathToSource.put(path, new WeakReference<>(source));
+                nameToSource.put(path, new WeakReference<>(source));
             }
         }
         notifyNewSource(source).tagAs(Tags.FROM_FILE);
@@ -211,8 +235,7 @@
     }
 
     /**
-     * Creates a non-canonical source from literal text. If an already created literal source must
-     * be retrievable by name, use {@link #asPseudoFile(CharSequence, String)}.
+     * Creates an anonymous source from literal text: not named and not indexed.
      *
      * @param chars textual source code
      * @param description a note about the origin, for error messages and debugging
@@ -226,6 +249,79 @@
     }
 
     /**
+     * Creates an anonymous source from literal text that is provided incrementally after creation:
+     * not named and not indexed.
+     *
+     * @param description a note about the origin, for error messages and debugging
+     * @return a newly created, non-indexed, initially empty, appendable source representation
+     */
+    public static Source fromAppendableText(String description) {
+        final Source source = new AppendableLiteralSource(description);
+        notifyNewSource(source).tagAs(Tags.FROM_LITERAL);
+        return source;
+    }
+
+    /**
+     * Creates a source from literal text that can be retrieved by name, with no assumptions about
+     * the structure or meaning of the name. If the name is already in the index, the new instance
+     * will replace the previously existing instance in the index.
+     *
+     * @param chars textual source code
+     * @param name string to use for indexing/lookup
+     * @return a newly created, source representation
+     */
+    public static Source fromNamedText(CharSequence chars, String name) {
+        final Source source = new LiteralSource(name, chars.toString());
+        nameToSource.put(name, new WeakReference<>(source));
+        notifyNewSource(source).tagAs(Tags.FROM_LITERAL);
+        return source;
+    }
+
+    /**
+     * Creates a source from literal text that is provided incrementally after creation and which
+     * can be retrieved by name, with no assumptions about the structure or meaning of the name. If
+     * the name is already in the index, the new instance will replace the previously existing
+     * instance in the index.
+     *
+     * @param name string to use for indexing/lookup
+     * @return a newly created, indexed, initially empty, appendable source representation
+     */
+    public static Source fromNamedAppendableText(String name) {
+        final Source source = new AppendableLiteralSource(name);
+        nameToSource.put(name, new WeakReference<>(source));
+        notifyNewSource(source).tagAs(Tags.FROM_LITERAL);
+        return source;
+    }
+
+    /**
+     * Creates a {@linkplain Source Source instance} that represents the contents of a sub-range of
+     * an existing {@link Source}.
+     *
+     * @param base an existing Source instance
+     * @param baseCharIndex 0-based index of the first character of the sub-range
+     * @param length the number of characters in the sub-range
+     * @return a new instance representing a sub-range of another Source
+     * @throws IllegalArgumentException if the specified sub-range is not contained in the base
+     */
+    public static Source subSource(Source base, int baseCharIndex, int length) {
+        final SubSource subSource = SubSource.create(base, baseCharIndex, length);
+        return subSource;
+    }
+
+    /**
+     * Creates a {@linkplain Source Source instance} that represents the contents of a sub-range at
+     * the end of an existing {@link Source}.
+     *
+     * @param base an existing Source instance
+     * @param baseCharIndex 0-based index of the first character of the sub-range
+     * @return a new instance representing a sub-range at the end of another Source
+     * @throws IllegalArgumentException if the index is out of range
+     */
+    public static Source subSource(Source base, int baseCharIndex) {
+        return subSource(base, baseCharIndex, base.getLength() - baseCharIndex);
+    }
+
+    /**
      * Creates a source whose contents will be read immediately from a URL and cached.
      *
      * @param url
@@ -286,21 +382,6 @@
         return source;
     }
 
-    /**
-     * Creates a source from literal text, but which acts as a file and can be retrieved by name
-     * (unlike other literal sources); intended for testing.
-     *
-     * @param chars textual source code
-     * @param pseudoFileName string to use for indexing/lookup
-     * @return a newly created, source representation, canonical with respect to its name
-     */
-    public static Source asPseudoFile(CharSequence chars, String pseudoFileName) {
-        final Source source = new LiteralSource(pseudoFileName, chars.toString());
-        filePathToSource.put(pseudoFileName, new WeakReference<>(source));
-        notifyNewSource(source).tagAs(Tags.FROM_LITERAL);
-        return source;
-    }
-
     // TODO (mlvdv) enable per-file choice whether to cache?
     /**
      * Enables/disables caching of file contents, <em>disabled</em> by default. Caching of sources
@@ -372,7 +453,7 @@
 
     private final ArrayList<SourceTag> tags = new ArrayList<>();
 
-    Source() {
+    private Source() {
     }
 
     private TextMap textMap = null;
@@ -448,7 +529,7 @@
      * Gets the number of characters in the source.
      */
     public final int getLength() {
-        return checkTextMap().length();
+        return getTextMap().length();
     }
 
     /**
@@ -467,9 +548,8 @@
      * Gets the text (not including a possible terminating newline) in a (1-based) numbered line.
      */
     public final String getCode(int lineNumber) {
-        checkTextMap();
-        final int offset = textMap.lineStartOffset(lineNumber);
-        final int length = textMap.lineLength(lineNumber);
+        final int offset = getTextMap().lineStartOffset(lineNumber);
+        final int length = getTextMap().lineLength(lineNumber);
         return getCode().substring(offset, offset + length);
     }
 
@@ -478,7 +558,7 @@
      * source without a terminating newline count as a line.
      */
     public final int getLineCount() {
-        return checkTextMap().lineCount();
+        return getTextMap().lineCount();
     }
 
     /**
@@ -488,7 +568,7 @@
      * @throws IllegalArgumentException if the offset is outside the text contents
      */
     public final int getLineNumber(int offset) throws IllegalArgumentException {
-        return checkTextMap().offsetToLine(offset);
+        return getTextMap().offsetToLine(offset);
     }
 
     /**
@@ -497,7 +577,7 @@
      * @throws IllegalArgumentException if the offset is outside the text contents
      */
     public final int getColumnNumber(int offset) throws IllegalArgumentException {
-        return checkTextMap().offsetToCol(offset);
+        return getTextMap().offsetToCol(offset);
     }
 
     /**
@@ -506,7 +586,7 @@
      * @throws IllegalArgumentException if there is no such line in the text
      */
     public final int getLineStartOffset(int lineNumber) throws IllegalArgumentException {
-        return checkTextMap().lineStartOffset(lineNumber);
+        return getTextMap().lineStartOffset(lineNumber);
     }
 
     /**
@@ -516,7 +596,17 @@
      * @throws IllegalArgumentException if there is no such line in the text
      */
     public final int getLineLength(int lineNumber) throws IllegalArgumentException {
-        return checkTextMap().lineLength(lineNumber);
+        return getTextMap().lineLength(lineNumber);
+    }
+
+    /**
+     * Append text to a Source explicitly created as <em>Appendable</em>.
+     *
+     * @param chars the text to append
+     * @throws UnsupportedOperationException by concrete subclasses that do not support appending
+     */
+    public void appendCode(CharSequence chars) {
+        throw new UnsupportedOperationException();
     }
 
     /**
@@ -556,9 +646,8 @@
      * @throws IllegalStateException if the source is one of the "null" instances
      */
     public final SourceSection createSection(String identifier, int startLine, int startColumn, int length) {
-        checkTextMap();
-        final int lineStartOffset = textMap.lineStartOffset(startLine);
-        if (startColumn > textMap.lineLength(startLine)) {
+        final int lineStartOffset = getTextMap().lineStartOffset(startLine);
+        if (startColumn > getTextMap().lineLength(startLine)) {
             throw new IllegalArgumentException("column out of range");
         }
         final int startOffset = lineStartOffset + startColumn - 1;
@@ -586,10 +675,8 @@
      */
     public final SourceSection createSection(String identifier, int charIndex, int length) throws IllegalArgumentException {
         checkRange(charIndex, length);
-        checkTextMap();
         final int startLine = getLineNumber(charIndex);
         final int startColumn = charIndex - getLineStartOffset(startLine) + 1;
-
         return new DefaultSourceSection(this, identifier, startLine, startColumn, charIndex, length);
     }
 
@@ -610,9 +697,8 @@
      * @throws IllegalStateException if the source is one of the "null" instances
      */
     public final SourceSection createSection(String identifier, int lineNumber) {
-        checkTextMap();
-        final int charIndex = textMap.lineStartOffset(lineNumber);
-        final int length = textMap.lineLength(lineNumber);
+        final int charIndex = getTextMap().lineStartOffset(lineNumber);
+        final int length = getTextMap().lineLength(lineNumber);
         return createSection(identifier, charIndex, length);
     }
 
@@ -627,13 +713,25 @@
         return new LineLocationImpl(this, lineNumber);
     }
 
-    private TextMap checkTextMap() {
+    /**
+     * An object suitable for using as a key into a hashtable that defines equivalence between
+     * different source types.
+     */
+    protected Object getHashKey() {
+        return getName();
+    }
+
+    protected final TextMap getTextMap() {
         if (textMap == null) {
             textMap = createTextMap();
         }
         return textMap;
     }
 
+    protected final void clearTextMap() {
+        textMap = null;
+    }
+
     protected TextMap createTextMap() {
         final String code = getCode();
         if (code == null) {
@@ -644,22 +742,22 @@
 
     private static final class LiteralSource extends Source {
 
-        private final String name; // Name used originally to describe the source
+        private final String description;
         private final String code;
 
-        public LiteralSource(String name, String code) {
-            this.name = name;
+        public LiteralSource(String description, String code) {
+            this.description = description;
             this.code = code;
         }
 
         @Override
         public String getName() {
-            return name;
+            return description;
         }
 
         @Override
         public String getShortName() {
-            return name;
+            return description;
         }
 
         @Override
@@ -669,7 +767,7 @@
 
         @Override
         public String getPath() {
-            return name;
+            return description;
         }
 
         @Override
@@ -688,11 +786,7 @@
 
         @Override
         public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + name.hashCode();
-            result = prime * result + (code == null ? 0 : code.hashCode());
-            return result;
+            return description.hashCode();
         }
 
         @Override
@@ -703,11 +797,69 @@
             if (obj == null) {
                 return false;
             }
-            if (!(obj instanceof LiteralSource)) {
-                return false;
+            if (obj instanceof LiteralSource) {
+                LiteralSource other = (LiteralSource) obj;
+                return description.equals(other.description);
             }
-            LiteralSource other = (LiteralSource) obj;
-            return name.equals(other.name) && code.equals(other.code);
+            return false;
+        }
+    }
+
+    private static final class AppendableLiteralSource extends Source {
+        private String description;
+        final List<CharSequence> codeList = new ArrayList<>();
+
+        public AppendableLiteralSource(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getName() {
+            return description;
+        }
+
+        @Override
+        public String getShortName() {
+            return description;
+        }
+
+        @Override
+        public String getCode() {
+            return getCodeFromIndex(0);
+        }
+
+        @Override
+        public String getPath() {
+            return description;
+        }
+
+        @Override
+        public URL getURL() {
+            return null;
+        }
+
+        @Override
+        public Reader getReader() {
+            return new StringReader(getCode());
+        }
+
+        @Override
+        protected void reset() {
+        }
+
+        private String getCodeFromIndex(int index) {
+            StringBuilder sb = new StringBuilder();
+            for (int i = index; i < codeList.size(); i++) {
+                CharSequence s = codeList.get(i);
+                sb.append(s);
+            }
+            return sb.toString();
+        }
+
+        @Override
+        public void appendCode(CharSequence chars) {
+            codeList.add(chars);
+            clearTextMap();
         }
 
     }
@@ -745,6 +897,11 @@
         }
 
         @Override
+        protected Object getHashKey() {
+            return path;
+        }
+
+        @Override
         public String getCode() {
             if (fileCacheEnabled) {
                 if (code == null || timeStamp != file.lastModified()) {
@@ -807,7 +964,6 @@
         protected void reset() {
             this.code = null;
         }
-
     }
 
     private static final class URLSource extends Source {
@@ -867,7 +1023,61 @@
         @Override
         protected void reset() {
         }
+    }
 
+    private static final class SubSource extends Source {
+        private final Source base;
+        private final int baseIndex;
+        private final int subLength;
+
+        private static SubSource create(Source base, int baseIndex, int length) {
+            if (baseIndex < 0 || length < 0 || baseIndex + length > base.getLength()) {
+                throw new IllegalArgumentException("text positions out of range");
+            }
+            return new SubSource(base, baseIndex, length);
+        }
+
+        private SubSource(Source base, int baseIndex, int length) {
+            this.base = base;
+            this.baseIndex = baseIndex;
+            this.subLength = length;
+        }
+
+        @Override
+        protected void reset() {
+            assert false;
+        }
+
+        @Override
+        public String getName() {
+            return base.getName();
+        }
+
+        @Override
+        public String getShortName() {
+            return base.getShortName();
+        }
+
+        @Override
+        public String getPath() {
+            return base.getPath();
+        }
+
+        @Override
+        public URL getURL() {
+            return null;
+        }
+
+        @Override
+        public Reader getReader() {
+            assert false;
+            return null;
+        }
+
+        @Override
+        public String getCode() {
+            return base.getCode(baseIndex, subLength);
+        }
     }
 
     private static final class BytesSource extends Source {
@@ -1132,7 +1342,7 @@
             final int prime = 31;
             int result = 1;
             result = prime * result + line;
-            result = prime * result + source.hashCode();
+            result = prime * result + source.getHashKey().hashCode();
             return result;
         }
 
@@ -1151,7 +1361,7 @@
             if (line != other.line) {
                 return false;
             }
-            return source.equals(other.source);
+            return source.getHashKey().equals(other.source.getHashKey());
         }
 
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java	Thu May 28 17:44:05 2015 +0200
@@ -52,6 +52,8 @@
  * @see #createBinaryProfile()
  */
 public abstract class ConditionProfile extends NodeCloneable {
+    ConditionProfile() {
+    }
 
     public abstract boolean profile(boolean value);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,513 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.vm;
+
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.TruffleLanguage.Registration;
+import com.oracle.truffle.api.TruffleLanguage.Env;
+import com.oracle.truffle.api.impl.Accessor;
+import com.oracle.truffle.api.source.Source;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.lang.reflect.Constructor;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Virtual machine for Truffle based languages. Use {@link #newVM()} to create new isolated virtual
+ * machine ready for execution of various languages. All the languages in a single virtual machine
+ * see each other exported global symbols and can co-operate. Use {@link #newVM()} multiple times to
+ * create different, isolated virtual machines completely separated from each other.
+ * <p>
+ * Once instantiated use {@link #eval(java.net.URI)} with a reference to a file or URL or directly
+ * pass code snippet into the virtual machine via {@link #eval(java.lang.String, java.lang.String)}.
+ * Support for individual languages is initialized on demand - e.g. once a file of certain mime type
+ * is about to be processed, its appropriate engine (if found), is initialized. Once an engine gets
+ * initialized, it remains so, until the virtual machine isn't garbage collected.
+ * <p>
+ * The <code>TruffleVM</code> is single-threaded and tries to enforce that. It records the thread it
+ * has been {@link Builder#build() created} by and checks that all subsequent calls are coming from
+ * the same thread.
+ */
+public final class TruffleVM {
+    private static final Logger LOG = Logger.getLogger(TruffleVM.class.getName());
+    private static final SPIAccessor SPI = new SPIAccessor();
+    private final Thread initThread;
+    private final Map<String, Language> langs;
+    private final Reader in;
+    private final Writer err;
+    private final Writer out;
+
+    /**
+     * Private & temporary only constructor.
+     */
+    private TruffleVM() {
+        this.initThread = null;
+        this.in = null;
+        this.err = null;
+        this.out = null;
+        this.langs = null;
+    }
+
+    /**
+     * Real constructor used from the builder.
+     *
+     * @param out stdout
+     * @param err stderr
+     * @param in stdin
+     */
+    private TruffleVM(Writer out, Writer err, Reader in) {
+        this.out = out;
+        this.err = err;
+        this.in = in;
+        this.initThread = Thread.currentThread();
+        this.langs = new HashMap<>();
+        Enumeration<URL> en;
+        try {
+            en = loader().getResources("META-INF/truffle/language");
+        } catch (IOException ex) {
+            throw new IllegalStateException("Cannot read list of Truffle languages", ex);
+        }
+        while (en.hasMoreElements()) {
+            URL u = en.nextElement();
+            Properties p;
+            try {
+                p = new Properties();
+                try (InputStream is = u.openStream()) {
+                    p.load(is);
+                }
+            } catch (IOException ex) {
+                LOG.log(Level.CONFIG, "Cannot process " + u + " as language definition", ex);
+                continue;
+            }
+            Language l = new Language(p);
+            for (String mimeType : l.getMimeTypes()) {
+                langs.put(mimeType, l);
+            }
+        }
+    }
+
+    static ClassLoader loader() {
+        ClassLoader l = TruffleVM.class.getClassLoader();
+        if (l == null) {
+            l = ClassLoader.getSystemClassLoader();
+        }
+        return l;
+    }
+
+    /**
+     * Creation of new Truffle virtual machine. Use the {@link Builder} methods to configure your
+     * virtual machine and then create one using {@link Builder#build()}:
+     *
+     * <pre>
+     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
+     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
+     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
+     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
+     *     .{@link Builder#build() build()};
+     * </pre>
+     *
+     * It searches for {@link Registration languages registered} in the system class loader and
+     * makes them available for later evaluation via
+     * {@link #eval(java.lang.String, java.lang.String)} methods.
+     *
+     * @return new, isolated virtual machine with pre-registered languages
+     */
+    public static TruffleVM.Builder newVM() {
+        // making Builder non-static inner class is a
+        // nasty trick to avoid the Builder class to appear
+        // in Javadoc next to TruffleVM class
+        TruffleVM vm = new TruffleVM();
+        return vm.new Builder();
+    }
+
+    /**
+     * Builder for a new {@link TruffleVM}. Call various configuration methods in a chain and at the
+     * end create new {@link TruffleVM virtual machine}:
+     *
+     * <pre>
+     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
+     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
+     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
+     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
+     *     .{@link Builder#build() build()};
+     * </pre>
+     */
+    public final class Builder {
+        private Writer out;
+        private Writer err;
+        private Reader in;
+
+        Builder() {
+        }
+
+        /**
+         * Changes the defaut output for languages running in <em>to be created</em>
+         * {@link TruffleVM virtual machine}. The default is to use {@link System#out}.
+         *
+         * @param w the writer to use as output
+         * @return instance of this builder
+         */
+        public Builder stdOut(Writer w) {
+            out = w;
+            return this;
+        }
+
+        /**
+         * Changes the error output for languages running in <em>to be created</em>
+         * {@link TruffleVM virtual machine}. The default is to use {@link System#err}.
+         *
+         * @param w the writer to use as output
+         * @return instance of this builder
+         */
+        public Builder stdErr(Writer w) {
+            err = w;
+            return this;
+        }
+
+        /**
+         * Changes the defaut input for languages running in <em>to be created</em>
+         * {@link TruffleVM virtual machine}. The default is to use {@link System#out}.
+         *
+         * @param r the reader to use as input
+         * @return instance of this builder
+         */
+        public Builder stdIn(Reader r) {
+            in = r;
+            return this;
+        }
+
+        /**
+         * Creates the {@link TruffleVM Truffle virtual machine}. The configuration is taken from
+         * values passed into configuration methods in this class.
+         *
+         * @return new, isolated virtual machine with pre-registered languages
+         */
+        public TruffleVM build() {
+            if (out == null) {
+                out = new OutputStreamWriter(System.out);
+            }
+            if (err == null) {
+                err = new OutputStreamWriter(System.err);
+            }
+            if (in == null) {
+                in = new InputStreamReader(System.in);
+            }
+            return new TruffleVM(out, err, in);
+        }
+    }
+
+    /**
+     * Descriptions of languages supported in this Truffle virtual machine.
+     *
+     * @return an immutable map with keys being mimetypes and values the {@link Language
+     *         descriptions} of associated languages
+     */
+    public Map<String, Language> getLanguages() {
+        return Collections.unmodifiableMap(langs);
+    }
+
+    /**
+     * Evaluates file located on a given URL. Is equivalent to loading the content of a file and
+     * executing it via {@link #eval(java.lang.String, java.lang.String)} with a mime type guess
+     * based on the file's extension and/or content.
+     *
+     * @param location the location of a file to execute
+     * @return result of a processing the file, possibly <code>null</code>
+     * @throws IOException exception to signal I/O problems or problems with processing the file's
+     *             content
+     */
+    public Object eval(URI location) throws IOException {
+        checkThread();
+        Source s;
+        String mimeType;
+        if (location.getScheme().equals("file")) {
+            File file = new File(location);
+            s = Source.fromFileName(file.getPath(), true);
+            if (file.getName().endsWith(".c")) {
+                mimeType = "text/x-c";
+            } else if (file.getName().endsWith(".sl")) {
+                mimeType = "application/x-sl";
+            } else {
+                mimeType = Files.probeContentType(file.toPath());
+            }
+        } else {
+            URL url = location.toURL();
+            s = Source.fromURL(url, location.toString());
+            URLConnection conn = url.openConnection();
+            mimeType = conn.getContentType();
+        }
+        TruffleLanguage l = getTruffleLang(mimeType);
+        if (l == null) {
+            throw new IOException("No language for " + location + " with mime type " + mimeType + " found. Supported types: " + langs.keySet());
+        }
+        return SPI.eval(l, s);
+    }
+
+    /**
+     * Evaluates code snippet. Chooses a language registered for a given mime type (throws
+     * {@link IOException} if there is none). And passes the specified code to it for execution.
+     *
+     * @param mimeType mime type of the code snippet - chooses the right language
+     * @param reader the source of code snippet to execute
+     * @return result of an exceution, possibly <code>null</code>
+     * @throws IOException thrown to signal errors while processing the code
+     */
+    public Object eval(String mimeType, Reader reader) throws IOException {
+        checkThread();
+        TruffleLanguage l = getTruffleLang(mimeType);
+        if (l == null) {
+            throw new IOException("No language for mime type " + mimeType + " found. Supported types: " + langs.keySet());
+        }
+        return SPI.eval(l, Source.fromReader(reader, mimeType));
+    }
+
+    /**
+     * Evaluates code snippet. Chooses a language registered for a given mime type (throws
+     * {@link IOException} if there is none). And passes the specified code to it for execution.
+     *
+     * @param mimeType mime type of the code snippet - chooses the right language
+     * @param code the code snippet to execute
+     * @return result of an exceution, possibly <code>null</code>
+     * @throws IOException thrown to signal errors while processing the code
+     */
+    public Object eval(String mimeType, String code) throws IOException {
+        checkThread();
+        TruffleLanguage l = getTruffleLang(mimeType);
+        if (l == null) {
+            throw new IOException("No language for mime type " + mimeType + " found. Supported types: " + langs.keySet());
+        }
+        return SPI.eval(l, Source.fromText(code, mimeType));
+    }
+
+    /**
+     * Looks global symbol provided by one of initialized languages up. First of all execute your
+     * program via one of your {@link #eval(java.lang.String, java.lang.String)} and then look
+     * expected symbol up using this method.
+     * <p>
+     * The names of the symbols are language dependant, but for example the Java language bindings
+     * follow the specification for method references:
+     * <ul>
+     * <li>"java.lang.Exception::new" is a reference to constructor of {@link Exception}
+     * <li>"java.lang.Integer::valueOf" is a reference to static method in {@link Integer} class
+     * </ul>
+     * Once an symbol is obtained, it remembers values for fast acces and is ready for being
+     * invoked.
+     *
+     * @param globalName the name of the symbol to find
+     * @return found symbol or <code>null</code> if it has not been found
+     */
+    public Symbol findGlobalSymbol(String globalName) {
+        checkThread();
+        Object obj = null;
+        Object global = null;
+        for (Language dl : langs.values()) {
+            TruffleLanguage l = dl.getImpl();
+            obj = SPI.findExportedSymbol(l, globalName);
+            if (obj != null) {
+                global = SPI.languageGlobal(l);
+                break;
+            }
+        }
+        return obj == null ? null : new Symbol(obj, global);
+    }
+
+    private void checkThread() {
+        if (initThread != Thread.currentThread()) {
+            throw new IllegalStateException("TruffleVM created on " + initThread.getName() + " but used on " + Thread.currentThread().getName());
+        }
+    }
+
+    private TruffleLanguage getTruffleLang(String mimeType) {
+        checkThread();
+        Language l = langs.get(mimeType);
+        return l == null ? null : l.getImpl();
+    }
+
+    /**
+     * Represents {@link TruffleVM#findGlobalSymbol(java.lang.String) global symbol} provided by one
+     * of the initialized languages in {@link TruffleVM Truffle virtual machine}.
+     */
+    public class Symbol {
+        private final Object obj;
+        private final Object global;
+
+        Symbol(Object obj, Object global) {
+            this.obj = obj;
+            this.global = global;
+        }
+
+        /**
+         * Invokes the symbol. If the symbol represents a function, then it should be invoked with
+         * provided arguments. If the symbol represents a field, then first argument (if provided)
+         * should set the value to the field; the return value should be the actual value of the
+         * field when the <code>invoke</code> method returns.
+         *
+         * @param thiz this/self in language that support such concept; use <code>null</code> to let
+         *            the language use default this/self or ignore the value
+         * @param args arguments to pass when invoking the symbol
+         * @return the value returned by invoking the symbol
+         * @throws IOException signals problem during execution
+         */
+        public Object invoke(Object thiz, Object... args) throws IOException {
+            List<Object> arr = new ArrayList<>();
+            if (thiz == null) {
+                if (global != null) {
+                    arr.add(global);
+                }
+            } else {
+                arr.add(thiz);
+            }
+            arr.addAll(Arrays.asList(args));
+            return SPI.invoke(obj, arr.toArray());
+        }
+    }
+
+    /**
+     * Description of a language registered in {@link TruffleVM Truffle virtual machine}. Languages
+     * are registered by {@link Registration} annotation which stores necessary information into a
+     * descriptor inside of the language's JAR file. When a new {@link TruffleVM} is created, it
+     * reads all available descritors and creates {@link Language} objects to represent them. One
+     * can obtain a {@link #getName() name} or list of supported {@link #getMimeTypes() mimetypes}
+     * for each language. The actual language implementation is not initialized until
+     * {@link TruffleVM#eval(java.lang.String, java.lang.String) a code is evaluated} in it.
+     */
+    public final class Language {
+        private final Properties props;
+        private TruffleLanguage impl;
+
+        Language(Properties props) {
+            this.props = props;
+        }
+
+        /**
+         * Mimetypes recognized by the language.
+         *
+         * @return returns immutable set of recognized mimetypes
+         */
+        public Set<String> getMimeTypes() {
+            TreeSet<String> ts = new TreeSet<>();
+            for (int i = 0;; i++) {
+                String mt = props.getProperty("mimeType." + i);
+                if (mt == null) {
+                    break;
+                }
+                ts.add(mt);
+            }
+            return Collections.unmodifiableSet(ts);
+        }
+
+        /**
+         * Human readable name of the language. Think of C, Ruby, JS, etc.
+         *
+         * @return string giving the language a name
+         */
+        public String getName() {
+            return props.getProperty("name");
+        }
+
+        TruffleLanguage getImpl() {
+            if (impl == null) {
+                String n = props.getProperty("className");
+                try {
+                    Class<?> langClazz = Class.forName(n, true, loader());
+                    Constructor<?> constructor = langClazz.getConstructor(Env.class);
+                    impl = SPI.attachEnv(TruffleVM.this, constructor, out, err, in);
+                } catch (Exception ex) {
+                    throw new IllegalStateException("Cannot initialize " + getName() + " language with implementation " + n, ex);
+                }
+            }
+            return impl;
+        }
+
+        @Override
+        public String toString() {
+            return "[" + getName() + " for " + getMimeTypes() + "]";
+        }
+    } // end of Language
+
+    private static class SPIAccessor extends Accessor {
+        @Override
+        public Object importSymbol(TruffleVM vm, TruffleLanguage ownLang, String globalName) {
+            Set<Language> uniqueLang = new LinkedHashSet<>(vm.langs.values());
+            for (Language dl : uniqueLang) {
+                TruffleLanguage l = dl.getImpl();
+                if (l == ownLang) {
+                    continue;
+                }
+                Object obj = SPI.findExportedSymbol(l, globalName);
+                if (obj != null) {
+                    return obj;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public TruffleLanguage attachEnv(TruffleVM vm, Constructor<?> langClazz, Writer stdOut, Writer stdErr, Reader stdIn) {
+            return super.attachEnv(vm, langClazz, stdOut, stdErr, stdIn);
+        }
+
+        @Override
+        public Object eval(TruffleLanguage l, Source s) throws IOException {
+            return super.eval(l, s);
+        }
+
+        @Override
+        public Object findExportedSymbol(TruffleLanguage l, String globalName) {
+            return super.findExportedSymbol(l, globalName);
+        }
+
+        @Override
+        public Object languageGlobal(TruffleLanguage l) {
+            return super.languageGlobal(l);
+        }
+
+        @Override
+        public Object invoke(Object obj, Object[] args) throws IOException {
+            return super.invoke(obj, args);
+        }
+    } // end of SPIAccessor
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package.html	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Truffle Virtual Machine</title>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    </head>
+    <body>
+        <div>Central place to control <a href="TruffleVM.html">Truffle Virtual Machine</a> and
+        all languages hosted in it.</div>
+    </body>
+</html>
--- a/graal/com.oracle.truffle.dsl.processor/src/META-INF/services/javax.annotation.processing.Processor	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/META-INF/services/javax.annotation.processing.Processor	Thu May 28 17:44:05 2015 +0200
@@ -1,2 +1,3 @@
 com.oracle.truffle.dsl.processor.TruffleProcessor
 com.oracle.truffle.dsl.processor.verify.VerifyTruffleProcessor
+com.oracle.truffle.dsl.processor.LanguageRegistrationProcessor
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ExpectError.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.dsl.processor;
+
+import java.util.*;
+
+import javax.annotation.processing.*;
+import javax.lang.model.element.*;
+import javax.tools.Diagnostic.*;
+
+public class ExpectError {
+
+    public static void assertNoErrorExpected(ProcessingEnvironment processingEnv, Element element) {
+        TypeElement eee = processingEnv.getElementUtils().getTypeElement(TruffleTypes.EXPECT_ERROR_CLASS_NAME);
+        if (eee != null) {
+            for (AnnotationMirror am : element.getAnnotationMirrors()) {
+                if (am.getAnnotationType().asElement().equals(eee)) {
+                    processingEnv.getMessager().printMessage(Kind.ERROR, "Expected an error, but none found!", element);
+                }
+            }
+        }
+    }
+
+    public static boolean isExpectedError(ProcessingEnvironment processingEnv, Element element, String message) {
+        TypeElement eee = processingEnv.getElementUtils().getTypeElement(TruffleTypes.EXPECT_ERROR_CLASS_NAME);
+        if (eee != null) {
+            for (AnnotationMirror am : element.getAnnotationMirrors()) {
+                if (am.getAnnotationType().asElement().equals(eee)) {
+                    Map<? extends ExecutableElement, ? extends AnnotationValue> vals = am.getElementValues();
+                    if (vals.size() == 1) {
+                        AnnotationValue av = vals.values().iterator().next();
+                        if (av.getValue() instanceof List) {
+                            List<?> arr = (List<?>) av.getValue();
+                            for (Object o : arr) {
+                                if (o instanceof AnnotationValue) {
+                                    AnnotationValue ov = (AnnotationValue) o;
+                                    if (message.equals(ov.getValue())) {
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.dsl.processor;
+
+import java.io.*;
+import java.util.*;
+
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.TruffleLanguage.Registration;
+
+@SupportedAnnotationTypes("com.oracle.truffle.api.*")
+public final class LanguageRegistrationProcessor extends AbstractProcessor {
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    private void createProviderFile(TypeElement language, Registration annotation) {
+        String filename = "META-INF/truffle/language";
+        try {
+            FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, language);
+            Properties p = new Properties();
+            String className = processingEnv.getElementUtils().getBinaryName(language).toString();
+            p.setProperty("name", annotation.name());
+            p.setProperty("className", className);
+            String[] mimes = annotation.mimeType();
+            for (int i = 0; i < mimes.length; i++) {
+                p.setProperty("mimeType." + i, mimes[i]);
+            }
+            try (OutputStream os = file.openOutputStream()) {
+                p.store(os, "Generated by " + LanguageRegistrationProcessor.class.getName());
+            }
+        } catch (IOException e) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), language);
+        }
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        for (Element e : roundEnv.getElementsAnnotatedWith(Registration.class)) {
+            Registration annotation = e.getAnnotation(Registration.class);
+            if (annotation != null && e.getKind() == ElementKind.CLASS) {
+                if (!e.getModifiers().contains(Modifier.PUBLIC)) {
+                    emitError("Registered language class must be public", e);
+                    continue;
+                }
+                if (e.getEnclosingElement().getKind() != ElementKind.PACKAGE && !e.getModifiers().contains(Modifier.STATIC)) {
+                    emitError("Registered language inner-class must be static", e);
+                    continue;
+                }
+                TypeMirror truffleLang = processingEnv.getElementUtils().getTypeElement(TruffleLanguage.class.getName()).asType();
+                if (!processingEnv.getTypeUtils().isAssignable(e.asType(), truffleLang)) {
+                    emitError("Registered language class must subclass TruffleLanguage", e);
+                    continue;
+                }
+                boolean found = false;
+                for (Element mem : e.getEnclosedElements()) {
+                    if (mem.getKind() != ElementKind.CONSTRUCTOR) {
+                        continue;
+                    }
+                    ExecutableElement ee = (ExecutableElement) mem;
+                    if (ee.getParameters().size() != 1) {
+                        continue;
+                    }
+                    if (!ee.getModifiers().contains(Modifier.PUBLIC)) {
+                        continue;
+                    }
+                    TypeMirror env = processingEnv.getElementUtils().getTypeElement(TruffleLanguage.Env.class.getCanonicalName()).asType();
+                    if (processingEnv.getTypeUtils().isSameType(ee.getParameters().get(0).asType(), env)) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found) {
+                    emitError("Language must have a public constructor accepting TruffleLanguage.Env as parameter", e);
+                    continue;
+                }
+                assertNoErrorExpected(e);
+                createProviderFile((TypeElement) e, annotation);
+            }
+        }
+
+        return true;
+    }
+
+    void assertNoErrorExpected(Element e) {
+        ExpectError.assertNoErrorExpected(processingEnv, e);
+    }
+
+    void emitError(String msg, Element e) {
+        if (ExpectError.isExpectedError(processingEnv, e, msg)) {
+            return;
+        }
+        processingEnv.getMessager().printMessage(Kind.ERROR, msg, e);
+    }
+
+}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Thu May 28 17:44:05 2015 +0200
@@ -44,6 +44,8 @@
  */
 public final class TruffleTypes {
 
+    public static final String EXPECT_ERROR_CLASS_NAME = "com.oracle.truffle.api.dsl.test.ExpectError";
+
     private final DeclaredType node;
     private final ArrayType nodeArray;
     private final TypeMirror unexpectedValueException;
@@ -94,7 +96,7 @@
         nodeFactory = getRequired(context, NodeFactory.class);
         nodeFactoryBase = getRequired(context, NodeFactoryBase.class);
         dslMetadata = getRequired(context, DSLMetadata.class);
-        expectError = (TypeElement) getRequired(context, ExpectError.class).asElement();
+        expectError = getOptional(context, EXPECT_ERROR_CLASS_NAME);
         generateNodeFactory = getRequired(context, GenerateNodeFactory.class);
     }
 
@@ -158,6 +160,10 @@
         return (DeclaredType) type;
     }
 
+    private static TypeElement getOptional(ProcessorContext context, String name) {
+        return context.getEnvironment().getElementUtils().getTypeElement(name);
+    }
+
     public TypeMirror getInvalidAssumption() {
         return invalidAssumption;
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Thu May 28 17:44:05 2015 +0200
@@ -168,7 +168,12 @@
 
         CodeTreeBuilder builder = method.createBuilder();
         builder.startReturn();
-        builder.startStaticCall(context.getType(Arrays.class), "asList");
+
+        if (factoryList.size() > 1) {
+            builder.startStaticCall(context.getType(Arrays.class), "asList");
+        } else {
+            builder.startStaticCall(context.getType(Collections.class), "singletonList");
+        }
 
         for (NodeData child : factoryList) {
             builder.startGroup();
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java	Thu May 28 17:44:05 2015 +0200
@@ -37,7 +37,7 @@
 @DSLOptions
 public class TypeSystemParser extends AbstractParser<TypeSystemData> {
 
-    public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(TypeSystem.class, ExpectError.class);
+    public static final List<Class<TypeSystem>> ANNOTATIONS = Arrays.asList(TypeSystem.class);
 
     @Override
     public Class<? extends Annotation> getAnnotationType() {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java	Thu May 28 17:44:05 2015 +0200
@@ -34,9 +34,10 @@
 import javax.tools.Diagnostic.Kind;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.nodes.Node.Child;
+import com.oracle.truffle.dsl.processor.*;
 
-@SupportedSourceVersion(SourceVersion.RELEASE_7)
-@SupportedAnnotationTypes({"com.oracle.truffle.api.CompilerDirectives.TruffleBoundary"})
+@SupportedAnnotationTypes({"com.oracle.truffle.api.CompilerDirectives.TruffleBoundary", "com.oracle.truffle.api.nodes.Node.Child"})
 public class VerifyTruffleProcessor extends AbstractProcessor {
     @Override
     public SourceVersion getSupportedSourceVersion() {
@@ -113,9 +114,28 @@
                 scope = null;
             }
         }
+
+        for (Element e : roundEnv.getElementsAnnotatedWith(Child.class)) {
+            if (e.getModifiers().contains(Modifier.FINAL)) {
+                emitError("@Child field cannot be final", e);
+                continue;
+            }
+            assertNoErrorExpected(e);
+        }
         return false;
     }
 
+    void assertNoErrorExpected(Element element) {
+        ExpectError.assertNoErrorExpected(processingEnv, element);
+    }
+
+    void emitError(String message, Element element) {
+        if (ExpectError.isExpectedError(processingEnv, element, message)) {
+            return;
+        }
+        processingEnv.getMessager().printMessage(Kind.ERROR, message, element);
+    }
+
     /**
      * Determines if a given exception is (most likely) caused by <a
      * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599">Bug 367599</a>.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.interop/src/META-INF/services/com.oracle.truffle.api.impl.SymbolInvoker	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,1 @@
+com.oracle.truffle.interop.SymbolInvokerImpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/SymbolInvokerImpl.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.interop;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.FrameDescriptor;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.impl.SymbolInvoker;
+import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.interop.messages.Execute;
+import com.oracle.truffle.interop.messages.Receiver;
+import com.oracle.truffle.interop.node.ForeignObjectAccessNode;
+import java.io.IOException;
+
+public final class SymbolInvokerImpl extends SymbolInvoker {
+    static final FrameDescriptor UNUSED_FRAMEDESCRIPTOR = new FrameDescriptor();
+
+    @Override
+    protected Object invoke(Object symbol, Object... arr) throws IOException {
+        ForeignObjectAccessNode executeMain = ForeignObjectAccessNode.getAccess(Execute.create(Receiver.create(), arr.length));
+        CallTarget callTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(executeMain, (TruffleObject) symbol, arr));
+        VirtualFrame frame = Truffle.getRuntime().createVirtualFrame(arr, UNUSED_FRAMEDESCRIPTOR);
+        return callTarget.call(frame);
+    }
+
+    private static class TemporaryRoot extends RootNode {
+        @Child private ForeignObjectAccessNode foreignAccess;
+        private final TruffleObject function;
+        private final Object[] args;
+
+        public TemporaryRoot(ForeignObjectAccessNode foreignAccess, TruffleObject function, Object... args) {
+            this.foreignAccess = foreignAccess;
+            this.function = function;
+            this.args = args;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return foreignAccess.executeForeign(frame, function, args);
+        }
+    }
+
+}
--- a/graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/TruffleGlobalScope.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.interop;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.interop.*;
-
-public interface TruffleGlobalScope {
-    void exportTruffleObject(Object identifier, TruffleObject object);
-
-    FrameSlot getFrameSlot(Object identifier);
-
-    TruffleObject getTruffleObject(FrameSlot slot);
-
-    boolean contains(Object identifier);
-}
--- a/graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/TruffleLanguage.java	Thu May 28 16:54:14 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.interop;
-
-import com.oracle.truffle.api.interop.*;
-
-public interface TruffleLanguage {
-    String getLanguageName();
-
-    Object run(String[] arguments);
-
-    void setTruffleGlobalScope(TruffleGlobalScope globalScope);
-
-    TruffleObject getLanguageGlobal();
-
-    boolean isObjectOfLanguage(TruffleObject object);
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.test;
+
+import com.oracle.truffle.api.test.vm.TruffleTCK;
+import com.oracle.truffle.api.vm.TruffleVM;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+/**
+ * This is the way to verify your language implementation is compatible.
+ *
+ */
+public class SLTckTest extends TruffleTCK {
+    @Test
+    public void testVerifyPresence() {
+        TruffleVM vm = TruffleVM.newVM().build();
+        assertTrue("Our language is present", vm.getLanguages().containsKey("application/x-sl"));
+    }
+
+    @Override
+    protected TruffleVM prepareVM() throws Exception {
+        TruffleVM vm = TruffleVM.newVM().build();
+        vm.eval("application/x-sl", // your langage
+                        "function fourtyTwo() {\n" + // your script
+                                        "  return 42;\n" + //
+                                        "}\n" + //
+                                        "function plus(a, b) {\n" + //
+                                        "  return a + b;\n" + //
+                                        "}\n" //
+        );
+        return vm;
+    }
+
+    @Override
+    protected String fourtyTwo() {
+        return "fourtyTwo";
+    }
+
+    @Override
+    protected String plusInt() {
+        return "plus";
+    }
+}
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java	Thu May 28 17:44:05 2015 +0200
@@ -37,11 +37,9 @@
 import org.junit.runners.model.*;
 
 import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.api.source.*;
-import com.oracle.truffle.sl.*;
+import com.oracle.truffle.api.vm.TruffleVM;
+import com.oracle.truffle.sl.SLMain;
 import com.oracle.truffle.sl.builtins.*;
-import com.oracle.truffle.sl.factory.*;
-import com.oracle.truffle.sl.runtime.*;
 import com.oracle.truffle.sl.test.SLTestRunner.TestCase;
 
 public final class SLTestRunner extends ParentRunner<TestCase> {
@@ -165,19 +163,18 @@
         notifier.fireTestStarted(testCase.name);
 
         ByteArrayOutputStream out = new ByteArrayOutputStream();
-        PrintStream printer = new PrintStream(out);
+        PrintWriter printer = new PrintWriter(out);
         try {
-            SLContext context = SLContextFactory.create(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats))), printer);
-            for (NodeFactory<? extends SLBuiltinNode> builtin : builtins) {
-                context.installBuiltin(builtin);
-            }
-            final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName);
-            SLMain.run(context, source, null, repeats);
+            TruffleVM vm = TruffleVM.newVM().stdIn(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats)))).stdOut(printer).build();
+
+            String script = readAllLines(testCase.path);
+            SLMain.run(vm, testCase.path.toUri(), null, printer, repeats, builtins);
 
+            printer.flush();
             String actualOutput = new String(out.toByteArray());
-            Assert.assertEquals(repeat(testCase.expectedOutput, repeats), actualOutput);
+            Assert.assertEquals(script, repeat(testCase.expectedOutput, repeats), actualOutput);
         } catch (Throwable ex) {
-            notifier.fireTestFailure(new Failure(testCase.name, ex));
+            notifier.fireTestFailure(new Failure(testCase.name, new IllegalStateException("Cannot run " + testCase.sourceName, ex)));
         } finally {
             notifier.fireTestFinished(testCase.name);
         }
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Thu May 28 17:44:05 2015 +0200
@@ -202,7 +202,7 @@
         notifier.fireTestStarted(testCase.name);
 
         ByteArrayOutputStream out = new ByteArrayOutputStream();
-        PrintStream printer = new PrintStream(out);
+        PrintWriter printer = new PrintWriter(out);
         final ASTProber prober = new SLStandardASTProber();
         Probe.registerASTProber(prober);
         try {
@@ -226,6 +226,7 @@
                 notifier.fireTestFailure(new Failure(testCase.name, new UnsupportedOperationException("No instrumentation found.")));
             }
 
+            printer.flush();
             String actualOutput = new String(out.toByteArray());
             Assert.assertEquals(testCase.expectedOutput, actualOutput);
         } catch (Throwable ex) {
@@ -270,15 +271,15 @@
 
     /**
      * This sample listener provides prints the value of an assignment (after the assignment is
-     * complete) to the {@link PrintStream} specified in the constructor. This listener can only be
+     * complete) to the {@link PrintWriter} specified in the constructor. This listener can only be
      * attached at {@link SLWriteLocalVariableNode}, but provides no guards to protect it from being
      * attached elsewhere.
      */
     public final class SLPrintAssigmentValueListener extends DefaultSimpleInstrumentListener {
 
-        private PrintStream output;
+        private PrintWriter output;
 
-        public SLPrintAssigmentValueListener(PrintStream output) {
+        public SLPrintAssigmentValueListener(PrintWriter output) {
             this.output = output;
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.output	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,1 @@
+Undefined function: foo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.sl	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,3 @@
+function main() {  
+  foo();
+}  
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Thu May 28 17:44:05 2015 +0200
@@ -32,8 +32,10 @@
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.api.tools.*;
+import com.oracle.truffle.api.vm.TruffleVM;
+import com.oracle.truffle.api.vm.TruffleVM.Symbol;
 import com.oracle.truffle.sl.builtins.*;
-import com.oracle.truffle.sl.factory.*;
+import com.oracle.truffle.sl.factory.SLContextFactory;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.nodes.call.*;
 import com.oracle.truffle.sl.nodes.controlflow.*;
@@ -42,6 +44,9 @@
 import com.oracle.truffle.sl.nodes.local.*;
 import com.oracle.truffle.sl.parser.*;
 import com.oracle.truffle.sl.runtime.*;
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * SL is a simple language to demonstrate and showcase features of Truffle. The implementation is as
@@ -129,7 +134,20 @@
  * <em>default printer</em>.
  *
  */
-public class SLMain {
+@TruffleLanguage.Registration(name = "sl", mimeType = "application/x-sl")
+public class SLMain extends TruffleLanguage {
+    private static SLMain LAST;
+    private static List<NodeFactory<? extends SLBuiltinNode>> builtins = Collections.emptyList();
+    private final SLContext context;
+
+    public SLMain(Env env) {
+        super(env);
+        context = SLContextFactory.create(new BufferedReader(env().stdIn()), new PrintWriter(env().stdOut(), true));
+        LAST = this;
+        for (NodeFactory<? extends SLBuiltinNode> builtin : builtins) {
+            context.installBuiltin(builtin);
+        }
+    }
 
     /* Demonstrate per-type tabulation of node execution counts */
     private static boolean nodeExecCounts = false;
@@ -142,29 +160,35 @@
      * The main entry point. Use the mx command "mx sl" to run it with the correct class path setup.
      */
     public static void main(String[] args) throws IOException {
-
-        SLContext context = SLContextFactory.create(new BufferedReader(new InputStreamReader(System.in)), System.out);
-
-        Source source;
-        if (args.length == 0) {
-            source = Source.fromReader(new InputStreamReader(System.in), "stdin");
-        } else {
-            source = Source.fromFileName(args[0]);
-        }
+        TruffleVM vm = TruffleVM.newVM().build();
+        assert vm.getLanguages().containsKey("application/x-sl");
 
         int repeats = 1;
         if (args.length >= 2) {
             repeats = Integer.parseInt(args[1]);
         }
 
-        run(context, source, System.out, repeats);
+        if (args.length == 0) {
+            vm.eval("application/x-sl", new InputStreamReader(System.in));
+        } else {
+            vm.eval(new File(args[0]).toURI());
+        }
+        Symbol main = vm.findGlobalSymbol("main");
+        if (main == null) {
+            throw new SLException("No function main() defined in SL source file.");
+        }
+        while (repeats-- > 0) {
+            main.invoke(null);
+        }
     }
 
     /**
      * Parse and run the specified SL source. Factored out in a separate method so that it can also
      * be used by the unit test harness.
      */
-    public static long run(SLContext context, Source source, PrintStream logOutput, int repeats) {
+    public static long run(TruffleVM context, URI source, PrintWriter logOutput, PrintWriter out, int repeats, List<NodeFactory<? extends SLBuiltinNode>> currentBuiltins) throws IOException {
+        builtins = currentBuiltins;
+
         if (logOutput != null) {
             logOutput.println("== running on " + Truffle.getRuntime().getName());
             // logOutput.println("Source = " + source.getCode());
@@ -193,11 +217,14 @@
         }
 
         /* Parse the SL source file. */
-        Parser.parseSL(context, source);
+        Object result = context.eval(source);
+        if (result != null) {
+            out.println(result);
+        }
 
         /* Lookup our main entry point, which is per definition always named "main". */
-        SLFunction main = context.getFunctionRegistry().lookup("main");
-        if (main.getCallTarget() == null) {
+        Symbol main = context.findGlobalSymbol("main");
+        if (main == null) {
             throw new SLException("No function main() defined in SL source file.");
         }
 
@@ -208,19 +235,21 @@
         /* Change to dump the AST to IGV over the network. */
         boolean dumpASTToIGV = false;
 
-        printScript("before execution", context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV);
+        printScript("before execution", LAST.context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV);
         long totalRuntime = 0;
         try {
             for (int i = 0; i < repeats; i++) {
                 long start = System.nanoTime();
                 /* Call the main entry point, without any arguments. */
                 try {
-                    Object result = main.getCallTarget().call();
+                    result = main.invoke(null);
                     if (result != SLNull.SINGLETON) {
-                        context.getOutput().println(result);
+                        out.println(result);
                     }
                 } catch (UnsupportedSpecializationException ex) {
-                    context.getOutput().println(formatTypeError(ex));
+                    out.println(formatTypeError(ex));
+                } catch (SLUndefinedFunctionException ex) {
+                    out.println(String.format("Undefined function: %s", ex.getFunctionName()));
                 }
                 long end = System.nanoTime();
                 totalRuntime += end - start;
@@ -231,7 +260,7 @@
             }
 
         } finally {
-            printScript("after execution", context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV);
+            printScript("after execution", LAST.context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV);
         }
         if (nodeExecCounter != null) {
             nodeExecCounter.print(System.out);
@@ -254,7 +283,7 @@
      * <p>
      * When printASTToLog is true: prints the ASTs to the console.
      */
-    private static void printScript(String groupName, SLContext context, PrintStream logOutput, boolean printASTToLog, boolean printSourceAttributionToLog, boolean dumpASTToIGV) {
+    private static void printScript(String groupName, SLContext context, PrintWriter logOutput, boolean printASTToLog, boolean printSourceAttributionToLog, boolean dumpASTToIGV) {
         if (dumpASTToIGV) {
             GraphPrintVisitor graphPrinter = new GraphPrintVisitor();
             graphPrinter.beginGroup(groupName);
@@ -300,7 +329,7 @@
         if (ex.getNode() != null && ex.getNode().getSourceSection() != null) {
             SourceSection ss = ex.getNode().getSourceSection();
             if (ss != null && !(ss instanceof NullSourceSection)) {
-                result.append(" at ").append(ss.getSource().getName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn());
+                result.append(" at ").append(ss.getSource().getShortName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn());
             }
         }
         result.append(": operation");
@@ -341,4 +370,30 @@
         return result.toString();
     }
 
+    @Override
+    protected Object eval(Source code) throws IOException {
+        context.executeMain(code);
+        return null;
+    }
+
+    @Override
+    protected Object findExportedSymbol(String globalName) {
+        for (SLFunction f : context.getFunctionRegistry().getFunctions()) {
+            if (globalName.equals(f.getName())) {
+                return f;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected Object getLanguageGlobal() {
+        return context;
+    }
+
+    @Override
+    protected boolean isObjectOfLanguage(Object object) {
+        return object instanceof SLFunction;
+    }
+
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintlnBuiltin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintlnBuiltin.java	Thu May 28 17:44:05 2015 +0200
@@ -53,7 +53,7 @@
     }
 
     @TruffleBoundary
-    private static void doPrint(PrintStream out, long value) {
+    private static void doPrint(PrintWriter out, long value) {
         out.println(value);
     }
 
@@ -64,7 +64,7 @@
     }
 
     @TruffleBoundary
-    private static void doPrint(PrintStream out, boolean value) {
+    private static void doPrint(PrintWriter out, boolean value) {
         out.println(value);
     }
 
@@ -75,7 +75,7 @@
     }
 
     @TruffleBoundary
-    private static void doPrint(PrintStream out, String value) {
+    private static void doPrint(PrintWriter out, String value) {
         out.println(value);
     }
 
@@ -86,7 +86,7 @@
     }
 
     @TruffleBoundary
-    private static void doPrint(PrintStream out, Object value) {
+    private static void doPrint(PrintWriter out, Object value) {
         out.println(value);
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java	Thu May 28 17:44:05 2015 +0200
@@ -52,20 +52,22 @@
         StringBuilder str = new StringBuilder();
 
         Truffle.getRuntime().iterateFrames(frameInstance -> {
-            dumpFrame(str, frameInstance.getCallTarget(), frameInstance.getFrame(FrameAccess.READ_ONLY, true));
+            CallTarget callTarget = frameInstance.getCallTarget();
+            Frame frame = frameInstance.getFrame(FrameAccess.READ_ONLY, true);
+            RootNode rn = ((RootCallTarget) callTarget).getRootNode();
+            if (rn.getClass().getName().contains("SLFunctionForeignAccess")) {
+                return 1;
+            }
+            if (str.length() > 0) {
+                str.append(System.getProperty("line.separator"));
+            }
+            str.append("Frame: ").append(rn.toString());
+            FrameDescriptor frameDescriptor = frame.getFrameDescriptor();
+            frameDescriptor.getSlots().stream().forEach((s) -> {
+                str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s));
+            });
             return null;
         });
         return str.toString();
     }
-
-    private static void dumpFrame(StringBuilder str, CallTarget callTarget, Frame frame) {
-        if (str.length() > 0) {
-            str.append(System.getProperty("line.separator"));
-        }
-        str.append("Frame: ").append(((RootCallTarget) callTarget).getRootNode().toString());
-        FrameDescriptor frameDescriptor = frame.getFrameDescriptor();
-        for (FrameSlot s : frameDescriptor.getSlots()) {
-            str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s));
-        }
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java	Thu May 28 17:44:05 2015 +0200
@@ -32,11 +32,7 @@
     private SLContextFactory() {
     }
 
-    public static SLContext create() {
-        return create(new BufferedReader(new InputStreamReader(System.in)), System.out);
-    }
-
-    public static SLContext create(BufferedReader input, PrintStream output) {
+    public static SLContext create(BufferedReader input, PrintWriter output) {
         final SLContext slContext = new SLContext(input, output);
         slContext.setVisualizer(new SLDefaultVisualizer());
         return slContext;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java	Thu May 28 17:44:05 2015 +0200
@@ -34,6 +34,11 @@
 
     public abstract Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments);
 
+    @Specialization(guards = "function.getCallTarget() == null")
+    protected Object doUndefinedFunction(SLFunction function, @SuppressWarnings("unused") Object[] arguments) {
+        throw new SLUndefinedFunctionException(function.getName());
+    }
+
     /**
      * Inline cached specialization of the dispatch.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUndefinedFunctionException.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.nodes.call;
+
+public class SLUndefinedFunctionException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    private final String functionName;
+
+    public SLUndefinedFunctionException(String functionName) {
+        this.functionName = functionName;
+    }
+
+    public String getFunctionName() {
+        return functionName;
+    }
+
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java	Thu May 28 17:44:05 2015 +0200
@@ -52,7 +52,7 @@
         return left instanceof Boolean && needsRightNode(((Boolean) left).booleanValue());
     }
 
-    @Specialization(rewriteOn = RuntimeException.class)
+    @Specialization
     protected boolean doBoolean(boolean left, boolean hasRight, boolean right) {
         return left || right;
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Thu May 28 17:44:05 2015 +0200
@@ -30,7 +30,6 @@
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.object.*;
 import com.oracle.truffle.api.source.*;
-import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.builtins.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.nodes.local.*;
@@ -50,11 +49,11 @@
     private static final Layout LAYOUT = Layout.createLayout();
 
     private final BufferedReader input;
-    private final PrintStream output;
+    private final PrintWriter output;
     private final SLFunctionRegistry functionRegistry;
     private final Shape emptyShape;
 
-    public SLContext(BufferedReader input, PrintStream output) {
+    public SLContext(BufferedReader input, PrintWriter output) {
         this.input = input;
         this.output = output;
         this.functionRegistry = new SLFunctionRegistry();
@@ -80,7 +79,7 @@
      * The default default, i.e., the output for the {@link SLPrintlnBuiltin}. To allow unit
      * testing, we do not use {@link System#out} directly.
      */
-    public PrintStream getOutput() {
+    public PrintWriter getOutput() {
         return output;
     }
 
@@ -158,11 +157,6 @@
      */
     public void executeMain(Source source) {
         Parser.parseSL(this, source);
-        SLFunction main = getFunctionRegistry().lookup("main");
-        if (main.getCallTarget() == null) {
-            throw new SLException("No function main() defined in SL source file.");
-        }
-        main.getCallTarget().call();
     }
 
     public DynamicObject createObject() {
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java	Thu May 28 16:54:14 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java	Thu May 28 17:44:05 2015 +0200
@@ -23,6 +23,7 @@
 package com.oracle.truffle.sl.runtime;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.interop.*;
 import com.oracle.truffle.api.utilities.*;
 
 /**
@@ -41,7 +42,7 @@
  * per name exists, the {@link SLFunctionRegistry} creates an instance also when performing name
  * lookup. A function that has been looked up, i.e., used, but not defined, has no call target.
  */
-public final class SLFunction {
+public final class SLFunction implements TruffleObject {
 
     /** The name of the function. */
     private final String name;
@@ -90,4 +91,14 @@
     public String toString() {
         return name;
     }
+
+    /**
+     * In case you want some of your objects to co-operate with other languages, you need to make
+     * them implement {@link TruffleObject} and provide additional {@link SLFunctionForeignAccess
+     * foreign access implementation}.
+     */
+    @Override
+    public ForeignAccessFactory getForeignAccessFactory() {
+        return SLFunctionForeignAccess.INSTANCE;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,90 @@
+/*
+ * 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.truffle.sl.runtime;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccessFactory;
+import com.oracle.truffle.api.interop.InteropPredicate;
+import com.oracle.truffle.api.interop.exception.UnsupportedMessageException;
+import com.oracle.truffle.api.interop.messages.Message;
+import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.interop.ForeignAccessArguments;
+import com.oracle.truffle.interop.messages.Execute;
+import com.oracle.truffle.interop.messages.Receiver;
+import com.oracle.truffle.sl.nodes.call.SLDispatchNode;
+import com.oracle.truffle.sl.nodes.call.SLDispatchNodeGen;
+import java.math.BigInteger;
+
+/**
+ * Implementation of foreing access for {@link SLFunction}.
+ */
+final class SLFunctionForeignAccess implements ForeignAccessFactory {
+    public static final ForeignAccessFactory INSTANCE = new SLFunctionForeignAccess();
+
+    private SLFunctionForeignAccess() {
+    }
+
+    @Override
+    public InteropPredicate getLanguageCheck() {
+        return (com.oracle.truffle.api.interop.TruffleObject o) -> o instanceof SLFunction;
+    }
+
+    @Override
+    public CallTarget getAccess(Message tree) {
+        if (Execute.create(Receiver.create(), 0).matchStructure(tree)) {
+            return Truffle.getRuntime().createCallTarget(new SLForeignCallerRootNode());
+        } else {
+            throw new UnsupportedMessageException(tree.toString() + " not supported");
+        }
+    }
+
+    private static class SLForeignCallerRootNode extends RootNode {
+        @Child private SLDispatchNode dispatch = SLDispatchNodeGen.create();
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            SLFunction function = (SLFunction) ForeignAccessArguments.getReceiver(frame.getArguments());
+            // the calling convention of interop passes the receiver of a
+            // function call (the this object)
+            // as an implicit 1st argument; we need to ignore this argument for SL
+            Object[] arguments = ForeignAccessArguments.extractUserArguments(1, frame.getArguments());
+            for (int i = 0; i < arguments.length; i++) {
+                if (arguments[i] instanceof Long) {
+                    continue;
+                }
+                if (arguments[i] instanceof BigInteger) {
+                    continue;
+                }
+                if (arguments[i] instanceof Number) {
+                    arguments[i] = ((Number) arguments[i]).longValue();
+                }
+            }
+
+            return dispatch.executeDispatch(frame, function, arguments);
+        }
+
+    }
+
+}
--- a/hotspot/.project	Thu May 28 16:54:14 2015 +0200
+++ b/hotspot/.project	Thu May 28 17:44:05 2015 +0200
@@ -133,7 +133,7 @@
 		<link>
 			<name>make</name>
 			<type>2</type>
-			<locationURI>WORKSPACE_LOC/make</locationURI>
+			<locationURI>PARENT-1-PROJECT_LOC/make</locationURI>
 		</link>
 		<link>
 			<name>solaris</name>
--- a/make/defs.make	Thu May 28 16:54:14 2015 +0200
+++ b/make/defs.make	Thu May 28 17:44:05 2015 +0200
@@ -402,6 +402,8 @@
 EXPORT_LIST += $(EXPORT_JRE_LIB_GRAAL_OPTIONS_DIR)/com.oracle.graal.truffle.PartialEvaluator
 EXPORT_LIST += $(EXPORT_JRE_LIB_GRAAL_OPTIONS_DIR)/com.oracle.graal.truffle.TruffleCompilerOptions
 EXPORT_LIST += $(EXPORT_JRE_LIB_GRAAL_OPTIONS_DIR)/com.oracle.graal.virtual.phases.ea.PartialEscapePhase
+EXPORT_LIST += $(EXPORT_JRE_LIB_GRAAL_OPTIONS_DIR)/com.oracle.graal.lir.asm.CompilationResultBuilder
+EXPORT_LIST += $(EXPORT_JRE_LIB_GRAAL_OPTIONS_DIR)/com.oracle.graal.java.GraphBuilderPhase
 
 
 .PHONY: $(HS_ALT_MAKE)/defs.make
--- a/make/linux/Makefile	Thu May 28 16:54:14 2015 +0200
+++ b/make/linux/Makefile	Thu May 28 17:44:05 2015 +0200
@@ -232,7 +232,7 @@
 # Solaris 2.5.1, 2.6).
 # Disable this check by setting DISABLE_HOTSPOT_OS_VERSION_CHECK=ok.
 
-SUPPORTED_OS_VERSION = 2.4% 2.5% 2.6% 3%
+SUPPORTED_OS_VERSION = 2.4% 2.5% 2.6% 3% 4%
 OS_VERSION := $(shell uname -r)
 EMPTY_IF_NOT_SUPPORTED = $(filter $(SUPPORTED_OS_VERSION),$(OS_VERSION))
 
--- a/mx/mx_graal.py	Thu May 28 16:54:14 2015 +0200
+++ b/mx/mx_graal.py	Thu May 28 17:44:05 2015 +0200
@@ -30,13 +30,13 @@
 from os.path import join, exists, dirname, basename
 from argparse import ArgumentParser, RawDescriptionHelpFormatter, REMAINDER
 from outputparser import OutputParser, ValuesMatcher
-import hashlib
 import mx
 import xml.dom.minidom
 import sanitycheck
 import itertools
 import json, textwrap
 import fnmatch
+import mx_graal_makefile
 
 # This works because when mx loads this file, it makes sure __file__ gets an absolute path
 _graal_home = dirname(dirname(__file__))
@@ -1559,7 +1559,6 @@
     parser = ArgumentParser(prog='mx ctw')
     parser.add_argument('--ctwopts', action='store', help='space separated Graal options used for CTW compilations (default: --ctwopts="' + defaultCtwopts + '")', default=defaultCtwopts, metavar='<options>')
     parser.add_argument('--jar', action='store', help='jar of classes to compiled instead of rt.jar', metavar='<path>')
-    parser.add_argument('vmargs', nargs=REMAINDER, metavar='VM options...')
 
     args, vmargs = parser.parse_known_args(args)
 
@@ -1640,6 +1639,12 @@
                 vm(['-XX:-TieredCompilation', '-G:RegisterPressure=' + registers, '-esa', '-version'])
 
     with VM('graal', 'product'):
+        with Task('BootstrapSSAWithRegisterPressure:product', tasks) as t:
+            if t:
+                registers = 'o0,o1,o2,o3,f8,f9,d32,d34' if platform.processor() == 'sparc' else 'rbx,r11,r10,r14,xmm3,xmm11,xmm14'
+                vm(['-XX:-TieredCompilation', '-G:+SSA_LIR', '-G:RegisterPressure=' + registers, '-esa', '-version'])
+
+    with VM('graal', 'product'):
         with Task('BootstrapWithImmutableCode:product', tasks) as t:
             if t: vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version'])
 
@@ -1700,6 +1705,7 @@
     parser = ArgumentParser(prog='mx gate')
     parser.add_argument('-j', '--omit-java-clean', action='store_false', dest='cleanJava', help='omit cleaning Java native code')
     parser.add_argument('-n', '--omit-native-clean', action='store_false', dest='cleanNative', help='omit cleaning and building native code')
+    parser.add_argument('-i', '--omit-ide-clean', action='store_false', dest='cleanIde', help='omit cleaning the ide project files')
     parser.add_argument('-g', '--only-build-graalvm', action='store_false', dest='buildNonGraal', help='only build the Graal VM')
     parser.add_argument('-t', '--task-filter', help='comma separated list of substrings to select subset of tasks to be run')
     parser.add_argument('--jacocout', help='specify the output directory for jacoco report')
@@ -1732,10 +1738,11 @@
                     clean(cleanArgs)
         _clean()
 
-        with Task('IDEConfigCheck', tasks):
+        with Task('IDEConfigCheck', tasks) as t:
             if t:
-                mx.ideclean([])
-                mx.ideinit([])
+                if args.cleanIde:
+                    mx.ideclean([])
+                    mx.ideinit([])
 
         eclipse_exe = mx.get_env('ECLIPSE_EXE')
         if eclipse_exe is not None:
@@ -2602,6 +2609,7 @@
         'longtests' : [longtests, ''],
         'sl' : [sl, '[SL args|@VM options]'],
         'jol' : [jol, ''],
+        'makefile' : [mx_graal_makefile.build_makefile, 'build makefiles for JDK build'],
     }
 
     mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append'])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mx/mx_graal_makefile.py	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,184 @@
+import mx, os, sys
+#
+# ----------------------------------------------------------------------------------------------------
+#
+# Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+# 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.
+#
+# ----------------------------------------------------------------------------------------------------
+#
+
+
+def build_makefile(args):
+    """Build a Makefile from the suitte.py to build graa.jar without python"""
+    if len(args) == 0 or args[0] == "-":
+        do_build_makefile(lambda l: sys.stdout.write(l + os.linesep))
+    elif args[0] == "-o":
+        with open(args[1], "w") as f:
+            do_build_makefile(lambda l: f.write(l + os.linesep))
+
+def relative_dep_path(d):
+    if isinstance(d, str): d = mx.dependency(d)
+    return os.path.basename(d.get_path(False))
+
+def createMakeRule(p, bootClasspath):
+    def filterDeps(deps, t):
+        def typeFilter(project): # filters
+            if isinstance(project, str):
+                project = mx.dependency(project, True)
+            return isinstance(project, t)
+        return [d for d in deps if typeFilter(d)]
+
+
+    canonicalDeps = p.canonical_deps()
+    canonicalProjectDep = filterDeps(canonicalDeps, mx.Project)
+    canonicalProjectDepDirs = ['$(TARGET)/' +i for i in canonicalProjectDep]
+    canonicalLibDep = filterDeps(canonicalDeps, mx.Library)
+    canonicalLibDepJars = ["$(LIB)/" + relative_dep_path(d) for d in canonicalLibDep]
+
+    allDep = p.all_deps([], True, False, includeAnnotationProcessors=True)
+    allProcessorDistNames = [x.definedAnnotationProcessorsDist.name for x in filterDeps(allDep, mx.Project) if x.definedAnnotationProcessors != None]
+    allProjectDep = filterDeps(allDep, mx.Project)
+    allProjectDepDir = ['$(TARGET)/' +i.name for i in allProjectDep]
+    allLibDep = filterDeps(allDep, mx.Library)
+    allLibDepJar = ["$(LIB)/" + relative_dep_path(d) for d in allLibDep]
+
+    processor = p.annotation_processors_path()
+    if processor != None: processor = processor.replace(p.suite.dir, "$(TARGET)")
+
+    cp = allLibDepJar +allProjectDepDir
+    props = {
+             'name': p.name,
+             'project_deps': ' '.join(canonicalProjectDepDirs + canonicalLibDepJars + allProcessorDistNames),
+             'cp_deps': ('-cp ' + ':'.join(cp)) if len(cp) > 0 else '',
+             'cp_boot': ('-bootclasspath ' + bootClasspath) if len(bootClasspath) > 0 else '',
+             'processor': ('-processorpath ' + processor) if processor != None else ''
+    }
+    return """$(TARGET)/{name}: $(shell find graal/{name}/src/ -type f -name *.java) {project_deps}
+\t$(eval TMP := $(shell mktemp -d))
+\ttest ! -d $(TARGET)/{name} || cp -Rp $(TARGET)/{name} $(TMP)
+\t$(JAVAC) -d $(TMP) {cp_boot} {processor} {cp_deps} $(shell find graal/{name}/src/ -type f -name *.java)
+\ttest ! -d graal/{name}/src/META-INF || (mkdir -p $(TARGET)/{name}/META-INF/ &&  cp -r graal/{name}/src/META-INF/ $(TARGET)/{name}/)
+\tmkdir -p $(TARGET)/{name}
+\tcp -r $(TMP)/* $(TARGET)/{name}
+\ttouch $(TARGET)/{name}
+\trm -r $(TMP)
+""".format(**props)
+
+def createDistributionRule(dist):
+    sorted_deps = set(dist.sorted_deps(False, True))
+    depDirs = ' '.join(['$(TARGET)/' + i.name for i in sorted_deps])
+    depDirsStar = ' '.join(['$(TARGET)/' + i.name + '/*' for i in sorted_deps])
+    jarPath = os.path.relpath(dist.path, dist.suite.dir)
+    jarDir = os.path.dirname(jarPath)
+    props = {
+             'dist_name': dist.name,
+             'depDirs': depDirs,
+             'depDirsStar': depDirsStar,
+             'jar_path': jarPath,
+             'jar_dir': jarDir,
+             'providers_dir': '$(TMP)/META-INF/providers/ ',
+             'services_dir': '$(TMP)/META-INF/services/'
+             }
+    return """{dist_name}: {depDirs}
+\t$(eval TMP := $(shell mktemp -d))
+\tmkdir -p $(TARGET){jar_dir}
+\ttouch $(TARGET)/{jar_path}
+\tcp -r {depDirsStar} $(TMP)
+\ttest -d {services_dir} || mkdir -p {services_dir} 
+\ttest ! -d {providers_dir} || (cd {providers_dir} && for i in $$(ls); do c=$$(cat $$i); echo $$i >> {services_dir}$$c; done)
+\ttest ! -d {providers_dir} || rm -r {providers_dir}
+\t$(JAR) cvf $(TARGET){jar_path} -C $(TMP) .
+\trm -r $(TMP)
+""".format(**props)
+
+def createDownloadRule(lib):
+    http_urls = [u for u in lib.urls if u.startswith("http")]
+    if len(http_urls) == 0: http_urls = [u for u in lib.urls if u.startswith("jar")]
+    if len(http_urls) == 0: raise BaseException("No http url specified for downloading library %s: available urls: %s" % (lib.name, lib.urls))
+    url = http_urls[0]
+    tofile = '$(LIB)/' + relative_dep_path(lib)
+    if url.startswith("jar"):
+        props = {
+            'url': url[url.find(":")+1:url.rfind("!")],
+            'archive_file': url[url.rfind("!")+1:],
+            'dest': tofile
+        }
+        dl = """\t$(eval TMP := $(shell mktemp -d))
+\tcd $(TMP) && $(WGET) -O dl.zip {url} && $(JAR) xf dl.zip
+\tmv $(TMP)/{archive_file} {dest}
+\trm -rf $(TMP)""".format(**props)
+    else:
+        dl = "\t$(WGET) -O {} {}".format(tofile, url)
+    return """{}:\n{}""".format(tofile, dl)
+
+
+def create_suite_build(suite, out):
+    for p in suite.projects:
+        java = mx.java(p.javaCompliance)
+        bootClassPath = java.bootclasspath()
+        bootClassPath = bootClassPath.replace(java.jdk, "$(JDK)")
+        out(createMakeRule(p, bootClassPath))
+    for l in suite.libs:
+        out(createDownloadRule(l))
+
+    distributionNames = []
+    for d in suite.dists:
+        distributionNames.append(d.name)
+        out(createDistributionRule(d))
+    out("{0}: {1}\n.PHONY: {1}".format(suite.name, " ".join(distributionNames)))
+
+
+def do_build_makefile(out):
+    out("""VERBOSE=
+TARGET=build/
+LIB=$(TARGET)/lib
+JDK=
+
+WGET=wget
+JAVAC=$(JDK)/bin/javac
+JAR=$(JDK)/bin/jar
+
+
+ifeq ($(JDK),)
+$(error Variable JDK must be set to a JDK installation.)
+endif
+ifneq ($(VERBOSE),)
+SHELL=sh -x
+endif
+
+all: default
+
+$(TARGET):
+\tmkdir -p $(TARGET)
+
+$(LIB):
+\tmkdir -p $(LIB)
+""")
+    suiteNames = []
+    for s in mx.suites():
+        suiteNames.append(s.name)
+        create_suite_build(s, out)
+
+    out("""default: $(TARGET) $(LIB) {0}
+.PHONY: {0}
+    """.format(" ".join(suiteNames)))
+
--- a/mx/sanitycheck.py	Thu May 28 16:54:14 2015 +0200
+++ b/mx/sanitycheck.py	Thu May 28 17:44:05 2015 +0200
@@ -219,7 +219,8 @@
     dacapoMatcher = ValuesMatcher(dacapoTime, {'group' : 'DaCapo', 'name' : '<benchmark>', 'score' : '<time>'})
     dacapoMatcher1 = ValuesMatcher(dacapoTime1, {'group' : 'DaCapo-1stRun', 'name' : '<benchmark>', 'score' : '<time>'})
 
-    return Test("DaCapo-" + name, ['-jar', mx._cygpathU2W(dacapo), name] + _noneAsEmptyList(dacapoArgs), [dacapoSuccess], [dacapoFail], [dacapoMatcher, dacapoMatcher1], ['-Xms2g', '-XX:+' + gc, '-XX:-UseCompressedOops'])
+    # Use ipv4 stack for dacapos; tomcat+solaris+ipv6_interface fails (see also: JDK-8072384)
+    return Test("DaCapo-" + name, ['-jar', mx._cygpathU2W(dacapo), name] + _noneAsEmptyList(dacapoArgs), [dacapoSuccess], [dacapoFail], [dacapoMatcher, dacapoMatcher1], ['-Xms2g', '-XX:+' + gc, '-XX:-UseCompressedOops', "-Djava.net.preferIPv4Stack=true"])
 
 def getScalaDacapos(level=SanityCheckLevel.Normal, gateBuildLevel=None, dacapoArgs=None):
     checks = []
--- a/mx/suite.py	Thu May 28 16:54:14 2015 +0200
+++ b/mx/suite.py	Thu May 28 17:44:05 2015 +0200
@@ -109,36 +109,6 @@
       "sha1" : "59b64c974662b5cf9dbd3cf9045d293853dd7a51",
     },
 
-    "OKRA" : {
-      "path" : "lib/okra-1.10.jar",
-      "urls" : [
-        "http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10.jar",
-        "http://cr.openjdk.java.net/~tdeneau/okra-1.10.jar",
-      ],
-      "sha1" : "96eb3c0ec808ed944ba88d1eb9311058fe0f3d1e",
-      "sourcePath" : "lib/okra-1.10-src.jar",
-      "sourceUrls" : [
-        "http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10-src.jar",
-        "http://cr.openjdk.java.net/~tdeneau/okra-1.10-src.jar",
-      ],
-      "sourceSha1" : "75751bb148fcebaba78ff590f883a114b2b09176",
-    },
-
-    "OKRA_WITH_SIM" : {
-      "path" : "lib/okra-1.10-with-sim.jar",
-      "urls" : [
-        "http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10-with-sim.jar",
-        "http://cr.openjdk.java.net/~tdeneau/okra-1.10-with-sim.jar",
-      ],
-      "sha1" : "7b8db879f1dbcf571290add78d9af24e15a2a50d",
-      "sourcePath" : "lib/okra-1.10-with-sim-src.jar",
-      "sourceSha1" : "7eefd94f16a3e3fd3b8f470cf91e265c6f5e7767",
-      "sourceUrls" : [
-        "http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10-with-sim-src.jar",
-        "http://cr.openjdk.java.net/~tdeneau/okra-1.10-with-sim-src.jar",
-      ],
-    },
-
     "JAVA_ALLOCATION_INSTRUMENTER" : {
       "path" : "lib/java-allocation-instrumenter.jar",
       "sourcePath" : "lib/java-allocation-instrumenter.jar",
@@ -397,15 +367,6 @@
       "workingSets" : "Graal,HotSpot,SPARC",
     },
 
-    "com.oracle.graal.hotspot.server" : {
-      "subDir" : "graal",
-      "sourceDirs" : ["src"],
-      "dependencies" : ["com.oracle.graal.hotspot"],
-      "checkstyle" : "com.oracle.graal.graph",
-      "javaCompliance" : "1.8",
-      "workingSets" : "Graal,HotSpot",
-    },
-
     "com.oracle.graal.hotspot.test" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
@@ -784,7 +745,7 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.graal.amd64",
-        "com.oracle.graal.compiler.test",
+        "com.oracle.graal.lir.jtt",
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
@@ -1010,7 +971,7 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.truffle.api.dsl",
+        "com.oracle.truffle.dsl.processor",
         "JUNIT",
       ],
       "checkstyle" : "com.oracle.graal.graph",
@@ -1079,6 +1040,7 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.truffle.api.dsl",
+        "com.oracle.truffle.interop",
         "com.oracle.truffle.api.object",
         "FINDBUGS"
       ],
@@ -1092,8 +1054,8 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.truffle.sl",
-        "JUNIT",
+        "com.oracle.truffle.api.test",
+        "com.oracle.truffle.sl"
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mxtool/CheckCopyright.java	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,918 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+import java.io.*;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.*;
+import java.util.regex.*;
+
+
+/**
+ * A program to check the existence and correctness of the copyright notice on a given set of sources.
+ * Sources are defined to be those under management by Mercurial and various options are available
+ * to limit the set of sources scanned.
+ */
+public class CheckCopyright {
+
+    static class YearInfo {
+
+        final int firstYear;
+        final int lastYear;
+
+        YearInfo(int firstYear, int lastYear) {
+            this.firstYear = firstYear;
+            this.lastYear = lastYear;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            final YearInfo yearInfo = (YearInfo) other;
+            return yearInfo.firstYear == firstYear && yearInfo.lastYear == lastYear;
+        }
+
+        @Override
+        public int hashCode() {
+            return firstYear ^ lastYear;
+        }
+    }
+
+    static class Info extends YearInfo {
+
+        final String fileName;
+
+        Info(String fileName, int firstYear, int lastYear) {
+            super(firstYear, lastYear);
+            this.fileName = fileName;
+        }
+
+        @Override
+        public String toString() {
+            return fileName + " " + firstYear + ", " + lastYear;
+        }
+    }
+
+    private static abstract class CopyrightHandler {
+    	enum CommentType{
+    		STAR, HASH
+    	}
+
+        private static Map<String, CopyrightHandler> copyrightMap;
+        private static String copyrightFiles = ".*/makefile|.*/Makefile|.*\\.sh|.*\\.bash|.*\\.mk|.*\\.java|.*\\.c|.*\\.h|.*\\.py|.*\\.g|.*\\.r";
+        private static Pattern copyrightFilePattern;
+
+        protected final String suffix;
+        private CopyrightHandler customHandler;
+
+        CopyrightHandler(CommentType commentType) {
+            this.suffix = commentType.name().toLowerCase();
+            initCopyrightMap();
+        }
+
+        void addCustomhandler(CopyrightHandler copyrightHandler) {
+        	this.customHandler = copyrightHandler;
+        }
+
+        /**
+         * Add @code extension to files handled by this {@code CopyrightKind}
+         */
+        protected void updateMap(String extension) {
+        	copyrightMap.put(extension, this);
+        }
+
+        static void addCopyrightFilesPattern(String pattern) {
+            copyrightFiles += "|" + pattern;
+        }
+
+        protected abstract void readCopyrights()  throws IOException;
+
+        protected abstract Matcher getMatcher(String fileName, String fileContent) throws IOException;
+
+        protected abstract String getText(String fileName) throws IOException ;
+
+        protected abstract boolean handlesFile(String fileName);
+
+        /**
+         * Checks that the Oracle copyright year info was correct.
+         * @return {@code false} if the year info was incorrect and was not fixed otherwise return {@code true}
+         * @throws IOException
+         */
+        protected abstract boolean checkYearInfo(String fileName, String fileContent, Matcher matcher, Info info) throws IOException;
+
+        static String getCopyrightText(String fileName) throws IOException {
+        	return getCopyrightHandler(fileName).getText(fileName);
+        }
+
+        private static CopyrightHandler getCopyrightHandler(String fileName) {
+        	initCopyrightMap();
+            if (!copyrightFilePattern.matcher(fileName).matches()) {
+                return null;
+            }
+            CopyrightHandler ck = getDefaultHandler(fileName);
+            if (ck.customHandler != null && ck.customHandler.handlesFile(fileName)) {
+            	return ck.customHandler;
+            } else {
+            	return ck;
+            }
+        }
+
+        private static void initCopyrightMap() {
+            if (copyrightMap == null) {
+                copyrightMap = new HashMap<String, CopyrightHandler>();
+                copyrightFilePattern = Pattern.compile(copyrightFiles);
+            }
+        }
+
+        static CopyrightHandler getDefaultHandler(String fileName) {
+            int index = fileName.lastIndexOf(File.separatorChar);
+            if (index > 0) {
+                fileName = fileName.substring(index + 1);
+            }
+            String ext = "";
+            index = fileName.lastIndexOf('.');
+            if (index > 0) {
+                ext = fileName.substring(index + 1);
+            }
+            if (fileName.equals("makefile")) {
+                ext = "mk";
+            }
+            CopyrightHandler ck = copyrightMap.get(ext);
+            assert ck != null : fileName;
+        	return ck;
+        }
+
+        protected String readCopyright(InputStream is) throws IOException {
+            byte[] b = new byte[16384];
+            int n = is.read(b);
+            is.close();
+            return new String(b, 0, n);
+    	}
+
+    }
+
+    private static class DefaultCopyrightHandler extends CopyrightHandler {
+        private static String ORACLE_COPYRIGHT = "oracle.copyright";
+        private static String ORACLE_COPYRIGHT_REGEX = "oracle.copyright.regex";
+
+        private String copyrightRegex;
+        private String copyright;
+        Pattern copyrightPattern;
+
+        DefaultCopyrightHandler(CopyrightHandler.CommentType commentType) throws IOException {
+    		super(commentType);
+    		if (commentType == CopyrightHandler.CommentType.STAR) {
+    			updateMap("java");
+    			updateMap("c");
+    			updateMap("h");
+    			updateMap("g");
+    		} else {
+    			updateMap("r");
+    			updateMap("R");
+    			updateMap("py");
+    			updateMap("sh");
+    			updateMap("mk");
+    			updateMap("bash");
+    			updateMap("");
+    		}
+    		readCopyrights();
+    	}
+
+    	private String readCopyright(String name) throws IOException {
+    		String copyRightDir = COPYRIGHT_DIR.getValue();
+    		String fileName = "copyrights/" + name + "." + suffix;
+    		String copyrightPath;
+    		if (copyRightDir != null) {
+    			copyrightPath = new File(new File(copyRightDir), fileName).getAbsolutePath();
+    		} else {
+    			URL url = CheckCopyright.class.getResource(fileName);
+    			try {
+    			copyrightPath = url.toURI().getPath();
+    			} catch (URISyntaxException ex) {
+    				throw new IOException(ex);
+    			}
+    		}
+            InputStream is = new FileInputStream(copyrightPath);
+            return readCopyright(is);
+        }
+
+    	@Override
+        protected void readCopyrights()  throws IOException {
+         	copyright = readCopyright(ORACLE_COPYRIGHT);
+         	copyrightRegex =  readCopyright(ORACLE_COPYRIGHT_REGEX);
+         	copyrightPattern = Pattern.compile(copyrightRegex, Pattern.DOTALL);
+        }
+
+    	@Override
+    	protected Matcher getMatcher(String fileName, String fileContent) {
+            return copyrightPattern.matcher(fileContent);
+    	}
+
+    	@Override
+        protected String getText(String fileName) {
+    		return copyright;
+    	}
+
+    	@Override
+    	protected boolean handlesFile(String fileName) {
+    		return true;
+    	}
+
+    	/**
+    	 * Check the year info against the copyright header.
+    	 * N.B. In the case of multiple matching groups, only the last group is checked.
+    	 * I.e., only the last lines containing year info is checked/updated.
+    	 */
+    	@Override
+        protected boolean checkYearInfo(String fileName, String fileContent, Matcher matcher, Info info) throws IOException {
+            int yearInCopyright;
+            int yearInCopyrightIndex;
+            int groupCount = matcher.groupCount();
+            String yearInCopyrightString = matcher.group(groupCount);
+            yearInCopyright = Integer.parseInt(yearInCopyrightString);
+            yearInCopyrightIndex = matcher.start(groupCount);
+            if (yearInCopyright != info.lastYear) {
+                System.out.println(fileName + " copyright last modified year " + yearInCopyright + ", hg last modified year " + info.lastYear);
+                if (FIX.getValue()) {
+                    // Use currentYear as that is what it will be when it's checked in!
+                    System.out.println("updating last modified year of " + fileName + " to " + info.lastYear);
+                    // If the previous copyright only specified a single (initial) year, we convert it to the pair form
+                    String newContent = fileContent.substring(0, yearInCopyrightIndex);
+                    if (matcher.group(groupCount - 1) == null) {
+                    	// single year form
+                    	newContent += yearInCopyrightString + ", ";
+                    }
+                    newContent += info.lastYear + fileContent.substring(yearInCopyrightIndex + 4);
+                    final FileOutputStream os = new FileOutputStream(fileName);
+                    os.write(newContent.getBytes());
+                    os.close();
+                    return true;
+                } else {
+                	return false;
+                }
+            }
+            return true;
+    	}
+
+    }
+
+    private static class CustomCopyrightHandler extends CopyrightHandler {
+    	private Map<String, String> overrides = new HashMap<String, String>();
+    	private CopyrightHandler defaultHandler;
+
+    	CustomCopyrightHandler(CopyrightHandler.CommentType commentType, CopyrightHandler defaultHandler) {
+    		super(commentType);
+    		this.defaultHandler = defaultHandler;
+    	}
+
+    	void addFile(String fileName, String copyright) {
+    		overrides.put(fileName, copyright);
+    	}
+
+		@Override
+		protected void readCopyrights() throws IOException {
+		}
+
+		@Override
+		protected Matcher getMatcher(String fileName, String fileContent) throws IOException {
+			String copyright = overrides.get(fileName);
+			assert copyright != null : fileName;
+			try (InputStream fs = new FileInputStream(copyright + "." + suffix + ".regex")) {
+				return Pattern.compile(readCopyright(fs), Pattern.DOTALL).matcher(fileContent);
+			}
+		}
+
+		@Override
+		protected String getText(String fileName) throws IOException {
+			String copyright = overrides.get(fileName);
+			assert copyright != null : fileName;
+			try (InputStream fs = new FileInputStream(copyright + "." + suffix)) {
+				return readCopyright(fs);
+			}
+		}
+
+		@Override
+		protected boolean handlesFile(String fileName) {
+			return overrides.get(fileName) != null;
+		}
+
+		@Override
+        protected boolean checkYearInfo(String fileName, String fileContent, Matcher matcher, Info info) throws IOException {
+			// This is a bit tacky
+			String copyright = overrides.get(fileName);
+			if (copyright.endsWith("no.copyright")) {
+				return true;
+			}
+			return defaultHandler.checkYearInfo(fileName, fileContent, matcher, info);
+		}
+    }
+
+	private static void initCopyrightKinds() throws IOException {
+		CopyrightHandler starHandler = new DefaultCopyrightHandler(CopyrightHandler.CommentType.STAR);
+		CopyrightHandler hashHandler = new DefaultCopyrightHandler(CopyrightHandler.CommentType.HASH);
+
+		String customCopyrightDir = CUSTOM_COPYRIGHT_DIR.getValue();
+		if (customCopyrightDir != null) {
+			CustomCopyrightHandler customStarHandler = new CustomCopyrightHandler(CopyrightHandler.CommentType.STAR, starHandler);
+			CustomCopyrightHandler customHashHandler = new CustomCopyrightHandler(CopyrightHandler.CommentType.HASH, hashHandler);
+			starHandler.addCustomhandler(customStarHandler);
+			hashHandler.addCustomhandler(customHashHandler);
+
+			File overrides = new File(new File(customCopyrightDir), "overrides");
+			if (overrides.exists()) {
+				ArrayList<String> lines = new ArrayList<>();
+				boolean changed = false;
+				try (BufferedReader br = new BufferedReader(new FileReader(
+						overrides))) {
+					while (true) {
+						String line = br.readLine();
+						if (line == null) {
+							break;
+						}
+						if (line.length() == 0 || line.startsWith("#")) {
+							lines.add(line);
+							continue;
+						}
+						String[] parts = line.split(",");
+						// filename,copyright-file
+						CopyrightHandler defaultHandler = CopyrightHandler.getDefaultHandler(parts[0]);
+						if (defaultHandler == null) {
+							System.err.println("no default copyright handler for: " + parts[0]);
+							System.exit(1);
+						}
+						if (!new File(parts[0]).exists()) {
+							System.err.printf("file %s in overrides file does not exist", parts[0]);
+							if (FIX.getValue()) {
+								System.err.print(" - removing");
+								line = null;
+								changed = true;
+							}
+							System.err.println();
+						}
+						if (line != null) {
+							lines.add(line);
+						}
+						CustomCopyrightHandler customhandler = (CustomCopyrightHandler) defaultHandler.customHandler;
+						customhandler.addFile(parts[0], new File(new File(customCopyrightDir), parts[1]).getAbsolutePath());
+					}
+				}
+				if (changed) {
+					try (BufferedWriter bw = new BufferedWriter(new FileWriter(
+							overrides))) {
+						for (String line : lines) {
+							bw.write(line);
+							bw.write('\n');
+						}
+					}
+				}
+			}
+		}
+	}
+
+    private static int currentYear = Calendar.getInstance().get(Calendar.YEAR);
+    private static Options options = new Options();
+    private static Option<Boolean> help = options.newBooleanOption("help", false, "Show help message and exit.");
+    private static Option<String> COPYRIGHT_DIR = options.newStringOption("copyright-dir", null, "override default location of copyright files");
+    private static Option<List<String>> FILES_TO_CHECK = options.newStringListOption("files", null, "list of files to check");
+    private static Option<String> FILE_LIST = options.newStringOption("file-list", null, "file containing list of files to check");
+    private static Option<Boolean> DIR_WALK = options.newBooleanOption("list-dir", false, "check all files in directory tree requiring a copyright (ls -R)");
+    private static Option<Boolean> HG_ALL = options.newBooleanOption("hg-all", false, "check all hg managed files requiring a copyright (hg status --all)");
+    private static Option<Boolean> HG_MODIFIED = options.newBooleanOption("hg-modified", false, "check all modified hg managed files requiring a copyright (hg status)");
+    private static Option<Boolean> HG_OUTGOING = options.newBooleanOption("hg-outgoing", false, "check outgoing hg managed files requiring a copyright (hg outgoing)");
+    private static Option<String> HG_LOG = options.newStringOption("hg-last", "0", "check hg managed files requiring a copyright in last N changesets (hg log -l N)");
+    private static Option<List<String>> PROJECT = options.newStringListOption("projects", null, "filter files to specific projects");
+    private static Option<String> OUTGOING_REPO = options.newStringOption("hg-repo", null, "override outgoing repository");
+    private static Option<Boolean> EXHAUSTIVE = options.newBooleanOption("hg-exhaustive", false, "check all hg managed files");
+    private static Option<Boolean> FIX = options.newBooleanOption("fix", false, "fix all copyright errors");
+    private static Option<String> FILE_PATTERN = options.newStringOption("file-pattern", null, "append additional file patterns for copyright checks");
+    private static Option<Boolean> REPORT_ERRORS = options.newBooleanOption("report-errors", false, "report non-fatal errors");
+    private static Option<Boolean> HALT_ON_ERROR = options.newBooleanOption("halt-on-error", false, "continue after normally fatal error");
+    private static Option<String> HG_PATH = options.newStringOption("hg-path", "hg", "path to hg executable");
+    private static Option<Boolean> VERBOSE = options.newBooleanOption("verbose", false, "verbose output");
+    private static Option<Boolean> VERY_VERBOSE = options.newBooleanOption("very-verbose", false, "very verbose output");
+    private static Option<String> CUSTOM_COPYRIGHT_DIR = options.newStringOption("custom-copyright-dir", null, "file containing filenames with custom copyrights");
+
+    private static String CANNOT_FOLLOW_FILE = "abort: cannot follow";
+    private static String hgPath;
+    private static boolean error;
+//    private static File workSpaceDirectory;
+    private static boolean verbose;
+    private static boolean veryVerbose;
+
+    public static void main(String[] args) {
+        // parse the arguments
+        options.parseArguments(args);
+        if (help.getValue()) {
+            options.printHelp();
+            return;
+        }
+
+        verbose = VERBOSE.getValue();
+        veryVerbose = VERY_VERBOSE.getValue();
+
+        hgPath = HG_PATH.getValue();
+
+        if (FILE_PATTERN.getValue() != null) {
+            CopyrightHandler.addCopyrightFilesPattern(FILE_PATTERN.getValue());
+        }
+
+        try {
+           initCopyrightKinds();
+            List<String> filesToCheck = null;
+            if (HG_ALL.getValue()) {
+                filesToCheck = getAllFiles(true);
+            } else if (HG_OUTGOING.getValue()) {
+                filesToCheck = getOutgoingFiles();
+            } else if (HG_MODIFIED.getValue()) {
+                filesToCheck = getAllFiles(false);
+            } else if (Integer.parseInt(HG_LOG.getValue()) > 0) {
+                filesToCheck = getLastNFiles(Integer.parseInt(HG_LOG.getValue()));
+            } else if (FILE_LIST.getValue() != null) {
+                filesToCheck = readFileList(FILE_LIST.getValue());
+            } else if (DIR_WALK.getValue()) {
+            	filesToCheck = getDirWalkFiles();
+            } else if (FILES_TO_CHECK.getValue() != null) {
+                filesToCheck = FILES_TO_CHECK.getValue();
+            } else {
+            	// no option set, default to HG_ALL
+            	filesToCheck = getAllFiles(true);
+            }
+            if (filesToCheck != null && filesToCheck.size() > 0) {
+                processFiles(filesToCheck);
+            } else {
+                System.out.println("nothing to check");
+            }
+            System.exit(error ? 1 : 0);
+        } catch (Exception ex) {
+            System.err.println("processing failed: " + ex);
+            ex.printStackTrace();
+        }
+    }
+
+    private static void processFiles(List<String> fileNames) throws Exception {
+        final List<String> projects = PROJECT.getValue();
+        Calendar cal = Calendar.getInstance();
+        for (String fileName : fileNames) {
+            if (projects == null || isInProjects(fileName, projects)) {
+            	File file = new File(fileName);
+            	if (file.isDirectory()) {
+            		continue;
+            	}
+            	if (verbose) {
+            		System.out.println("checking " + fileName);
+            	}
+                try {
+                	Info info = null;
+                	if (DIR_WALK.getValue()) {
+                		info = getFromLastModified(cal, fileName);
+                	} else {
+                		final List<String> logInfo = hglog(fileName);
+                		if (logInfo.size() == 0) {
+                			// an added file, so go with last modified
+                			info = getFromLastModified(cal, fileName);
+                		} else {
+                			info = getInfo(fileName, true, logInfo);
+                		}
+                	}
+                    checkFile(fileName, info);
+                } catch (Exception e) {
+                    System.err.format("COPYRIGHT CHECK WARNING: error while processing %s: %s%n", fileName, e.getMessage());
+                }
+            }
+        }
+    }
+
+    private static Info getFromLastModified(Calendar cal, String fileName) {
+		File file = new File(fileName);
+		cal.setTimeInMillis(file.lastModified());
+		int year = cal.get(Calendar.YEAR);
+		return new Info(fileName, year, year);
+    }
+
+    private static boolean isInProjects(String fileName, List<String> projects) {
+        final int ix = fileName.indexOf(File.separatorChar);
+        if (ix < 0) {
+            return false;
+        }
+        final String fileProject = fileName.substring(0, ix);
+        for (String project : projects) {
+            if (fileProject.equals(project)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static List<String> readFileList(String fileListName) throws IOException {
+        final List<String> result = new ArrayList<String>();
+        BufferedReader b = null;
+        try {
+            b = new BufferedReader(new FileReader(fileListName));
+            while (true) {
+                final String fileName = b.readLine();
+                if (fileName == null) {
+                    break;
+                }
+                if (fileName.length() == 0) {
+                    continue;
+                }
+                result.add(fileName);
+            }
+        } finally {
+            if (b != null) {
+                b.close();
+            }
+        }
+        return result;
+    }
+
+    private static Info getInfo(String fileName, boolean lastOnly, List<String> logInfo) {
+        // process sequence of changesets
+        int lastYear = 0;
+        int firstYear = 0;
+        int ix = 0;
+
+        while (ix < logInfo.size()) {
+        	Map<String, String> tagMap = new HashMap<>();
+        	ix = getChangeset(logInfo, ix, tagMap);
+        	String date = tagMap.get("date");
+            assert date != null;
+            final int csYear = getYear(date);
+            if (lastYear == 0) {
+                lastYear = csYear;
+                firstYear = lastYear;
+            } else {
+                firstYear = csYear;
+            }
+            // if we only want the last modified year, quit now
+            if (lastOnly) {
+                break;
+            }
+
+        }
+
+        if (HG_MODIFIED.getValue()) {
+            // We are only looking at modified and, therefore, uncommitted files.
+            // This means that the lastYear value will be the current year once the
+            // file is committed, so that is what we want to check against.
+            lastYear = currentYear;
+        }
+        return new Info(fileName, firstYear, lastYear);
+    }
+
+    /**
+     * Process all the changeset data, storing in {@outMap}.
+     * Return updated value of {@code ix}.
+     */
+    private static int getChangeset(List<String> logInfo, int ixx, Map<String, String> outMap) {
+    	int ix = ixx;
+    	String s = logInfo.get(ix++);
+    	while (s.length() > 0) {
+    		int cx = s.indexOf(':');
+    		String tag = s.substring(0, cx);
+    		String value = s.substring(cx + 1);
+    		outMap.put(tag, value);
+    		s = logInfo.get(ix++);
+    	}
+    	return ix;
+    }
+
+    private static int getYear(String dateLine) {
+        final String[] parts = dateLine.split(" ");
+        assert parts[parts.length - 2].startsWith("20");
+        return Integer.parseInt(parts[parts.length - 2]);
+    }
+
+    private static void checkFile(String c, Info info) throws IOException {
+        String fileName = info.fileName;
+        File file = new File(fileName);
+        if (!file.exists()) {
+            System.err.println("COPYRIGHT CHECK WARNING: file " + file + " doesn't exist");
+            return;
+        }
+        int fileLength = (int) file.length();
+        byte[] fileContentBytes = new byte[fileLength];
+        FileInputStream is = new FileInputStream(file);
+        is.read(fileContentBytes);
+        is.close();
+        final String fileContent = new String(fileContentBytes);
+        CopyrightHandler copyrightHandler = CopyrightHandler.getCopyrightHandler(fileName);
+        if (file.getName().equals("Makefile")) {
+        	System.console();
+        }
+        if (copyrightHandler != null) {
+            Matcher copyrightMatcher = copyrightHandler.getMatcher(fileName, fileContent);
+            if (copyrightMatcher.matches()) {
+            	error = error | !copyrightHandler.checkYearInfo(fileName, fileContent, copyrightMatcher, info);
+            } else {
+            	// If copyright is missing, insert it, otherwise user has to manually fix existing copyright.
+				if (!fileContent.contains("Copyright")) {
+					System.out.print("file " + fileName + " has missing copyright");
+					if (FIX.getValue()) {
+						final FileOutputStream os = new FileOutputStream(file);
+						os.write(CopyrightHandler.getCopyrightText(fileName)
+								.getBytes());
+						os.write(fileContentBytes);
+						os.close();
+						System.out.println("...fixed");
+					} else {
+						System.out.println();
+						error = true;
+					}
+				} else {
+					System.out.println("file " + fileName + " has malformed copyright" + (FIX.getValue() ? " not fixing" : ""));
+					error = true;
+				}
+            }
+        } else if (EXHAUSTIVE.getValue()) {
+            System.out.println("ERROR: file " + fileName + " has no copyright");
+            error = true;
+        }
+    }
+
+
+    private static List<String> hglog(String fileName) throws Exception {
+        final String[] cmd = new String[] {hgPath, "log", "-f", fileName};
+        return exec(null, cmd, true);
+    }
+
+    private static List<String> getLastNFiles(int n) throws Exception {
+        final String[] cmd = new String[] {hgPath, "log", "-v", "-l", Integer.toString(n)};
+        return getFilesFiles(exec(null, cmd, false));
+    }
+
+    private static List<String> getAllFiles(boolean all) throws Exception {
+        final String[] cmd;
+        if (HG_MODIFIED.getValue()) {
+            cmd = new String[] {hgPath,  "status"};
+        } else {
+            cmd = new String[] {hgPath,  "status",  "--all"};
+        }
+        List<String> output = exec(null, cmd, true);
+        final List<String> result = new ArrayList<String>(output.size());
+        for (String s : output) {
+            final char ch = s.charAt(0);
+            if (!(ch == 'R' || ch == 'I' || ch == '?' ||  ch == '!')) {
+                result.add(s.substring(2));
+            }
+        }
+        return result;
+    }
+
+    private static List<String> getOutgoingFiles() throws Exception {
+        final String[] cmd;
+        if (OUTGOING_REPO.getValue() == null) {
+            cmd = new String[] {hgPath,  "-v", "outgoing"};
+        } else {
+            cmd = new String[] {hgPath,  "-v", "outgoing", OUTGOING_REPO.getValue()};
+        }
+
+        final List<String> output = exec(null, cmd, false); // no outgoing exits with result 1
+        return getFilesFiles(output);
+    }
+
+    private static List<String> getFilesFiles(List<String> output) {
+        // there may be multiple changesets so merge the "files:"
+        final Map<String, String> outSet = new TreeMap<String, String>();
+        for (String s : output) {
+            if (s.startsWith("files:")) {
+                int ix = s.indexOf(' ');
+                while (ix < s.length() && s.charAt(ix) == ' ') {
+                    ix++;
+                }
+                final String[] files = s.substring(ix).split(" ");
+                for (String file : files) {
+                    outSet.put(file, file);
+                }
+            }
+        }
+        return new ArrayList<String>(outSet.values());
+    }
+
+    private static List<String> getDirWalkFiles() {
+    	File cwd = new File(System.getProperty("user.dir"));
+    	ArrayList<String> result = new ArrayList<String>();
+    	getDirWalkFiles(cwd, result);
+    	// remove "user.dir" prefix to make files relative as per hg
+    	String cwdPath = cwd.getAbsolutePath() + '/';
+    	for (int i = 0; i < result.size(); i++) {
+    		String path = result.get(i);
+    		result.set(i, path.replace(cwdPath, ""));
+    	}
+    	return result;
+    }
+
+    private static void getDirWalkFiles(File dir, ArrayList<String> list) {
+    	File[] files = dir.listFiles();
+    	for (File file : files) {
+    		if (ignoreFile(file.getName())) {
+    			continue;
+    		}
+    		if (file.isDirectory()) {
+    				getDirWalkFiles(file, list);
+    		} else {
+    			list.add(file.getAbsolutePath());
+    		}
+    	}
+    }
+
+    private static final String IGNORE_LIST = "\\.hg|.*\\.class|bin|src_gen";
+    private static final Pattern ignorePattern = Pattern.compile(IGNORE_LIST);
+
+    private static boolean ignoreFile(String name) {
+    	return ignorePattern.matcher(name).matches();
+    }
+
+    private static List<String> exec(File workingDir, String[] command, boolean failOnError) throws IOException, InterruptedException {
+        List<String> result = new ArrayList<String>();
+        if (veryVerbose) {
+            System.out.println("Executing process in directory: " + workingDir);
+            for (String c : command) {
+                System.out.println("  " + c);
+            }
+        }
+        final Process process = Runtime.getRuntime().exec(command, null, workingDir);
+        try {
+            result = readOutput(process.getInputStream());
+            final int exitValue = process.waitFor();
+            if (exitValue != 0) {
+                final List<String> errorResult = readOutput(process.getErrorStream());
+                if (REPORT_ERRORS.getValue()) {
+                    System.err.print("execution of command: ");
+                    for (String c : command) {
+                        System.err.print(c);
+                        System.err.print(' ');
+                    }
+                    System.err.println("failed with result " + exitValue);
+                    for (String e : errorResult) {
+                        System.err.println(e);
+                    }
+                }
+                if (failOnError && HALT_ON_ERROR.getValue()) {
+                	if (!cannotFollowNonExistentFile(errorResult)) {
+                		throw new Error("terminating");
+                	}
+                }
+            }
+        } finally {
+            process.destroy();
+        }
+        return result;
+    }
+
+    private static boolean cannotFollowNonExistentFile(List<String> errorResult) {
+        return errorResult.size() == 1 && errorResult.get(0).startsWith(CANNOT_FOLLOW_FILE);
+    }
+
+    private static List<String> readOutput(InputStream is) throws IOException {
+        final List<String> result = new ArrayList<String>();
+        BufferedReader bs = null;
+        try {
+            bs = new BufferedReader(new InputStreamReader(is));
+            while (true) {
+                final String line = bs.readLine();
+                if (line == null) {
+                    break;
+                }
+                result.add(line);
+            }
+        } finally {
+            if (bs != null) {
+                bs.close();
+            }
+        }
+        return result;
+    }
+
+    private static class Options {
+    	private static Map<String, Option<?>> optionMap  = new TreeMap<>();
+
+    	private Option<Boolean> newBooleanOption(String name, boolean defaultValue, String help) {
+    		Option<Boolean> option = new Option<Boolean>(name, help, defaultValue, false, false);
+    		optionMap.put(key(name), option);
+    		return option;
+    	}
+
+    	private Option<String> newStringOption(String name, String defaultValue, String help) {
+    		Option<String> option = new Option<String>(name, help, defaultValue);
+    		optionMap.put(key(name), option);
+    		return option;
+    	}
+
+    	private Option<List<String>> newStringListOption(String name, List<String> defaultValue, String help) {
+    		Option<List<String>> option = new Option<List<String>>(name, help, defaultValue, true, true);
+    		optionMap.put(key(name), option);
+    		return option;
+    	}
+
+    	private static String key(String name) {
+    		return "--" + name;
+    	}
+
+    	void parseArguments(String[] args) {
+            for (int i = 0; i < args.length; i++) {
+            	final String arg = args[i];
+            	if (arg.startsWith("--")) {
+            		Option<?> option = optionMap.get(arg);
+            		if (option == null || (option.consumesNext() && i == args.length - 1)) {
+            			System.out.println("usage:");
+            			printHelp();
+            			System.exit(1);
+            		}
+            		if (option.consumesNext()) {
+            			i++;
+            			option.setValue(args[i]);
+            		} else {
+            			option.setValue(true);
+            		}
+            	}
+            }
+    	}
+
+        void printHelp() {
+        	int maxKeyLen = 0;
+        	for (Map.Entry<String, Option<?>> entrySet : optionMap.entrySet()) {
+        		int l = entrySet.getKey().length();
+        		if (l > maxKeyLen) {
+        			maxKeyLen = l;
+        		}
+        	}
+        	for (Map.Entry<String, Option<?>> entrySet : optionMap.entrySet()) {
+        		String key = entrySet.getKey();
+        		System.out.printf("  %s", key);
+        		for (int i = 0; i < maxKeyLen - key.length(); i++) {
+        			System.out.print(' ');
+        		}
+        		System.out.printf("   %s%n", entrySet.getValue().help);
+        	}
+        }
+}
+
+    private static class Option<T> {
+    	private final String name;
+    	private final String help;
+    	private final boolean consumesNext;
+    	private final boolean isList;
+    	private T value;
+
+    	Option(String name, String help, T defaultValue, boolean consumesNext, boolean isList) {
+    		this.name = name;
+    		this.help = help;
+    		this.value = defaultValue;
+    		this.consumesNext = consumesNext;
+    		this.isList = isList;
+
+    	}
+
+    	Option(String name, String help, T defaultValue) {
+    		this(name, help, defaultValue, true, false);
+    	}
+
+        T getValue() {
+    		return value;
+    	}
+
+        boolean consumesNext() {
+        	return consumesNext;
+        }
+
+ 	   @SuppressWarnings("unchecked")
+       void setValue(boolean value) {
+        	this.value = (T) new Boolean(value);
+        }
+
+ 	   @SuppressWarnings("unchecked")
+        void setValue(String value) {
+ 		   if (isList) {
+ 			   String[] parts = value.split(",");
+ 			   this.value = (T) Arrays.asList(parts);
+ 		   } else {
+ 			   this.value = (T) value;
+ 		   }
+        }
+
+ 	   @SuppressWarnings("unused")
+ 	   String getName() {
+ 		   return name;
+ 	   }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mxtool/copyrights/oracle.copyright.hash	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,22 @@
+#
+# 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.
+#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mxtool/copyrights/oracle.copyright.regex.hash	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,1 @@
+(?:#!.*\n#\n#\ -*\n)?#\n# Copyright \(c\) (?:(20[0-9][0-9]), )?(20[0-9][0-9]), Oracle and/or its affiliates. All rights reserved.\n# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n#\n# This code is free software; you can redistribute it and/or modify it\n# under the terms of the GNU General Public License version 2 only, as\n# published by the Free Software Foundation.\n#\n# This code is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n# version 2 for more details \(a copy is included in the LICENSE file that\n# accompanied this code\).\n#\n# You should have received a copy of the GNU General Public License version\n# 2 along with this work; if not, write to the Free Software Foundation,\n# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n# or visit www.oracle.com if you need additional information or have any\n# questions.\n#\n.*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mxtool/copyrights/oracle.copyright.regex.star	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,1 @@
+/\*\n \* Copyright \(c\) (?:(20[0-9][0-9]), )?(20[0-9][0-9]), Oracle and/or its affiliates. All rights reserved.\n \* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n \*\n \* This code is free software; you can redistribute it and/or modify it\n \* under the terms of the GNU General Public License version 2 only, as\n \* published by the Free Software Foundation.\n \*\n \* This code is distributed in the hope that it will be useful, but WITHOUT\n \* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n \* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n \* version 2 for more details \(a copy is included in the LICENSE file that\n \* accompanied this code\).\n \*\n \* You should have received a copy of the GNU General Public License version\n \* 2 along with this work; if not, write to the Free Software Foundation,\n \* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n \*\n \* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n \* or visit www.oracle.com if you need additional information or have any\n \* questions.\n \*/\n.*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mxtool/copyrights/oracle.copyright.star	Thu May 28 17:44:05 2015 +0200
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
--- a/mxtool/mx.py	Thu May 28 16:54:14 2015 +0200
+++ b/mxtool/mx.py	Thu May 28 17:44:05 2015 +0200
@@ -622,7 +622,7 @@
 
         if not exists(cachePath) or sha1OfFile(cachePath) != sha1:
             if exists(cachePath):
-                log('SHA1 of ' + cachePath + ' does not match expected value (' + sha1 + ') - re-downloading')
+                log('SHA1 of ' + cachePath + ' does not match expected value (' + sha1 + ') - found ' + sha1OfFile(cachePath) + ' - re-downloading')
             print 'Downloading ' + ("sources " if sources else "") + name + ' from ' + str(urls)
             download(cachePath, urls)
 
@@ -1019,6 +1019,7 @@
             p = Project(self, name, srcDirs, deps, javaCompliance, workingSets, d)
             p.checkstyleProj = attrs.pop('checkstyle', name)
             p.native = attrs.pop('native', '') == 'true'
+            p.checkPackagePrefix = attrs.pop('checkPackagePrefix', 'true') == 'true'
             if not p.native and p.javaCompliance is None:
                 abort('javaCompliance property required for non-native project ' + name)
             if len(ap) > 0:
@@ -2317,15 +2318,8 @@
 
     def _init_classpaths(self):
         if not self._classpaths_initialized:
-            myDir = dirname(__file__)
-            outDir = join(dirname(__file__), '.jdk' + str(self.version))
-            if not exists(outDir):
-                os.makedirs(outDir)
-            javaSource = join(myDir, 'ClasspathDump.java')
-            javaClass = join(outDir, 'ClasspathDump.class')
-            if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
-                subprocess.check_call([self.javac, '-d', _cygpathU2W(outDir), _cygpathU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
-            self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', _cygpathU2W(outDir), 'ClasspathDump'], stderr=subprocess.PIPE).split('|')]
+            _, binDir = _compile_mx_class('ClasspathDump', jdk=self)
+            self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', _cygpathU2W(binDir), 'ClasspathDump'], stderr=subprocess.PIPE).split('|')]
             if self.javaCompliance <= JavaCompliance('1.8'):
                 # All 3 system properties accessed by ClasspathDump are expected to exist
                 if not self._bootclasspath or not self._extdirs or not self._endorseddirs:
@@ -2536,15 +2530,12 @@
 
     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', _cygpathU2W(myDir), _cygpathU2W(javaSource)])
+    _, binDir = _compile_mx_class('URLConnectionDownload')
+
     verbose = []
     if sys.stderr.isatty():
         verbose.append("-v")
-    if run([java().java, '-cp', _cygpathU2W(myDir), 'URLConnectionDownload', _cygpathU2W(path)] + verbose + urls, nonZeroIsFatal=False) == 0:
+    if run([java().java, '-cp', _cygpathU2W(binDir), 'URLConnectionDownload', _cygpathU2W(path)] + verbose + urls, nonZeroIsFatal=False) == 0:
         return
 
     abort('Could not download to ' + path + ' from any of the following URLs:\n\n    ' +
@@ -2768,7 +2759,7 @@
         # N.B. Limiting to a suite only affects the starting set of projects. Dependencies in other suites will still be compiled
         sortedProjects = sorted_project_deps(projects, includeAnnotationProcessors=True)
 
-    if args.java:
+    if args.java and jdtJar:
         ideinit([], refreshOnly=True, buildProcessorJars=False)
 
     tasks = {}
@@ -2946,7 +2937,7 @@
                 log('Compiling {0} failed'.format(t.proj.name))
             abort('{0} Java compilation tasks failed'.format(len(failed)))
 
-    if args.java:
+    if args.java and not args.only:
         files = []
         for dist in sorted_dists():
             if dist not in updatedAnnotationProcessorDists:
@@ -3355,9 +3346,10 @@
     nonCanonical = []
     for s in suites(True):
         for p in s.projects:
-            for pkg in p.defined_java_packages():
-                if not pkg.startswith(p.name):
-                    abort('package in {0} does not have prefix matching project name: {1}'.format(p, pkg))
+            if p.checkPackagePrefix:
+                for pkg in p.defined_java_packages():
+                    if not pkg.startswith(p.name):
+                        abort('package in {0} does not have prefix matching project name: {1}'.format(p, pkg))
 
             ignoredDeps = set([name for name in p.deps if project(name, False) is not None])
             for pkg in p.imported_java_packages():
@@ -3451,7 +3443,7 @@
 
         config = join(project(p.checkstyleProj).dir, '.checkstyle_checks.xml')
         if not exists(config):
-            logv('[No Checkstyle configuration foudn for {0} - skipping]'.format(p))
+            logv('[No Checkstyle configuration found for {0} - skipping]'.format(p))
             continue
 
         # skip checking this Java project if its Java compliance level is "higher" than the configured JDK
@@ -4157,8 +4149,8 @@
     launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'})
     launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': consoleOn})
     launchOut.open('mapAttribute', {'key' : 'org.eclipse.debug.core.environmentVariables'})
-    launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : _opts.java_home})
-    launchOut.element('mapEntry', {'key' : 'EXTRA_JAVA_HOMES', 'value' : _opts.extra_java_homes})
+    launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : _default_java_home.jdk})
+    launchOut.element('mapEntry', {'key' : 'EXTRA_JAVA_HOMES', 'value' :  os.pathsep.join([extraJavaHome.jdk for extraJavaHome in _extra_java_homes])})
     launchOut.close('mapAttribute')
 
     if refresh:
@@ -4431,14 +4423,19 @@
     out.close('condition')
 
     out.close('target')
-    out.open('target', {'name' : '-post-compile'})
+    out.open('target', {'name' : 'compile'})
     out.open('exec', {'executable' : sys.executable})
     out.element('env', {'key' : 'JAVA_HOME', 'value' : jdk.jdk})
     out.element('arg', {'value' : os.path.abspath(__file__)})
-    out.element('arg', {'value' : 'archive'})
-    out.element('arg', {'value' : '@GRAAL'})
+    out.element('arg', {'value' : 'build'})
+    out.element('arg', {'value' : '--only'})
+    out.element('arg', {'value' : p.name})
+    out.element('arg', {'value' : '--force-javac'})
+    out.element('arg', {'value' : '--no-native'})
     out.close('exec')
     out.close('target')
+    out.open('target', {'name' : 'jar', 'depends' : 'compile'})
+    out.close('target')
     out.close('project')
     update_file(join(p.dir, 'build.xml'), out.xml(indent='\t', newl='\n'))
     if files:
@@ -5437,6 +5434,65 @@
         _show_section('projects', s.projects)
         _show_section('distributions', s.dists)
 
+def _compile_mx_class(javaClassName, classpath=None, jdk=None):
+    myDir = dirname(__file__)
+    binDir = join(myDir, 'bin' if not jdk else '.jdk' + str(jdk.version))
+    javaSource = join(myDir, javaClassName + '.java')
+    javaClass = join(binDir, javaClassName + '.class')
+    if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
+        if not exists(binDir):
+            os.mkdir(binDir)
+        javac = jdk.javac if jdk else java().javac
+        cmd = [javac, '-d', _cygpathU2W(binDir)]
+        if classpath:
+            cmd += ['-cp', _separatedCygpathU2W(binDir + os.pathsep + classpath)]
+        cmd += [_cygpathU2W(javaSource)]
+        try:
+            subprocess.check_call(cmd)
+        except subprocess.CalledProcessError:
+            abort('failed to compile:' + javaSource)
+
+    return (myDir, binDir)
+
+def checkcopyrights(args):
+    '''run copyright check on the sources'''
+    class CP(ArgumentParser):
+        def format_help(self):
+            return ArgumentParser.format_help(self) + self._get_program_help()
+
+        def _get_program_help(self):
+            help_output = subprocess.check_output([java().java, '-cp', _cygpathU2W(binDir), 'CheckCopyright', '--help'])
+            return '\nother argumemnts preceded with --\n' +  help_output
+
+    myDir, binDir = _compile_mx_class('CheckCopyright')
+
+    parser = CP(prog='mx checkcopyrights')
+
+    parser.add_argument('--primary', action='store_true', help='limit checks to primary suite')
+    parser.add_argument('remainder', nargs=REMAINDER, metavar='...')
+    args = parser.parse_args(args)
+    remove_doubledash(args.remainder)
+
+
+    # ensure compiled form of code is up to date
+
+    result = 0
+    # copyright checking is suite specific as each suite may have different overrides
+    for s in suites(True):
+        if args.primary and not s.primary:
+            continue
+        custom_copyrights = _cygpathU2W(join(s.mxDir, 'copyrights'))
+        custom_args = []
+        if exists(custom_copyrights):
+            custom_args = ['--custom-copyright-dir', custom_copyrights]
+        rc = run([java().java, '-cp', _cygpathU2W(binDir), 'CheckCopyright', '--copyright-dir', _cygpathU2W(myDir)] + custom_args + args.remainder, cwd=s.dir, nonZeroIsFatal=False)
+        result = result if rc == 0 else rc
+    return result
+
+def remove_doubledash(args):
+    if '--' in args:
+        args.remove('--')
+
 def ask_yes_no(question, default=None):
     """"""
     assert not default or default == 'y' or default == 'n'
@@ -5480,6 +5536,7 @@
     'build': [build, '[options]'],
     'checkstyle': [checkstyle, ''],
     'canonicalizeprojects': [canonicalizeprojects, ''],
+    'checkcopyrights': [checkcopyrights, '[options]'],
     'clean': [clean, ''],
     'eclipseinit': [eclipseinit, ''],
     'eclipseformat': [eclipseformat, ''],
--- a/src/cpu/sparc/vm/graalCodeInstaller_sparc.cpp	Thu May 28 16:54:14 2015 +0200
+++ b/src/cpu/sparc/vm/graalCodeInstaller_sparc.cpp	Thu May 28 17:44:05 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,7 +45,13 @@
   Handle obj = HotSpotObjectConstantImpl::object(constant);
   jobject value = JNIHandles::make_local(obj());
   if (HotSpotObjectConstantImpl::compressed(constant)) {
-    fatal("unimplemented: narrow oop relocation");
+#ifdef _LP64
+    int oop_index = _oop_recorder->find_index(value);
+    RelocationHolder rspec = oop_Relocation::spec(oop_index);
+    _instructions->relocate(pc, rspec, 1);
+#else
+    fatal("compressed oop on 32bit");
+#endif
   } else {
     NativeMovConstReg* move = nativeMovConstReg_at(pc);
     move->set_data((intptr_t) value);
--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Thu May 28 16:54:14 2015 +0200
+++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Thu May 28 17:44:05 2015 +0200
@@ -3546,11 +3546,8 @@
 #ifdef GRAAL
   masm->block_comment("BEGIN GRAAL");
   int implicit_exception_uncommon_trap_offset = __ offset() - start;
-  //__ pushptr(Address(G2_thread, in_bytes(JavaThread::graal_implicit_exception_pc_offset())));
   __ ld_ptr(G2_thread, in_bytes(JavaThread::graal_implicit_exception_pc_offset()), O7);
-  //__ add(G0, 0x321, O7);
   __ add(O7, -8, O7);
-  //__ st_ptr(I7, SP, I7->sp_offset_in_saved_window()*wordSize + STACK_BIAS);
 
   int uncommon_trap_offset = __ offset() - start;
 
@@ -3558,15 +3555,11 @@
   masm->block_comment("save_live_regs");
   (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
   masm->block_comment("/save_live_regs");
-  //__ ld_ptr(G2_thread, in_bytes(JavaThread::graal_implicit_exception_pc_offset()), O7);
-  // fetch_unroll_info needs to call last_java_frame()
   masm->block_comment("set_last_java_frame");
   __ set_last_Java_frame(SP, NULL);
   masm->block_comment("/set_last_java_frame");
 
-  //__ movl(c_rarg1, Address(r15_thread, in_bytes(ThreadShadow::pending_deoptimization_offset())));
   __ ld(G2_thread, in_bytes(ThreadShadow::pending_deoptimization_offset()), O1);
-  //__ movl(Address(r15_thread, in_bytes(ThreadShadow::pending_deoptimization_offset())), -1);
   __ sub(G0, 1, L1);
   __ st_ptr(L1, G2_thread, in_bytes(ThreadShadow::pending_deoptimization_offset()));
 
@@ -3613,33 +3606,6 @@
   // Restore G2_thread
   __ get_thread();
 
-#ifdef GRAAL
-  // load throwing pc from JavaThread and patch it as the return address
-  // of the current frame. Then clear the field in JavaThread
-  __ block_comment("load throwing pc and patch return");
-  Address exception_pc(G2_thread, JavaThread::exception_pc_offset());
-  Label has_no_pc;
-  // TODO: Remove this weird check if we should patch the return pc
-  // This is because when graal decides to deoptimize and the ExceptionHandlerStub.java
-  // jumps back to this code and the I7 register contains the pc pointing to the begin
-  // of this code. If this is the case (PC within a certain range) then we need to patch
-  // the return pc.
-  // THIS NEEDS REWORK! (sa)
-  __ rdpc(L0);
-  __ sub(L0, I7, L0);
-  __ cmp(L0, 0xFFF);
-  __ br(Assembler::greater, false, Assembler::pt, has_no_pc);
-  __ delayed() -> nop();
-  __ cmp(L0, -0xFFF);
-  __ br(Assembler::less, false, Assembler::pt, has_no_pc);
-  __ delayed() -> nop();
-  __ ld_ptr(exception_pc, I7);
-  __ sub(I7, 8, I7);
-  __ st_ptr(G0, exception_pc);
-  __ bind(has_no_pc);
-  __ block_comment("/load throwing pc and patch return");
-#endif // GAAL
-
 #ifdef ASSERT
   {
     // verify that there is really an exception oop in exception_oop
--- a/src/share/vm/classfile/systemDictionary.hpp	Thu May 28 16:54:14 2015 +0200
+++ b/src/share/vm/classfile/systemDictionary.hpp	Thu May 28 17:44:05 2015 +0200
@@ -200,8 +200,6 @@
   do_klass(BitSet_klass,                                java_util_BitSet,                          Opt                 ) \
   /* Graal classes. These are loaded on-demand. */                                                                                 \
   GRAAL_ONLY(do_klass(Debug_klass,                           com_oracle_graal_debug_Debug,                                 Graal)) \
-  GRAAL_ONLY(do_klass(Node_klass,                            com_oracle_graal_graph_Node,                                  Graal)) \
-  GRAAL_ONLY(do_klass(NodeClass_klass,                       com_oracle_graal_graph_NodeClass,                             Graal)) \
   GRAAL_ONLY(do_klass(HotSpotCompiledCode_klass,             com_oracle_graal_hotspot_HotSpotCompiledCode,                 Graal)) \
   GRAAL_ONLY(do_klass(HotSpotCompiledCode_Comment_klass,     com_oracle_graal_hotspot_HotSpotCompiledCode_Comment,         Graal)) \
   GRAAL_ONLY(do_klass(HotSpotCompiledNmethod_klass,          com_oracle_graal_hotspot_HotSpotCompiledNmethod,              Graal)) \
@@ -227,7 +225,6 @@
   GRAAL_ONLY(do_klass(DebugInfo_klass,                       com_oracle_graal_api_code_DebugInfo,                          Graal)) \
   GRAAL_ONLY(do_klass(RegisterSaveLayout_klass,              com_oracle_graal_api_code_RegisterSaveLayout,                 Graal)) \
   GRAAL_ONLY(do_klass(BytecodeFrame_klass,                   com_oracle_graal_api_code_BytecodeFrame,                      Graal)) \
-  GRAAL_ONLY(do_klass(CompilationResult_klass,               com_oracle_graal_api_code_CompilationResult,                  Graal)) \
   GRAAL_ONLY(do_klass(CompilationResult_Call_klass,          com_oracle_graal_api_code_CompilationResult_Call,             Graal)) \
   GRAAL_ONLY(do_klass(CompilationResult_ConstantReference_klass, com_oracle_graal_api_code_CompilationResult_ConstantReference, Graal)) \
   GRAAL_ONLY(do_klass(CompilationResult_DataPatch_klass,     com_oracle_graal_api_code_CompilationResult_DataPatch,        Graal)) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Thu May 28 16:54:14 2015 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Thu May 28 17:44:05 2015 +0200
@@ -301,8 +301,6 @@
   /* Support for Graal */                                                                                                             \
   template(java_util_BitSet,                                         "java/util/BitSet")                                              \
   GRAAL_ONLY(template(com_oracle_graal_debug_Debug,                             "com/oracle/graal/debug/Debug"))                                  \
-  GRAAL_ONLY(template(com_oracle_graal_graph_Node,                              "com/oracle/graal/graph/Node"))                                   \
-  GRAAL_ONLY(template(com_oracle_graal_graph_NodeClass,                         "com/oracle/graal/graph/NodeClass"))                              \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotGraalRuntime,             "com/oracle/graal/hotspot/HotSpotGraalRuntime"))                  \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotCompiledCode,             "com/oracle/graal/hotspot/HotSpotCompiledCode"))                  \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotCompiledCode_Comment,     "com/oracle/graal/hotspot/HotSpotCompiledCode$Comment"))          \
@@ -336,7 +334,6 @@
   GRAAL_ONLY(template(com_oracle_graal_api_meta_Assumptions_NoFinalizableSubclass, "com/oracle/graal/api/meta/Assumptions$NoFinalizableSubclass")) \
   GRAAL_ONLY(template(com_oracle_graal_api_meta_Assumptions_ConcreteMethod,     "com/oracle/graal/api/meta/Assumptions$ConcreteMethod"))          \
   GRAAL_ONLY(template(com_oracle_graal_api_meta_Assumptions_CallSiteTargetValue,"com/oracle/graal/api/meta/Assumptions$CallSiteTargetValue"))     \
-  GRAAL_ONLY(template(com_oracle_graal_api_code_CompilationResult,              "com/oracle/graal/api/code/CompilationResult"))                   \
   GRAAL_ONLY(template(com_oracle_graal_api_code_CompilationResult_Call,         "com/oracle/graal/api/code/CompilationResult$Call"))              \
   GRAAL_ONLY(template(com_oracle_graal_api_code_CompilationResult_ConstantReference, "com/oracle/graal/api/code/CompilationResult$ConstantReference")) \
   GRAAL_ONLY(template(com_oracle_graal_api_code_CompilationResult_DataPatch,    "com/oracle/graal/api/code/CompilationResult$DataPatch"))         \
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Thu May 28 16:54:14 2015 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Thu May 28 17:44:05 2015 +0200
@@ -390,7 +390,7 @@
   CompilerThread* compilerThread = thread->is_Compiler_thread() ? thread->as_CompilerThread() : NULL;
   _oop_recorder = new OopRecorder(&_arena, true);
   _dependencies = new Dependencies(&_arena, _oop_recorder, compilerThread != NULL ? compilerThread->log() : NULL);
-  objArrayHandle assumptions = CompilationResult::assumptions(HotSpotCompiledCode::comp(compiled_code));
+  objArrayHandle assumptions = HotSpotCompiledCode::assumptions(compiled_code);
   if (!assumptions.is_null()) {
     int length = assumptions->length();
     for (int i = 0; i < length; ++i) {
@@ -413,7 +413,7 @@
       }
     }
   }
-  objArrayHandle methods = CompilationResult::methods(HotSpotCompiledCode::comp(compiled_code));
+  objArrayHandle methods = HotSpotCompiledCode::methods(compiled_code);
   if (!methods.is_null()) {
     int length = methods->length();
     for (int i = 0; i < length; ++i) {
@@ -483,7 +483,6 @@
 }
 
 void CodeInstaller::initialize_fields(oop compiled_code) {
-  Handle comp_result = HotSpotCompiledCode::comp(compiled_code);
   if (compiled_code->is_a(HotSpotCompiledNmethod::klass())) {
     Handle hotspotJavaMethod = HotSpotCompiledNmethod::method(compiled_code);
     methodHandle method = getMethodFromHotSpotMethod(hotspotJavaMethod());
@@ -497,10 +496,10 @@
   _sites_handle = JNIHandles::make_local(HotSpotCompiledCode::sites(compiled_code));
   _exception_handlers_handle = JNIHandles::make_local(HotSpotCompiledCode::exceptionHandlers(compiled_code));
 
-  _code_handle = JNIHandles::make_local(CompilationResult::targetCode(comp_result));
-  _code_size = CompilationResult::targetCodeSize(comp_result);
-  _total_frame_size = CompilationResult::totalFrameSize(comp_result);
-  _custom_stack_area_offset = CompilationResult::customStackAreaOffset(comp_result);
+  _code_handle = JNIHandles::make_local(HotSpotCompiledCode::targetCode(compiled_code));
+  _code_size = HotSpotCompiledCode::targetCodeSize(compiled_code);
+  _total_frame_size = HotSpotCompiledCode::totalFrameSize(compiled_code);
+  _custom_stack_area_offset = HotSpotCompiledCode::customStackAreaOffset(compiled_code);
 
   // Pre-calculate the constants section size.  This is required for PC-relative addressing.
   _data_section_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSection(compiled_code));
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Thu May 28 16:54:14 2015 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Thu May 28 17:44:05 2015 +0200
@@ -472,7 +472,7 @@
   method->set_dont_inline(true);
 C2V_END
 
-C2V_VMENTRY(jint, installCode0, (JNIEnv *jniEnv, jobject, jobject compiled_code, jobject installed_code, jobject speculation_log))
+C2V_VMENTRY(jint, installCode, (JNIEnv *jniEnv, jobject, jobject compiled_code, jobject installed_code, jobject speculation_log))
   ResourceMark rm;
   HandleMark hm;
   Handle compiled_code_handle = JNIHandles::resolve(compiled_code);
@@ -502,7 +502,6 @@
       assert(installed_code_handle->is_a(InstalledCode::klass()), "wrong type");
       InstalledCode::set_address(installed_code_handle, (jlong) cb);
       InstalledCode::set_version(installed_code_handle, InstalledCode::version(installed_code_handle) + 1);
-      oop comp_result = HotSpotCompiledCode::comp(compiled_code_handle);
       if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) {
         HotSpotInstalledCode::set_size(installed_code_handle, cb->size());
         HotSpotInstalledCode::set_codeStart(installed_code_handle, (jlong) cb->code_begin());
@@ -1045,7 +1044,6 @@
 #define HS_COMPILED_CODE      "Lcom/oracle/graal/hotspot/HotSpotCompiledCode;"
 #define HS_CONFIG             "Lcom/oracle/graal/hotspot/HotSpotVMConfig;"
 #define INSTALLED_CODE        "Lcom/oracle/graal/api/code/InstalledCode;"
-#define NODE_CLASS            "Lcom/oracle/graal/graph/NodeClass;"
 #define HS_STACK_FRAME_REF    "Lcom/oracle/graal/hotspot/HotSpotStackFrameReference;"
 #define METASPACE_KLASS       "J"
 #define METASPACE_METHOD      "J"
@@ -1085,7 +1083,7 @@
   {CC"getMaxCallTargetOffset",                       CC"(J)J",                                                                 FN_PTR(getMaxCallTargetOffset)},
   {CC"getMetaspaceMethod",                           CC"("CLASS"I)"METASPACE_METHOD,                                           FN_PTR(getMetaspaceMethod)},
   {CC"initializeConfiguration",                      CC"("HS_CONFIG")V",                                                       FN_PTR(initializeConfiguration)},
-  {CC"installCode0",                                 CC"("HS_COMPILED_CODE INSTALLED_CODE SPECULATION_LOG")I",                 FN_PTR(installCode0)},
+  {CC"installCode",                                  CC"("HS_COMPILED_CODE INSTALLED_CODE SPECULATION_LOG")I",                 FN_PTR(installCode)},
   {CC"notifyCompilationStatistics",                  CC"(I"HS_RESOLVED_METHOD"ZIJJ"INSTALLED_CODE")V",                         FN_PTR(notifyCompilationStatistics)},
   {CC"resetCompilationStatistics",                   CC"()V",                                                                  FN_PTR(resetCompilationStatistics)},
   {CC"disassembleCodeBlob",                          CC"(J)"STRING,                                                            FN_PTR(disassembleCodeBlob)},
--- a/src/share/vm/graal/graalJavaAccess.hpp	Thu May 28 16:54:14 2015 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Thu May 28 17:44:05 2015 +0200
@@ -68,13 +68,18 @@
     boolean_field(HotSpotNmethod, isDefault)                                                                                                                   \
   end_class                                                                                                                                                    \
   start_class(HotSpotCompiledCode)                                                                                                                             \
-    oop_field(HotSpotCompiledCode, comp, "Lcom/oracle/graal/api/code/CompilationResult;")                                                                      \
     objArrayOop_field(HotSpotCompiledCode, sites, "[Lcom/oracle/graal/api/code/CompilationResult$Site;")                                                       \
     objArrayOop_field(HotSpotCompiledCode, exceptionHandlers, "[Lcom/oracle/graal/api/code/CompilationResult$ExceptionHandler;")                               \
     objArrayOop_field(HotSpotCompiledCode, comments, "[Lcom/oracle/graal/hotspot/HotSpotCompiledCode$Comment;")                                                \
+    objArrayOop_field(HotSpotCompiledCode, assumptions, "[Lcom/oracle/graal/api/meta/Assumptions$Assumption;")                                                 \
+    typeArrayOop_field(HotSpotCompiledCode, targetCode, "[B")                                                                                                  \
+    int_field(HotSpotCompiledCode, targetCodeSize)                                                                                                             \
     typeArrayOop_field(HotSpotCompiledCode, dataSection, "[B")                                                                                                 \
     int_field(HotSpotCompiledCode, dataSectionAlignment)                                                                                                       \
     objArrayOop_field(HotSpotCompiledCode, dataSectionPatches, "[Lcom/oracle/graal/api/code/CompilationResult$DataPatch;")                                     \
+    int_field(HotSpotCompiledCode, totalFrameSize)                                                                                                             \
+    int_field(HotSpotCompiledCode, customStackAreaOffset)                                                                                                      \
+    objArrayOop_field(HotSpotCompiledCode, methods, "[Lcom/oracle/graal/api/meta/ResolvedJavaMethod;")                                                         \
   end_class                                                                                                                                                    \
   start_class(HotSpotCompiledCode_Comment)                                                                                                                     \
     oop_field(HotSpotCompiledCode_Comment, text, "Ljava/lang/String;")                                                                                         \
@@ -93,14 +98,6 @@
   start_class(HotSpotForeignCallLinkageImpl)                                                                                                                   \
     long_field(HotSpotForeignCallLinkageImpl, address)                                                                                                         \
   end_class                                                                                                                                                    \
-  start_class(CompilationResult)                                                                                                                               \
-    int_field(CompilationResult, totalFrameSize)                                                                                                               \
-    int_field(CompilationResult, customStackAreaOffset)                                                                                                        \
-    typeArrayOop_field(CompilationResult, targetCode, "[B")                                                                                                    \
-    objArrayOop_field(CompilationResult, assumptions, "[Lcom/oracle/graal/api/meta/Assumptions$Assumption;")                                                   \
-    objArrayOop_field(CompilationResult, methods, "[Lcom/oracle/graal/api/meta/ResolvedJavaMethod;")                                                           \
-    int_field(CompilationResult, targetCodeSize)                                                                                                               \
-  end_class                                                                                                                                                    \
   start_class(Assumptions_NoFinalizableSubclass)                                                                                                               \
     oop_field(Assumptions_NoFinalizableSubclass, receiverType, "Lcom/oracle/graal/api/meta/ResolvedJavaType;")                                                 \
   end_class                                                                                                                                                    \
--- a/src/share/vm/runtime/arguments.cpp	Thu May 28 16:54:14 2015 +0200
+++ b/src/share/vm/runtime/arguments.cpp	Thu May 28 17:44:05 2015 +0200
@@ -1502,9 +1502,6 @@
   // to use UseCompressedOops is InitialHeapSize.
   size_t max_heap_size = MAX2(MaxHeapSize, InitialHeapSize);
   // Set default on graal with sparc to not use compressed oops as long they are not implemented
-#if defined(GRAAL) && defined(TARGET_ARCH_sparc)
-  FLAG_SET_DEFAULT(UseCompressedOops, false);
-#else // if !(GRAAL && SOLARIS)
   if (max_heap_size <= max_heap_for_compressed_oops()) {
 #if !defined(COMPILER1) || defined(TIERED)
     if (FLAG_IS_DEFAULT(UseCompressedOops)) {
@@ -1529,7 +1526,6 @@
   }
 #endif // _LP64
 #endif // ZERO
-#endif // !(GRAAL && SOLARIS)
 }